Closed linnsog closed 6 years ago
You need to convert your tiff image to a 3D volume (and make it gray scale). See also this thread on the PyRadiomics forum and issue #298 here on the github.
The images are already gray scale. Do they need to be converted to nrrd files, and does the mask also need to be in 3d?
Yes and yes. Image and Mask must both be 3D (but when converting from 2D, they will have a size of 1 in the 3rd dimension).
You can do this using SimpleITK.JoinSeries()
, but check that the images are really grayscale (i.e. not a vector for each pixel value, check this by print(im)
, where im
is a SimpleITK image object).
Related: what is the origin of your tiff images? If the origin is DICOM, it is better to directly convert DICOM to NRRD (as in tiff, spacing information etc. is often discarded).
The images are original in tif. We made the mask from numpy.ones(), and made it the same size as the image (since the whole image is of interest). Then added a new axis to make it 3d and made a nrrd-file. We also converted the tif image to 3d with "image3d = sitk.JoinSeries(image2d)", but we are having problems to make it in to a nrrd file so we can us it as input in the RadiomicsFirstOrder class.
2018-01-22 12:07 GMT+01:00 Joost van Griethuysen notifications@github.com:
Yes and yes. Image and Mask must both be 3D (but when converting from 2D, they will have a size of 1 in the 3rd dimension).
You can do this using SimpleITK.JoinSeries(), but check that the images are really grayscale (i.e. not a vector for each pixel value, check this by print(im), where im is a SimpleITK image object).
Related: what is the origin of your tiff images? If the origin is DICOM, it is better to directly convert DICOM to NRRD (as in tiff, spacing information etc. is often discarded).
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Radiomics/pyradiomics/issues/339#issuecomment-359392204, or mute the thread https://github.com/notifications/unsubscribe-auth/AV5s4FtOlCaX37e7WJULUztHCSzAO2AHks5tNGv5gaJpZM4Rmcep .
Try this:
import SimpleITK as sitk
import numpy
from radiomics import featureextractor
# Transform input
im_tiff = sitk.ReadImage('path/to/image.tiff')
im_vect = sitk.JoinSeries(im_tiff) # Add 3rd dimension
im = sitk.VectorImageSelectionCast(im_vect, 0, sitk.sitkFloat64) # Select first color channel (if image is grayscale, all channels are equal)
# Build full mask
im_arr = sitk.GetArrayFromImage(im)
ma_arr = numpy.ones(im_arr.shape)
ma = sitk.GetImageFromArray(ma_arr)
ma.CopyInformation(im)
# Instantiate extractor
extractor = featureextractor.RadiomicsFeaturesExtractor('path/to/config') # optional supply parameter file)
# extractor = featureextractor.RadiomicsFeaturesExtractor() # Default settings
# Enable just first order
extractor.disableAllFeatures()
extractor.enableFeatureClassByName('firstorder')
# Extract features
results = extractor.execute(im, ma)
If you want to store it as a nrrd, run this as well:
sitk.WriteImage(im, 'path/to/image.nrrd')
Don't forget the correct extension, SimpleITK uses this to determine the format.
Looks like it's working now. Thanks a lot!
2018-01-22 14:51 GMT+01:00 Joost van Griethuysen notifications@github.com:
Try this:
import SimpleITK as sitk import numpy from radiomics import featureextractor
Transform input
im_tiff = sitk.ReadImage('path/to/image.tiff') im_vect = sitk.JoinSeries(im_tiff) # Add 3rd dimension im = sitk.VectorImageSelectionCast(im_vect, 0, sitk.sitkFloat64) # Select first color channel (if image is grayscale, all channels are equal)
Build full mask
im_arr = sitk.GetArrayFromImage(im) ma_arr = numpy.ones(im_arr.shape) ma = sitk.GetImageFromArray(ma_arr) ma.CopyInformation(im)
Instantiate extractor
extractor = featureextractor.RadiomicsFeaturesExtractor('path/to/config') # optional supply parameter file)
extractor = featureextractor.RadiomicsFeaturesExtractor() # Default settings
Enable just first order
extractor.disableAllFeatures extractor.enableFeatureClassByName('firstorder')
Extract features
results = extractor.execute(im, ma)
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Radiomics/pyradiomics/issues/339#issuecomment-359428638, or mute the thread https://github.com/notifications/unsubscribe-auth/AV5s4CjqSQn1t-fHYKI53dBCas_poa6Wks5tNJJIgaJpZM4Rmcep .
@JoostJM I have a similar question , whether the DCM image (2D) also needs to convert to 3D?
@QiChen2014 Yes
Try this:
import SimpleITK as sitk import numpy from radiomics import featureextractor # Transform input im_tiff = sitk.ReadImage('path/to/image.tiff') im_vect = sitk.JoinSeries(im_tiff) # Add 3rd dimension im = sitk.VectorImageSelectionCast(im_vect, 0, sitk.sitkFloat64) # Select first color channel (if image is grayscale, all channels are equal) # Build full mask im_arr = sitk.GetArrayFromImage(im) ma_arr = numpy.ones(im_arr.shape) ma = sitk.GetImageFromArray(ma_arr) ma.CopyInformation(im) # Instantiate extractor extractor = featureextractor.RadiomicsFeaturesExtractor('path/to/config') # optional supply parameter file) # extractor = featureextractor.RadiomicsFeaturesExtractor() # Default settings # Enable just first order extractor.disableAllFeatures() extractor.enableFeatureClassByName('firstorder') # Extract features results = extractor.execute(im, ma)
How to convert tif image (RGB) into grayscale image?
@destinybuilt, PyRadiomics has since been upgraded and now also supports 2D input. Therefore, the addition of the 3rd dimension is no longer necessary.
However, PyRadiomics does still require a scalar datatype. Your example constitutes one way of dealing with this (extracting features for channels separately). You can also put this in a loop to extract for all channels:
import SimpleITK as sitk
import numpy
from radiomics import featureextractor
# Transform input
im_vect = sitk.ReadImage('path/to/image.tiff')
# im_vect = sitk.JoinSeries(im_vect) # Add 3rd dimension, NO LONGER NECESSARY
# Build full mask
im_size = numpy.array(im_vect.GetSize())[::-1] # flip x, y, z to z, y, x
ma_arr = numpy.ones(im_size)
ma = sitk.GetImageFromArray(ma_arr)
ma.CopyInformation(im_vect)
# Instantiate extractor
extractor = featureextractor.RadiomicsFeaturesExtractor('path/to/config') # optional supply parameter file)
# extractor = featureextractor.RadiomicsFeaturesExtractor() # Default settings
# Enable just first order
extractor.disableAllFeatures()
extractor.enableFeatureClassByName('firstorder')
# Extract features
results = []
selector = sitk.VectorIndexSelectionCastImageFilter()
for i in range(im_vect.GetNumberOfComponentsPerPixel()):
selector.SetIndex(i)
im = selector.Execute(im_vect) # Select first color channel (if image is grayscale, all channels are equal)
channel_result = extractor.execute(im, ma)
channel_result["channel"] = i
results.append(channel_result
Alternatively, you can merge the channels prior to extraction (yielding a scalar volume). For this, you'd need to decide how to aggregate the information from the separate channels. E.g. take the mean, max, min...
@destinybuilt, PyRadiomics has since been upgraded and now also supports 2D input. Therefore, the addition of the 3rd dimension is no longer necessary.
However, PyRadiomics does still require a scalar datatype. Your example constitutes one way of dealing with this (extracting features for channels separately). You can also put this in a loop to extract for all channels:
import SimpleITK as sitk import numpy from radiomics import featureextractor # Transform input im_vect = sitk.ReadImage('path/to/image.tiff') # im_vect = sitk.JoinSeries(im_vect) # Add 3rd dimension, NO LONGER NECESSARY # Build full mask im_size = numpy.array(im_vect.GetSize())[::-1] # flip x, y, z to z, y, x ma_arr = numpy.ones(im_size) ma = sitk.GetImageFromArray(ma_arr) ma.CopyInformation(im_vect) # Instantiate extractor extractor = featureextractor.RadiomicsFeaturesExtractor('path/to/config') # optional supply parameter file) # extractor = featureextractor.RadiomicsFeaturesExtractor() # Default settings # Enable just first order extractor.disableAllFeatures() extractor.enableFeatureClassByName('firstorder') # Extract features results = [] selector = sitk.VectorIndexSelectionCastImageFilter() for i in range(im_vect.GetNumberOfComponentsPerPixel()): selector.SetIndex(i) im = selector.Execute(im_vect) # Select first color channel (if image is grayscale, all channels are equal) channel_result = extractor.execute(im, ma) channel_result["channel"] = i results.append(channel_result
Alternatively, you can merge the channels prior to extraction (yielding a scalar volume). For this, you'd need to decide how to aggregate the information from the separate channels. E.g. take the mean, max, min...
Thank you for your reply! Maybe I should explain to you the purpose of applying pyradiomics to tif images: I want to extract all the features of the tif image...not just the first-order features; I use matlab to read the tif file (info = Tiff('path /to/image.tif', 'r');), read my image and mask (I already have a mask file so I don't need numpy to generate the mask) are 2D RGB files; see this post Previous content, so I thought I would like to increase the third dimension of my two tif files (set to 1), and I found that after using the sitk.JoinSeries function, the third dimension of my original tif file did not Was changed (I have never used simple itk and pyradiomics, so I guess maybe I don't know how to save the changed file overwrite to the original path...) The following is the code I used to run pyradiomics for extraction. Can you help to modify the code to meet the purpose of extracting all the features of the tif file (about twenty patients)? thank you very much!
import radiomics import radiomics.featureextractor as FEE import SimpleITK as sitk
main_path = r'D:\1Transition\1Trans\Test' ori_name = r'\tissueSlide.tif' lab_name = r'\mask.tif' para_name = r'\Params.yaml'
ori_path = main_path + ori_name # image path lab_path = main_path + lab_name # mask path para_path = main_path + para_name print("originl path: " + ori_path) print("label path: " + lab_path) print("parameter path: " + para_path)
extractor = FEE.RadiomicsFeaturesExtractor(para_path) print("Extraction parameters:\n\t", extractor.settings) print("Enabled filters:\n\t", extractor._enabledImagetypes) print("Enabled features:\n\t", extractor._enabledFeatures)
result = extractor.execute(ori_path, lab_path) # Extract features print("Result type:", type(result)) # result is returned in a Python ordered dictionary print("") print("Calculated features") for key, value in result.items(): # Output features print("\t", key, ":", value)
You can apply the following code, it will extract features for each channel in the image, and use the first channel in mask to get the mask (I assume all 3 channels in the mask are identical). If your image is grayscale, you can extract from 1 channel (e.g. channel 0), as all channels are the same.
Finally, I'd advise using a parameter file. The documentation for this is here.
You need a list of python tuples, which each tuple consisting of 3 values: p_name (identifier for your case), string pointing to the location of the image file and string pointing to the location of the mask file.
e.g.:
get_patients = [
('case_1', r'path\to\case_1\image.tiff', r'path\to\case_1\mask.tiff'),
('case_2', r'path\to\case_2\image.tiff', r'path\to\case_2\mask.tiff'),
...,
('case_n', r'path\to\case_n\image.tiff', r'path\to\case_n\mask.tiff'),
]
You can then use this piece of code:
import SimpleITK as sitk
import numpy
from radiomics import featureextractor
param_file = r'path\to\config.yml'
# Instantiate extractor
extractor = featureextractor.RadiomicsFeaturesExtractor('path/to/config') # optional supply parameter file)
results_dict = {}
# Extract features for each case
for p_name, im_path, ma_path in get_patients:
# Transform input
im_vect = sitk.ReadImage(im_path)
# Extract features
results = []
selector = sitk.VectorIndexSelectionCastImageFilter()
for i in range(im_vect.GetNumberOfComponentsPerPixel()): # extract features for each channel
selector.SetIndex(i)
im = selector.Execute(im_vect) # Select first color channel (if image is grayscale, all channels are equal)
channel_result = extractor.execute(im, ma_path, label_channel=0) # label_channel = 0 selects the first channel in the mask tiff image
channel_result["channel"] = i
results.append(channel_result
results_dict[p_name] = results
This will give you a python dictionary (results_dict), with 1 entry for each case. each entry value is a list (length = number of channels), where each item in the list is another python dictionary, giving you the feature values for that case for that channel:
results_dict = {
'case_1': [
{ 'feature_1': value, 'feature_2': value, ..., 'feature_n': value},
{ 'feature_1': value, 'feature_2': value, ..., 'feature_n': value},
{ 'feature_1': value, 'feature_2': value, ..., 'feature_n': value}
],
'case_2': [
{ 'feature_1': value, 'feature_2': value, ..., 'feature_n': value},
{ 'feature_1': value, 'feature_2': value, ..., 'feature_n': value},
{ 'feature_1': value, 'feature_2': value, ..., 'feature_n': value}
],
...,
'case_n': [
{ 'feature_1': value, 'feature_2': value, ..., 'feature_n': value},
{ 'feature_1': value, 'feature_2': value, ..., 'feature_n': value},
{ 'feature_1': value, 'feature_2': value, ..., 'feature_n': value}
]
}
@JoostJM Thank you very much, I will run your code a bit, but it will still report an error. The error is: RuntimeError: Exception thrown in SimpleITK VectorIndexSelectionCastImageFilter_Execute: c:\d\vs14-win64-pkg\simpleitk\code\common\include\sitkDualMemberFunctionFactory.hxx:214: Sitk::ERROR: Pixel type: 8-bit unsigned integer is not supported in 2D byclass itk::simple::VectorIndexSelectionCastImageFilter Here is my code: import SimpleITK as sitk import numpy from radiomics import featureextractor
param_file = r'D:\1Transition\1Trans\Test\Params.yaml'
extractor = featureextractor.RadiomicsFeaturesExtractor(r'D:\1Transition\1Trans\Test\Params.yaml') # optional supply parameter file)
get_patients=[('case_1',r'D:\1Transition\1Trans\Test\tissueSlide.tif',r'D:\1Transition\1Trans\Test\mask.tif'),('case_2',r'D:\1Transition\1Trans\Test\tissueSlide.tif',r'D:\1Transition\1Trans\Test\mask.tif')]
results_dict = {}
for p_name, im_path, ma_path in get_patients:
im_vect = sitk.ReadImage(im_path)
results = [] selector = sitk.VectorIndexSelectionCastImageFilter() for i in range(im_vect.GetNumberOfComponentsPerPixel()): # extract features for each channel selector.SetIndex(i) im = selector.Execute(im_vect) # Select first color channel (if image is grayscale, all channels are equal) channel_result = extractor.execute(im, ma_path, label_channel=0) # label_channel = 0 selects the first channel in the mask tiff image channel_result["channel"] = i results.append(channel_result) results_dict[p_name] = results
I can't upload more than 10MB files (even if I use zip files). Can you give me one of your emails? I can pass you a tif file and the corresponding mask so that you can debug it.
Try this
import SimpleITK as sitk
import numpy
from radiomics import featureextractor
param_file = r'path\to\config.yml'
# Instantiate extractor
extractor = featureextractor.RadiomicsFeaturesExtractor('path/to/config') # optional supply parameter file)
results_dict = {}
# Extract features for each case
for p_name, im_path, ma_path in get_patients:
# Transform input
im_vect = sitk.ReadImage(im_path)
# Extract features
results = []
if im_vect.GetNumberOfComponentsPerPixel() == 1: # scalar image
results.append(extractor.execute(im_vect, ma_path, label_channel=0)
else: # vector image
selector = sitk.VectorIndexSelectionCastImageFilter()
for i in range(im_vect.GetNumberOfComponentsPerPixel()): # extract features for each channel
selector.SetIndex(i)
im = selector.Execute(im_vect) # Select first color channel (if image is grayscale, all channels are equal)
channel_result = extractor.execute(im, ma_path, label_channel=0) # label_channel = 0 selects the first channel in the mask tiff image
channel_result["channel"] = i
results.append(channel_result
results_dict[p_name] = results
@JoostJM It still reports an error....
TypeError: execute() got an unexpected keyword argument 'label_channel
@JoostJM The following is the image and mask I shared with Google Cloud Drive:
https://drive.google.com/file/d/1tEj9AwFzrh_j-rjQtXeb_7bf5HN8BP5U/view?usp=sharing https://drive.google.com/file/d/1uvrwiKjDuhiKWpLoHnO8wZsdLRZn2jOY/view?usp=sharing https://drive.google.com/file/d/1Xfycu5EXFezEq6DXVu1THHbPKh-Jnp9V/view?usp=sharing
Is it possible to use extract first order features on 2D tiff images using the built in class?