Project-MONAI / MONAILabel

MONAI Label is an intelligent open source image labeling and learning tool.
https://docs.monai.io/projects/label
Apache License 2.0
628 stars 196 forks source link

Setting default window width (WW) and default window level (WL) #447

Closed masadcv closed 2 years ago

masadcv commented 3 years ago

We have had some feedback from clinical partners regarding setting of window for highlighting different organs. The window/levels are defined typically by window width (WW) and window level (WL). This is then used in the following formula to set the min/max levels for CT images. w_min = WL - WW/2 w_max = WL+WW/2

More info about this can be found here: https://radiopaedia.org/articles/windowing-ct?lang=gb

There are known WL/WW values for different organs/tissues (as listed in the above link).

For example, a lung window is typically defined as WW=1500 and WL=-600. This has the following effect on visualizing the image volume:

Before applying lung window: image

After applying lung window (WW=1500, WL=-600): image

You can notice that it highlights tissues/lesions inside lung better. The above is just one example, the values for WW/WL can vary for different organs and institute.

In 3D Slicer, the above can be achieved as:

WL=-600; WW=1500
volumeNode = slicer.mrmlScene.GetFirstNodeByClass("vtkMRMLScalarVolumeNode")
volumeNode.GetDisplayNode().SetAutoWindowLevel(False)
volumeNode.GetDisplayNode().SetWindowLevelMinMax(WL-WW/2, WL+WW/2)

Does this sound like something we can pass as argument from an app as default, given that we know the target organ/tissue and its WL/WW. In cases where these are not present, we can skip updating the above. In other cases where the user wants to change these, there is a window level button that can be used to adjust manually.

cc: @tvercaut

lassoan commented 3 years ago

If you load the data from DICOM then the recommended WW/WL values are stored in the file and Slicer applies them when the data is loaded. If you load from nrrd or there is no WW/WL in the DICOM file then the full intensity range is displayed, which indeed may not be always ideal.

I agree that it could also make sense for the applications to specify display options, such as WW/WL, colormap, threshold value, but also things like enable/disable volume rendering (and volume rendering settings) or hanging protocols (defining a list of views and what each view should display).

Alternatively, you could make WW/WL sticky. It would be very easy to implement this: when the user requests loading of the next data set, you would first remember the WW/WL value of the current volume and then apply this to the volume that you load next.

Also note that users can choose WW/WL preset in Volumes module in Slicer (see screenshot below). It is probably not convenient for users to switch modules (and they may not even know that the Volumes module exist and there are presets there), so we could make things more convenient - we are open to suggestions. For example, we could add common presets to the drop-down menu of the WW/WL mouse mode button; or add presets to the right-click menu in slice viewers.

image

tvercaut commented 3 years ago

MONAI-Label will typically work with nifti-like data and thus will typically not have access to the relevant DICOM metadata. In addition to the "sticky" preference feature discussed by @lassoan, I guess that for many MONAI Label apps, the type of images and object of interest would be known in advance. In these cases, the app could provide a suitable default windowing.

e.g. CT input, lung lesion segmentation task -> use CT lung window as default MRI input, any task -> use min/max window as default

masadcv commented 3 years ago

There is an open pull request for this: https://github.com/Project-MONAI/MONAILabel/pull/473 As discussed in our meetings, we need to think a bit more about such feature and where it goes for MONAI Label.

masadcv commented 2 years ago

Closing this and #473 for now. We can reopen if we see interest in getting this solved within monai label.

rbumm commented 2 years ago

>> or add presets to the right-click menu in slice viewers.

For your information, this function is now available in SLicer 5

rbumm commented 2 years ago

We are segmenting many CT datasets from various sources and quality with MONAILabel. 

It seems, as if segmentation results could be better standardized and more precise if the datasets could somehow be batch normalized in respect of HU range or histogram for certain organs like lung or airways, I face the same problem when I segment data from the lung06 dataset with 3D Slicer´s extension "Lung CT Segmenter".  

Any ideas on that?

masadcv commented 2 years ago

Hi @rbumm,

Many thanks for your question. Indeed, the HU intensity range is normalised for each volume in every MONAI Label app using ScaleIntensityRanged transform. However, the default setting for the included sample apps is targetting multiple organs in the abdomen. This default normalisation may not work well with CT Lung volume, as you rightly pointed out.

You will need to override these in your app to target lungs in CT. For example, for radiology app if you are using Scribbles, you will need to change the following lines: https://github.com/Project-MONAI/MONAILabel/blob/main/sample-apps/radiology/main.py#L118-L137

to

        infers.update(
            {
                "Histogram+GraphCut": HistogramBasedGraphCut(
                    intensity_range=(-1000, 400, 0.0, 1.0, True),
                    pix_dim=(2.5, 2.5, 5.0),
                    lamda=1.0,
                    sigma=0.1,
                    num_bins=64,
                    labels=task_config.labels,
                ),
                "GMM+GraphCut": GMMBasedGraphCut(
                    intensity_range=(-1000, 400, 0.0, 1.0, True),
                    pix_dim=(2.5, 2.5, 5.0),
                    lamda=5.0,
                    sigma=0.5,
                    num_mixtures=20,
                    labels=task_config.labels,
                ),
            }
        )

Here the intensity_range parameters provides (input_min, input_max, output_min, output_max, apply_clipping) where min max ranges for input and normalised output are specified along with whether to discard values outside these ranges with apply_clipping. You can change these ranges to a suitable range for your data. If you are using deepedit or other functionality, you will need to have the same changes for ScaleIntensityRanged in each app/module.

In addition, as you pointed out above, you will require appropriate windowing for displaying this data to radiologists/clinicians as the ScaleIntensityRanged is only used for the algorithmic part.

Hope this is clear, please let me know if you have any further questions regarding this, I may be able to help out as I have been involved in using MONAI Label in CT Lung volumes for our projects.

rbumm commented 2 years ago

Hi @masadcv , 

Thank you for the detailed answer.

My current approach is to load datasets in 3D Slicer within ML with the "Next sample" button, then label the CT lung dataset with my own extension (Lung CT Segmenter, a module of Lung CT Analyzer), and then "submit label" and train. Just to be able to create lung masks and airways with Monailabels autosegmentation.  

I get astonishingly stable results on a gaming PC already using the ML segmentation model (Auto Segmentation, 11 s)

monailabel start_server --app ./apps/lung --studies ./datasets/Task06_Lung/imagesTr --conf models segmentation

and the Monailabel approach is fascinating. 

In this workflow, do you see the need to set lung or airway intensity ranges somewhere? Or is this only needed if we use the scribbles function?

masadcv commented 2 years ago

Hi @rbumm , This is quite interesting workflow. I believe, as you are doing all processing on Lung CT Segmenter, you only may need to normalise/clip intensity ranges in Lung CT Segmenter.

The monai label intensity normalisation approach is only needed if you use one of the server apps (including deepedit, autoseg and scribbles etc) to perform the annotation. As you are not using them, you wont need to modify anything related to the intensity ranges in those apps. I believe it will be useful to set these ranges in Lung CT Segmenter (if not already done).

That being said, I wonder if your approach can be implemented as a MONAI Label App to have the relevant algorithms working inside a server app (using scribbles or points). I will check out the code for Lung CT Segmenter to know more about the methods you use.

masadcv commented 2 years ago

Another aspect to mention in context of this discussion is that the Histogram and Gaussian Mixture Model that are currently implement in MONAI Label may be too simple models for capturing large variations in lung regions, especially when segmenting lesions. We have developed a more sophisticated approach to address such problems in lung CT by using a CNN instead of these simple models. The code for this is available at: https://github.com/masadcv/ECONet-MONAILabel

rbumm commented 2 years ago

This is a very good idea. Will try to normalize the intensities in Lung CT Segmenter and see how that goes. It is on the to-do list. 

It would be very interesting to enable MONALLabel to do segmentations within its own AI results: For example:  to find nodules (only!)  in the right lung segment that it has auto segmented before. My approach (3D Slicer, no ML)  would be to segment the lung masks, subtract vessels and airways, then detect round objects with a certain size and "roundness". Exclude all tubular objects. 

BTW very interesting link