Skip to content
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

Make sct_get_centerline robust to intensities with range [0, 1] #1746

Merged
merged 18 commits into from May 22, 2018

Conversation

charleygros
Copy link
Member

@charleygros charleygros commented May 17, 2018

Requirements

Description of the Change

If all intensities of the image are < 1, then this line:
https://github.com/neuropoly/spinalcordtoolbox/blob/master/spinalcordtoolbox/centerline/optic.py#L95
leads to a binarization of the input image --> fail of OptiC

Solution: make an intensity scaling prior to the int16 conversion.
Changes tested on ~ 50 images --> seems to do not affect OptiC.

Steps and Constraints

To test the pull request, please reinstall the toolbox because the changes are made in spinalcordtoolbox/optic

Copy link
Contributor

@stephaniealley stephaniealley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue is resolved for me. I tested it on all 3 of the contrasts for which it failed in this manner, and the segmentations are now successfully generated.

Copy link
Member

@jcohenadad jcohenadad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be better to fix the issue inside sct_image instead?

def apply_intensity_normalization(fname_in, fname_out):
img = Image(fname_in)
img_normalized = img.copy()
p2, p98 = np.percentile(img.data, (2, 98))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't int16 range -32,768 to 32,767?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am sorry, I am not sure to understand: does the below comment helps? Otherwise, May I ask you to re-explain to me? Thank you

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be better to fix the issue inside sct_image instead?

Maybe! But I am not sure to see how, Could you please help me? Merci

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry @charleygros i meant line 71 (below), where it says: out_range=(0, 255) (equivalent 8bit unsigned), whereas later in the code the data is converted to int16, hence we loose precision. Or am i missing something?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe skimage.img_as_uint could be useful here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to be a better solution, merci!

Just one question: The documentation says:

Negative input values will be clipped.

--> Could we assume that images will always have positive values?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i suggest we do, but we should check for it. If there are neg values, a "warning" should be sent.

@charleygros
Copy link
Member Author

The issue here is:

cd /Volumes/sct_testing/issues/20180517_issue1740
sct_image -i 9611-0_0-images_017_jvgre10TE2mm1001_trace15Cav.nii.gz -type int16 -o 9611-0_0-images_017_jvgre10TE2mm1001_trace15Cav_int16.nii.gz

Leads to:
screen shot 2018-05-17 at 8 15 38 pm

Concerning the -32,768 to 32,767:

cd /Volumes/sct_testing/issues/20180517_issue1740
python
>>> from msct_image import Image
>>> import numpy as np
>>> ii = Image('9611-0_0-images_017_jvgre10TE2mm1001_trace15Cav_-31_689_31_115999.nii.gz')
>>> np.min(ii.data), np.max(ii.data)
(-31.698, 31.115999)
>>> del ii
>>> quit()
sct_get_centerline -i 9611-0_0-images_017_jvgre10TE2mm1001_trace15Cav_-31_689_31_115999.nii.gz -c t2s

Leads to:
screen shot 2018-05-17 at 8 41 46 pm

@jcohenadad
Copy link
Member

jcohenadad commented May 18, 2018

Wouldn't it be better to fix the issue inside sct_image instead?

@charleygros I will look into it and provide suggestions

UPDATE 2018-05-18 10.20: There is already code inside msct_image.changeType() which is supposed to deal with that issue. Obviously this code is not working. So we should just fix that part, without the need to add a rescaling in sct_deepseg_sc: simply calling msct_image.changeType() should work.

@jcohenadad jcohenadad added this to the 3.2.0 milestone May 18, 2018
@charleygros
Copy link
Member Author

charleygros commented May 18, 2018

Image with intensities between -31.689 and 31.115999:

sct_get_centerline -i 9611-0_0-images_017_jvgre10TE2mm1001_trace15Cav_-31_689_31_115999.nii.gz -c t2s

leads to:

--
Spinal Cord Toolbox (cg_i1740/f2ba0738910525997abb8f3f4fca1c5cdd981335)
Running /Users/chgroc/spinalcordtoolbox/scripts/sct_get_centerline.py -i 9611-0_0-images_017_jvgre10TE2mm1001_trace15Cav_-31_689_31_115999.nii.gz -c t2s
Configuring sentry report
sentry is set!
Detecting the spinal cord using OptiC
cp /Volumes/sct_testing/issues/20180517_issue1740/9611-0_0-images_017_jvgre10TE2mm1001_trace15Cav_-31_689_31_115999.nii.gz /var/folders/0_/g93k0_9d53ggwtb6hxgmw10c19x4f8/T/sct-180517211726-1XTrCK
Traceback (most recent call last):
  File "/Users/chgroc/spinalcordtoolbox/scripts/sct_get_centerline.py", line 266, in <module>
    run_main()
  File "/Users/chgroc/spinalcordtoolbox/scripts/sct_get_centerline.py", line 261, in run_main
    verbose=verbose)
  File "/Users/chgroc/spinalcordtoolbox/spinalcordtoolbox/centerline/optic.py", line 108, in detect_centerline
    scale_intensities_uint16(image_fname, image_int_filename)
  File "/Users/chgroc/spinalcordtoolbox/spinalcordtoolbox/centerline/optic.py", line 70, in scale_intensities_uint16
    img_scaled.data = img_as_uint(img.data)
  File "/Users/chgroc/spinalcordtoolbox/python/lib/python2.7/site-packages/skimage/util/dtype.py", line 325, in img_as_uint
    return convert(image, np.uint16, force_copy)
  File "/Users/chgroc/spinalcordtoolbox/python/lib/python2.7/site-packages/skimage/util/dtype.py", line 205, in convert
    raise ValueError("Images of type float must be between -1 and 1.")
ValueError: Images of type float must be between -1 and 1.
Sentry is attempting to send 1 pending error messages
Waiting up to 10 seconds
Press Ctrl-C to quit
[1]+  Done                    fslview 9611-0_0-images_017_jvgre10TE2mm1001_trace15Cav.nii.gz -l Greyscale ./9611-0_0-images_017_jvgre10TE2mm1001_trace15Cav_centerline_optic.nii.gz -l Red -t 1

@jcohenadad
Copy link
Member

jcohenadad commented May 18, 2018

in response to this comment: can't we do a rescaling, by adjusting the in_min and in_max to the out_min and out_max, as done here? That would solve issue with neg values.

@charleygros
Copy link
Member Author

charleygros commented May 18, 2018

Travis showed error of sct_testing -f sct_propseg.
Reason:
https://github.com/neuropoly/spinalcordtoolbox/blob/master/scripts/sct_propseg.py#L530
The output of PropSeg is converted to int8 --> a scaling of [0, 1] leads to [-127, 128] --> Dice = 0, because of this commit:
f26a735

I would suggest to:

  • keep the former implementation of msct_image.changeType since removing the "if condition" will certainly break other functions
  • do the uint16-scaling in sct_get_centerline then change the type

@jcohenadad
Copy link
Member

Let's do a comparative test as in #1757 before merging. I'll take care of that and add results in this PR.

Copy link
Member

@jcohenadad jcohenadad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's wait for the comparative tests before merging

@jcohenadad
Copy link
Member

jcohenadad commented May 22, 2018

Below are the Dice results:
violin_plot

The logs and pickles are under Gdrive/NeuroPoly/Projects/SCT/testing:

  • results_test_sct_deepseg_sc_180522015441 --> cg_i1740
  • results_test_sct_deepseg_sc_180521063534 --> master

As expected, cg_i1740 solves the issue on these two problematic datasets:

prague_sct-users_20180518
unknown_sct-users_20180518

However, that should result in at least two fails less, whereas there is only one fail less compared to master, which means that this PR does break compatibility in other datasets. Investigating...

UPDATE 2018-05-22 10.26: When pulling cg_i1740 and trying locally on this subject, a segmentation is created. Maybe there was an issue with branch management on cedar (probably my fault). I'll re-run.

UPDATE 2018-05-22 11.10: I've re-run, making sure cg_i1740 was selected, but there are still blank segmentation on the problematic subjects. Investigating...

UPDATE 2018-05-22 11.18: When running the job in interactive mode, i confirm the running branch is cg_i1740. Investigating further...

UPDATE 2018-05-22 11.24: Realizing now that the modified function was under /spinalcordtoolbox (i though it was only under /scripts), meaning that SCT should have been reinstalled. Nice way to loose 2h...

UPDATE 2018-05-22 14.17: After reinstalling with -p -m -b -d, I still have blank segmentations, as if the re-installation did not successfully update /spinalcordtoolbox modules. Now doing a full installation (with only flag -p) --> THAT WORKED! Anyone has any idea why ./install_sct -p -m -b -d did not update spinalcordtoolbox/centerline but ./install_sct -p did? I though that the line pip install ${SCT_SOURCE} was supposed to update the /spinalcordtoolbox modules? @zougloub do you have any idea? This is not the first time that happened to me (#1702).

UPDATE 2018-05-22 17.09: Updated violin plots and (now with working installation).

@jcohenadad jcohenadad mentioned this pull request May 22, 2018
@charleygros
Copy link
Member Author

charleygros commented May 22, 2018

@jcohenadad: By comparing the two pickles (master and cg_i1740):

path_cg = '/Users/chgroc/code/i1740/cg_i.pickle'
path_master = '/Users/chgroc/code/i1740/master.pickle'

pickle_file = open(path_cg)
cg_data = pickle.load(pickle_file)
cg_status99 = cg_data[(cg_data.status == 99)]['path_data'].apply(lambda x: x.split('/')[5])

pickle_file = open(path_master)
master_data = pickle.load(pickle_file)
master_status99 = master_data[(master_data.status == 99)]['path_data'].apply(lambda x: x.split('/')[6])

print list(set(set(cg_status99)-set(master_status99)))

we obtain the following result:

['milan_20160628-marcella_DCD-20110907']

I will investigate further this subject

UPDATE 2018-05-22 10.13: I have run locally this subject on the branch cg_i1740 --> all was good: Am I missing something?

UPDATE 2018-05-22 10.17: For this subject (['milan_20160628-marcella_DCD-20110907']), the different status is due to:
On master the dice is: 0.80005518 --> status=0
On cg_i1740 the dice is: 0.79990912 --> status=99

@jcohenadad jcohenadad merged commit dea98c9 into master May 22, 2018
@jcohenadad jcohenadad deleted the cg_i1740 branch May 22, 2018 23:46
@jcohenadad jcohenadad added the enhancement category: improves performance/results of an existing feature label May 27, 2018
@jcohenadad jcohenadad changed the title Make sct_get_centerline robust to intensities ∈ [0, 1] Make sct_get_centerline robust to intensities with range [0, 1] May 27, 2018
jcohenadad pushed a commit that referenced this pull request Dec 18, 2019
* add a intensity scaling prior to int16 conversion to prevent intensity < 1

* Add refs in the header of the functions

* add ref optic deepseg_sc

* convert to uint16

* for intensities between 0 and 1 the data was not rescaled, we removed the "if" condition

* use changeType

* the if condition is crucial for binary images as input.

* use skimage.img_as_uint + be robust to negative values with an intensity translation

* img_as_int instead of img_as_uint

* replace the skimage functions --> rescale in uint16 range then convert to uint16


Former-commit-id: dea98c9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement category: improves performance/results of an existing feature sct_get_centerline context:
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants