-
Notifications
You must be signed in to change notification settings - Fork 61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for saving segments in a single file #464
Conversation
Failures of the round-trip tests are expected, since output is not what is expected. Issues identified that need to be fixed:
|
For whatever reason, a new list was created for each segment
🎆 |
Now I need to fix |
perhaps this is faster than iterating over the pixels in a loop?
Introducing a new class OverlapUtil that is able to check whether segments of a given DICOM segmentation are overlapping. It computes an overlap matrix denoting which segments overlap with each other. Also, from that it can derive groups of segments that do not overlap, e.g. for exporting them later into NRRD files or similar formats that cannot deal with overlapping segments.
The code no produces first results - NRRD file(s) for merged segments, though they still need to be checked for correctness. Also on some segmentations the code still seems to crash (to be fixed).
Ensure that errors are passed up the hierarchy. This esp. fixes handling of files with non-consecutive segment numbers (such as an old verison of the brain atlas that uses weird segment numbers).
Fix computation of Image origin for ITK which has been introduced when refactoring the code. Let DCMTK make use of STL classes which gives a some speedup in particular regarding the usage of OFMap that is used in the functional group classes (dcmfg module).
Fix assignment of frames to NRRD file (used index instead of vector element at that index). Speed up writing of segmentation by disabling functional group structure checking. The segmentation to ITK validator should now produce valid NRRD files, grouping non-overlapping segments into the same file (if option --mergedSegments is being provided on the command line).
This also make sure that the updated workflow actions are used.
Since ITK to DICOM and DICOM to ITK conversion do not have much in common, the original class ImageSEGConverter is now splitted into Itk2DicomConverter and Dicom2ItkConverter.
@michaelonken I think I know why it fails. The NRRD outputs you are saving start with prefix 0, while they used to start from 1. E.g., |
Makes sense,thanks! I'll try this on Monday. |
@michaelonken here are commands to download the image and segmentation for an oblique acquisition:
You will need to have s5cmd installed first: https://github.com/peak/s5cmd. For the sake of completeness, the above commands will download corresponding DICOM series from the public AWS buckets maintained by NCI Imaging Data Commons (IDC). The samples are from the QIN-Prostate-Repeatablity collection, which is hosted on IDC. |
Fixed tests caused by bug not exporting last frame of a segment. The underlying API has been changed so usage error is less likely to occur. Simplified includes, better error messages, documentation.
Bumping node version -- but not too high since at some version node requires higher GLIBC version. Higher verisons than 12.19.1 may work, though, earlier versions did not work.
The coordinate relevant for frame sorting is now identified by computing the cross product for image orientation patient and selecting the coordinate that results in the bigges absolute value. Minor enhancements in error handling and documentation.
Before, all ITK images have been returned at once after conversion. Now, this is done with an iterator-like access that allows to delete an ITK image once produced by the converter. The converter class does not keep any reference to the ITK image, so once it goes out of scope of the "user" class (like segimage2itkimage.cxx), memory of the image is freed (converter returns smart pointer).
Fixed bug when creating the JSON for merged segments where more than one file was produced. Instead of then splitting segments into different entries in the outer array of the JSON, the segments have been written to the inner array instead.
Added test that writes 3 segments, 2 of them non-overlapping. That means that two NRRD files will be produced, one with 2 segments, the other with only a single one.
Current status of this pull request:
Weaknesses:
Other remaining work:
|
@michaelonken I built the branch, and it appears that the output files that are created by |
Hm, I could not confirm this on my system, e.g. see the following log:
Also using Maybe I am overlooking something, or have you maybe used an old version that has been in your PATH or so? |
@michaelonken I am very sorry - I messed it up. Indeed, I was on a stale branch. I thought I updated, but I was multitasking, and apparently I did something wrong. Output file numbering works as expected! I am fixing few items in the Slicer QuantitativeReporting extension in this PR that I discovered in the process of testing. |
@michaelonken I did testing with various samples from IDC, and it works great! I am very tempted to just merge it and get this out into Slicer. We can address refinements in subsequent work. What do you think?
Indeed, it will require some extra code, since AND is applied to frames before unpacking. Such frame sizes are not common. For the record, I used the query below to search IDC for such segmentations: SELECT
collection_id,
PatientID,
StudyInstanceUID,
SeriesInstanceUID,
`Rows`,
`Columns`,
ARRAY_LENGTH(SegmentSequence) AS numberOfSegments
FROM
`bigquery-public-data.idc_current.dicom_all`
WHERE
Modality="SEG"
AND MOD(`Rows`*`Columns`, 8) <> 0
ORDER BY
Collection_id desc and only three collections contain such samples, all of them containing just single segment. So I do not think it makes sense to spend too much time on this, or delay integration of this PR. |
Thanks for testing @fedorov ! Nice SQL query :-) For the MOD 8 issue: I agree, let's skip it for now. I will look into it if there is some time left. I thought about it and I think the bit-wise comparison will also work for the other frame sizes as long as the "margin" bytes at the beginning and at the end of the frame, which may contain overlapping bits from other frames, are masked out correctly first. This is a bit intricate so I don't want to implement this quickly without proper unit tests. The one remaining thing that we might to guard against are oblique slices. If I understand correctly, in those Series the position (Image Position Patient) does not only vary in one (e.g. z) coordinate between slices, but also in the other two coordinates (x,y). The overlap detection code right now superimposes frames that are on the same z coordinate, without "aligning" them on their x,y coordinate. This way pixels are compared that might have totally different positions in 3D space, eventually leading to broken merges or non-merges of segments. The right way would be to accommodate for the x,y shift before doing the comparison. Probably it is just some "simple" matrix operation(s) but nothing I could shake off my sleeve. As a workaround, one might try to detect oblique slicing and then fallback to the non-merging operation. What do you think? |
@michaelonken I spent some time looking at the code in question, which as I understand is around here: https://github.com/fedorov/dcmqi/blob/merged-segments/libsrc/OverlapUtil.cpp#L736-L761. I think this logic could be significantly simplified. Instead of trying to detect |
@fedorov I can check this in detail Tuesday next week. From just taking a quick look I am not sure whether the frame sorting code you referenced takes into account the x,y coordinate shifting that I mentioned. It's clear, also for oblique cases, how to identify the relevant coordinate (using Image Orientation Patient as the framesorter code and the OverlapUtil code does). The problem I see is in the shifting of the other two coordinates, so that if two frames are on the same "plane" (e.g. z coordinate, "relevant coordinate"), we cannot simply compare value for "pixel" 1,1 from frame A to the 1,1 from frame B since Frame B might start 2 cm more to the right (e.g. x direction) and 1 cm more in y-direction. Here is a very sophisticated picture to demonstrate my bad explanation :-) |
Michael, I do not think this would be the case for any volumetric acquisition. In oblique scans, the frames are not shifted when observed along the scan direction. What you show would be the case if one projected oblique acquisition slices to a plane. |
Ah, thank you. Sorry for the noise then. And we can always assume that we don't have such kind of shifts in any acquisitions we handle? I think then we are safe to go with the current code. We could simplify by using the existing framesorter code (that I just didn't know) but maybe this can be a second step a bit later if you want to merge. P.S: Note that Frame A and Frame B are usually parts of two different segments, not of a real "acquisition" of a modality, so a segmentation creator could in theory at least place frames in space where he wants to; this is what I am afraid of. |
This may be a valid scenario in theory, but it would be crazy, and in any case it is probably not handled in dcmqi in other places. I am not sure. I have never seen such cases. Would be nice to add an error check for this or something like this! I will go ahead merging this, to make this functionality easier accessible to the users, and make it easier to test and identify deficiencies! |
There are two very important improvements in this updated version: 1. Performance of conversion is improved perhaps by at least an order of magnitude, cutting down the conversion for large DICOM SEG (such as TotalSegmentator results) from minutes to seconds. 2. It is now possible to save non-overlapping segments into a single file instead of previous convention of saving each segment as a separate file. See details in QIICR/dcmqi#464. Note that to use this feature you will need to use the --merge flag (there may be changes needed to the MITK dcmqi wrapper - I am sure you will test this - but there are no changes to the JSON schema)
There are two very important improvements in this updated version: 1. Performance of conversion is improved perhaps by at least an order of magnitude, cutting down the conversion for large DICOM SEG (such as TotalSegmentator results) from minutes to seconds. 2. It is now possible to save non-overlapping segments into a single file instead of previous convention of saving each segment as a separate file. See details in QIICR/dcmqi#464. Note that to use this feature you will need to use the --merge flag (there may be changes needed to the MITK dcmqi wrapper - I am sure you will test this - but there are no changes to the JSON schema)
Summary: Upgrade DCMQI to 1.3.0 There are two very important improvements in this updated version: 1. Performance of conversion is improved perhaps by at least an order of magnitude, cutting down the conversion for large DICOM SEG (such as TotalSegmentator results) from minutes to seconds. 2. It is now possible to save non-overlapping segments into a single file instead of previous convention of saving each segment as a separate file. See details in QIICR/dcmqi#464. Note that to use this feature you will need to use the --merge flag (there may be changes needed to the MITK dcmqi wrapper - I am sure you will test this - but there are no changes to the JSON schema) Update dcmqi to 1.3.1 Bump to DCMQI v1.3.2 Adapt to new DCMQI interface + fixed T30286 Fixed error in label generation when loading multiple groups from DICOM Seg Fixed error in assigning the label name when DCM Seg is loaded Added support for SegmentOverlap tag. If segment overlap == NO then all segements are added as label of one group. In all other cases each segment is added as new group (old behavior). + fixed memory leak Test Plan: code review, test to load and save segs as/from DCM Seg. Segmentations of a group in MITK should stay now a group also after loading. Loading old/other DCM seg results in a group per segment/label. Reviewers: O1 MITK Reviewer Group I, kislinsk Reviewed By: O1 MITK Reviewer Group I, kislinsk Subscribers: kislinsk Maniphest Tasks: T30286 Differential Revision: https://phabricator.mitk.org/D966
WIP towards addressing #462