dcmjs-org / dcmjs

Javascript implementation of DICOM manipulation
https://dcmjs.netlify.com/
MIT License
291 stars 110 forks source link

use SegmentNumber from the segment metadata exporting DICOM SEG. #339

Closed IbrahimCSAE closed 1 year ago

IbrahimCSAE commented 1 year ago

Hello,

I would like to ask if it's possible to use the SegmentNumber from the cornerstoneTools segmentation metadata when exporting DICOM SEG, rather than being limited to sequential segment numbers. Currently, if I have non-sequential segments (e.g. 3 and 4), when I export the segmentation using the dcmjs adapter, it will assign sequential segment numbers (1 and 2) when exported.

1 - Psoas Muscle -> exported index will map to this segment 2 - Subcutaneous Fat -> exported index will map to this segment 3 - Visceral Fat -> user drew this segment 4 - Skeletal Wall Muscle -> user drew this segment

Screenshot_2

This change would be useful for our web app as we have hard-coded behavior based on the SegmentNumber that spans multiple areas of the app, including activating the correct segment for drawing, setting the correct color for the segment, the correct name in the UI, threshold values for the brush for that segment, configuring the cornerstone colorLUT, labelmap3Ds, labelmap2Ds, etc. We also have a fixed set of segments, which is why we have taken a hard-coded approach. Our backend also has AI models that follow these segment numbers strictly when it generates SEGs, making it easy for the frontend to identify what should be displayed in the UI.

Currently, if a user exports their drawn segmentation to the cloud and the indexes for non-sequential segments get turned into sequential segments, most of the logic that depends on the segment number will fail (next time they retrieve it from the cloud, all the mapping will be wrong). This applies whether they draw manually or use any of our AI models and then overwrite the SEG when using dcmjs. This is also problematic when a user ovewrites a pre existing SEG in the cloud, when we regenerate the SEG with dcmjs and send it back to S3 or some other storage, that updated segmentation will have wrong index's, so it affects new generations or overwriting existing SEGs in the cloud storage.

I understand that this approach of linking behavior to the SegmentNumber might not be reliable and I should look into better approaches (maybe ID the segments some other way? Using a database and just ignoring the SegmentNumber in the meta entirely?). However, I would still like to ask if it is possible to have exports with the SegmentNumber. I have been using a fork of the library with the changes I mentioned, and it has been working okay for our needs.

 SegmentNumber: (SegmentSequence.length + 1).toString()
 SegmentNumber: Segment.SegmentNumber

https://github.com/dcmjs-org/dcmjs/blob/b4732d7b677b8cbb7ae12276019e18371a4864a6/src/derivations/Segmentation.js#L408

I acknowledge that this approach could fail if developers doesn't set the metadata for the segment in cornerstoneTools before exporting the SEG, or if they don't add the SegmentNumber in generated metadata. One way to decide whether to use sequential numbers or the metadata for the segments could be to check if all the segments contain the SegmentNumber field, then we proceed with the SegmentNumbers, otherwise fallback to sequential?

segmentsLength = segments.length
segmentNumbersLenght = segments.filter(segment => segment.SegmentNumber !== undefined)
if (segmentNumbersLength == segmentsLength){
 SegmentNumber: Segment.SegmentNumber
}else{
 SegmentNumber: (SegmentSequence.length + 1).toString()
}

In summary, can we use the SegmentNumber from the user-generated metadata when exporting the SEG?

Any help is really appreciated, thank you, this library is great and It does a lot of amazing things. Thanks for all the efforts put into this!

fedorov commented 1 year ago

The standard is very clear in requiring SegmentNumber to be assigned sequentially: https://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.8.20.2.4.html#sect_C.8.20.2.4

Segment Number (0062,0004) shall be unique within each Instance, start at a value of 1, and increase monotonically by 1.

fedorov commented 1 year ago

Adding @dclunie, as I think it will be good for him to be aware of the issue you are trying to address.

IbrahimCSAE commented 1 year ago

The standard is very clear in requiring SegmentNumber to be assigned sequentially: https://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.8.20.2.4.html#sect_C.8.20.2.4

Segment Number (0062,0004) shall be unique within each Instance, start at a value of 1, and increase monotonically by 1.

@fedorov Thanks for sharing, It looks like I should rethink my entire approach to the problem then. I was not aware that it has to be sequential.

pieper commented 1 year ago

@IbrahimCSAE Thanks for your careful attention to this issue - it's a very important application level concept. It is true that many systems rely on numbering conventions to identify segments, but independent of dicom, this can lead to issues like you describe when, for example, a new segment type is introduced or a previous segment gets subdivided. There's always some versioned "map" that goes from these numbers to some other concept like anatomy, color, etc.

The dicom approach is to use other codes like snomed so you can describe the intent or meaning of the segment. These are the 'coding schemes' and 'coded concepts' you'll see in the standard and there are other mechanisms to do things like provide an id to a lesion so you can track it over time. If this is too complex or none of the standard schemes fit your application, you can define a custom scheme, with a designator like "99MYAPP" and put your segment numbers there so that your round trips to dicom seg are lossless.

IbrahimCSAE commented 1 year ago

@pieper

Thank you for explaining the benefits of using coding schemes and coded concepts to identify segments in DICOM.

I took a look at the standard and this will definitely fit my use case. I appreciate it!

fedorov commented 1 year ago

Another "feature" of the standard you should be aware of is the TrackingID/TrackingUID attributes that you can assign at the segment level. Using those you can link segments corresponding to the same structure segmented across series/modalities/timepoints: https://dicom.innolitics.com/ciods/segmentation/segmentation-image/00620002/00620021.