Skip to content

Commit

Permalink
Improve how to handle DICOM special modality
Browse files Browse the repository at this point in the history
  • Loading branch information
nroduit committed Dec 13, 2023
1 parent 97f733f commit 5c398f7
Show file tree
Hide file tree
Showing 20 changed files with 587 additions and 361 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ public enum LayerType {
Boolean.TRUE,
Boolean.TRUE),

DICOM_SEG(95, "DICOM SEG", Boolean.TRUE, Boolean.TRUE, Boolean.FALSE, Boolean.FALSE), // NON-NLS

DICOM_SR(100, "DICOM SR", Boolean.TRUE, Boolean.TRUE, Boolean.FALSE, Boolean.TRUE), // NON-NLS

DICOM_RT(110, "DICOM RT", Boolean.TRUE, Boolean.TRUE, Boolean.FALSE, Boolean.FALSE), // NON-NLS
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collectors;
import org.dcm4che3.data.Attributes;
import org.dcm4che3.data.Tag;
Expand All @@ -29,7 +31,7 @@
import org.weasis.dicom.codec.macro.SOPInstanceReferenceAndMAC;
import org.weasis.dicom.codec.macro.SeriesAndInstanceReference;

public class AbstractKOSpecialElement extends DicomSpecialElement {
public class AbstractKOSpecialElement extends HiddenSpecialElement {

public static class Reference {
private final String studyInstanceUID;
Expand Down Expand Up @@ -499,4 +501,89 @@ private static int[] removeFrames(int[] arr1, List<Integer> frameList) {
}
return result.stream().mapToInt(i -> i).toArray();
}

/**
* @param seriesUID the Series Instance UID
* @param specialElements the list of DicomSpecialElement
* @return the KOSpecialElement collection for the given parameters, if the referenced seriesUID
* is null all the KOSpecialElement from specialElements collection are returned. In any case
* all the KOSpecialElement that are writable will be added to the returned collection
* whatever is the seriesUID. These KO are part of the new created one's by users of the
* application
*/
public static Collection<KOSpecialElement> getKoSpecialElements(
Collection<KOSpecialElement> specialElements, String seriesUID) {

if (specialElements == null) {
return Collections.emptySet();
}

SortedSet<KOSpecialElement> koElementSet = null;
for (KOSpecialElement koElement : specialElements) {
Set<String> referencedSeriesInstanceUIDSet = koElement.getReferencedSeriesInstanceUIDSet();
if (seriesUID == null
|| referencedSeriesInstanceUIDSet.contains(seriesUID)
|| koElement.getMediaReader().isEditableDicom()) {

if (koElementSet == null) {
koElementSet = new TreeSet<>(ORDER_BY_DATE);
}
koElementSet.add(koElement);
}
}
return koElementSet == null ? Collections.emptySet() : koElementSet;
}

public static Collection<RejectedKOSpecialElement> getRejectionKoSpecialElements(
Collection<RejectedKOSpecialElement> specialElements, String seriesUID) {

if (specialElements == null) {
return Collections.emptySet();
}

SortedSet<RejectedKOSpecialElement> sortedSet = null;
for (RejectedKOSpecialElement element : specialElements) {
Set<String> referencedSeriesInstanceUIDSet = element.getReferencedSeriesInstanceUIDSet();

if (seriesUID == null
|| referencedSeriesInstanceUIDSet.contains(seriesUID)
|| element.getMediaReader().isEditableDicom()) {

if (sortedSet == null) {
sortedSet = new TreeSet<>(ORDER_BY_DATE);
}
sortedSet.add(element);
}
}
return sortedSet == null ? Collections.emptySet() : sortedSet;
}

public static RejectedKOSpecialElement getRejectionKoSpecialElement(
Collection<RejectedKOSpecialElement> specialElements,
String seriesUID,
String sopUID,
Integer dicomFrameNumber) {

if (specialElements == null) {
return null;
}
List<RejectedKOSpecialElement> koList = null;

for (RejectedKOSpecialElement koElement : specialElements) {
if (isSopuidInReferencedSeriesSequence(
koElement.getReferencedSOPInstanceUIDObject(seriesUID), sopUID, dicomFrameNumber)) {
if (koList == null) {
koList = new ArrayList<>();
}
koList.add(koElement);
}
}

if (koList != null && !koList.isEmpty()) {
// return the most recent Rejection Object
koList.sort(ORDER_BY_DATE);
return koList.getFirst();
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.dcm4che3.data.Attributes;
import org.dcm4che3.data.BulkData;
Expand Down Expand Up @@ -83,6 +84,7 @@ public class DicomMediaIO implements DcmMediaReader {
public static final String SERIES_MIMETYPE = "series/dicom"; // NON-NLS
public static final String SERIES_PR_MIMETYPE = "pr/dicom"; // NON-NLS
public static final String SERIES_KO_MIMETYPE = "ko/dicom"; // NON-NLS
public static final String SERIES_SEG_MIMETYPE = "seg/dicom"; // NON-NLS

public static final String SERIES_ENCAP_DOC_MIMETYPE = "encap/dicom"; // NON-NLS
public static final String UNREADABLE = "unreadable/dicom"; // NON-NLS
Expand Down Expand Up @@ -186,13 +188,12 @@ public class DicomMediaIO implements DcmMediaReader {
}

public static final Map<String, DicomSpecialElementFactory> DCM_ELEMENT_FACTORIES =
new HashMap<>();
new ConcurrentHashMap<>();

static {
/*
* DICOM PR and KO are not displayed with a special viewer but are transversally managed objects. So they are
* not registered from a viewer.
*/
// The hidden type factories are not displayed with a special viewer but are transversally
// managed objects.

DCM_ELEMENT_FACTORIES.put(
"PR",
new DicomSpecialElementFactory() {
Expand All @@ -207,11 +208,17 @@ public String[] getModalities() {
return new String[] {"PR"};
}

@Override
public boolean isHidden() {
return true;
}

@Override
public DicomSpecialElement buildDicomSpecialElement(DicomMediaIO mediaIO) {
return new PRSpecialElement(mediaIO);
}
});

DCM_ELEMENT_FACTORIES.put(
"KO",
new DicomSpecialElementFactory() {
Expand All @@ -226,6 +233,11 @@ public String[] getModalities() {
return new String[] {"KO"};
}

@Override
public boolean isHidden() {
return true;
}

@Override
public DicomSpecialElement buildDicomSpecialElement(DicomMediaIO mediaIO) {
if (RejectedKOSpecialElement.isRejectionKOS(mediaIO)) {
Expand All @@ -234,6 +246,31 @@ public DicomSpecialElement buildDicomSpecialElement(DicomMediaIO mediaIO) {
return new KOSpecialElement(mediaIO);
}
});

DCM_ELEMENT_FACTORIES.put(
"SEG",
new DicomSpecialElementFactory() {

@Override
public String getSeriesMimeType() {
return SERIES_SEG_MIMETYPE;
}

@Override
public String[] getModalities() {
return new String[] {"SEG"};
}

@Override
public boolean isHidden() {
return true;
}

@Override
public DicomSpecialElement buildDicomSpecialElement(DicomMediaIO mediaIO) {
return new SegSpecialElement(mediaIO);
}
});
}

private static final SoftHashMap<DicomMediaIO, DicomMetaData> HEADER_CACHE =
Expand Down Expand Up @@ -325,7 +362,7 @@ public synchronized boolean isReadableDicom() {
return false;
}

if (tags.size() == 0) {
if (tags.isEmpty()) {
try {
DicomMetaData md = readMetaData();
Attributes fmi = md.getFileMetaInformation();
Expand All @@ -347,7 +384,11 @@ public synchronized boolean isReadableDicom() {
// MPEG4 AVC/H.264 BD 1.2.840.10008.1.2.4.103
mimeType = SERIES_VIDEO_MIMETYPE;
} else {
mimeType = IMAGE_MIMETYPE;
if ("1.2.840.10008.5.1.4.1.1.66.4".equals(mediaStorageSOPClassUID)) {
mimeType = SERIES_SEG_MIMETYPE; // Do not display SEG images
} else {
mimeType = IMAGE_MIMETYPE;
}
}
} else {
boolean special = setDicomSpecialType(header);
Expand Down Expand Up @@ -423,7 +464,7 @@ public Iterator<Entry<TagW, Object>> getTagEntrySetIterator() {
}

private void writeInstanceTags(DicomMetaData md) {
if (tags.size() > 0 || md == null || md.getDicomObject() == null) {
if (!tags.isEmpty() || md == null || md.getDicomObject() == null) {
return;
}
Attributes fmi = md.getFileMetaInformation();
Expand Down Expand Up @@ -698,8 +739,9 @@ public synchronized MediaElement[] getMediaElement() {
} else if (SERIES_ENCAP_DOC_MIMETYPE.equals(mimeType)) {
image = new MediaElement[] {new DicomEncapDocElement(this, null)};
} else {
DicomSpecialElementFactory factory = getDicomSpecialElementFactory();
if (numberOfFrame > 0) {
image = new MediaElement[numberOfFrame];
image = new MediaElement[factory == null ? numberOfFrame : numberOfFrame + 1];
for (int i = 0; i < image.length; i++) {
image[i] = new DicomImageElement(this, i);
}
Expand All @@ -712,25 +754,30 @@ public synchronized MediaElement[] getMediaElement() {
image[i].setTag(TagD.get(Tag.InstanceNumber), nb);
}
}
} else {
String modality = TagD.getTagValue(this, Tag.Modality, String.class);
if (modality != null) {
DicomSpecialElementFactory factory = DCM_ELEMENT_FACTORIES.get(modality);
if (factory != null) {
image = new MediaElement[1];
image[0] = factory.buildDicomSpecialElement(this);
}
if (factory != null) {
image[numberOfFrame] = factory.buildDicomSpecialElement(this);
}
if (image == null) {
} else {
if (factory == null) {
// Corrupted image => should have one frame
image = new MediaElement[0];
} else {
image = new MediaElement[] {factory.buildDicomSpecialElement(this)};
}
}
}
}
return image;
}

private DicomSpecialElementFactory getDicomSpecialElementFactory() {
String modality = TagD.getTagValue(this, Tag.Modality, String.class);
if (modality != null) {
return DCM_ELEMENT_FACTORIES.get(modality);
}
return null;
}

@Override
public MediaSeries<MediaElement> getMediaSeries() {
Series<MediaElement> series = null;
Expand Down Expand Up @@ -880,4 +927,14 @@ private synchronized DicomMetaData readMetaData() throws IOException {
reader.dispose();
}
}

public static boolean isHiddenModality(String modality) {
if (modality != null) {
DicomSpecialElementFactory factory = DCM_ELEMENT_FACTORIES.get(modality);
if (factory != null) {
return factory.isHidden();
}
}
return false;
}
}
Loading

0 comments on commit 5c398f7

Please sign in to comment.