Does fastai v1 support .dcm file read? Thanks!
Hi, fast.ai is a library for accelerate Deep Learning. In case of .dcm (DICOM) is a standard, so it is implemented in medical packages but compatible with python.
Looks like .dcm is not yet supported, i got the following error when i tried creating ImageDataBunch
OSError: Traceback (most recent call last):
File "/opt/local/miniconda/envs/dl/lib/python3.7/site-packages/torch/utils/data/dataloader.py", line 138, in _worker_loop
samples = collate_fn([dataset[i] for i in batch_indices])
File "/opt/local/miniconda/envs/dl/lib/python3.7/site-packages/torch/utils/data/dataloader.py", line 138, in <listcomp>
samples = collate_fn([dataset[i] for i in batch_indices])
File "/opt/local/miniconda/envs/dl/lib/python3.7/site-packages/fastai/vision/data.py", line 73, in __getitem__
def __getitem__(self,i): return open_image(self.x[i]),self.y[i]
File "/opt/local/miniconda/envs/dl/lib/python3.7/site-packages/fastai/vision/image.py", line 355, in open_image
x = PIL.Image.open(fn).convert('RGB')
File "/opt/local/miniconda/envs/dl/lib/python3.7/site-packages/PIL/Image.py", line 2657, in open
% (filename if filename else fp))
OSError: cannot identify image file '/opt/local/external/rsna/data/train/e59728f7-a4ac-47d3-9962-429bcdb579ef.dcm'
i’m looking for work around to use fast v1 with .dcm files.
Can you share your code and data ?
data is based off of rsna pneumonia detection challenge kaggle competition.
I tried to create a labels.csv
file using only the image name and target variable, and then creation of ImageDataBunch
, ConvLearner
object and finally fit
.
data = vision.ImageDataBunch.from_csv(path, folder='train', csv_labels='labels.csv', valid_pct=0.2, suffix='.dcm')
learn = vision.ConvLearner(data, vision.models.resnet18, metrics=accuracy)
learn.fit(1)
@snmateen, I don’t know how important it is to keep the original format, but if it is not, perhaps you could just convert them?
mogrify -format JPEG *
and then use fastai normally?
mogrify is from imagemagick. it can handle pretty much any image format - of course choose the destination format that is not lossy, JPEG was just an example.
Check the source code for the various ImageDataset classes. It’s pretty easy to create a DICOM version from that.
Thanks @jeremy, i’m trying to replace the open_image
function with the below one.
from fastai.vision import Image
from fastai.vision import pil2tensor
def open_dcm_image(fn)->Image:
"Return `Image` object created from image in file `fn`."
array = pydicom.dcmread(fn).pixel_array
x = PIL.Image.fromarray(array).convert('RGB')
return Image(pil2tensor(x).float().div_(255))
fastai.vision.data.open_image = open_dcm_image
followed by
data = ImageDataBunch.from_csv(path,
folder='train',
csv_labels='labels.csv',
valid_pct=0.2, suffix='.dcm')
learn = ConvLearner(data, models.resnet18, metrics=accuracy)
learn.fit(1)
i’m i doing it right?
Just look at data.train_ds[0]
to see what it looks like. You might also check it loads batches properly by running next(iter(data.train_dl))
or data.show_batch()
.
@sgugger, yes it worked great! Thank you!
few more questions on similar topic, is resnet[35,50]
a good architecture for medical images such as X-rays?
can anyone suggest how to predict bounding boxes on X-rays?
Did it work? If so, how much did it slow down because of the conversion overhead?
Often for CT images, the pixels are uint16 which needs to be converted to uint8 while preserving the information. If you do a direct convert, the body will be completely white and most of the detail is lost. Four variables for converting the image are Intercept, Slope, window, and level. You can grab the first 2 from the dicom file. The second two depend on the body part of interest. For abdomen, window 350 and level 40 is a good start.
def open_dcm_image(fn)->Image:
dicom_file = pydicom.dcmread(str(fn))
arr = dicom_file.pixel_array.copy()
arr = arr + int(dicom_file.RescaleIntercept)
arr = arr * int(dicom_file.RescaleSlope)
level = 40; window = 350
arr = np.clip(arr, level - window / 2, level + window / 2)
x = pil2tensor(PIL.Image.fromarray(arr).convert("RGB"), np.float32).div_(255)
return Image(x)
Thanks astein for pointing out that pixel values need to be converted. However, slight change in the code based on following link http://www.idlcoyote.com/fileio_tips/hounsfield.html
# it should be
arr = arr * int(dicom_file.RescaleSlope) + int(dicom_file.RescaleIntercept)
Posting the entire code
def open_dcm_image(fn:PathOrStr, div:bool=True, convert_mode:str='RGB', cls:type=Image,
after_open:Callable=None)->Image:
"Return `Image` object created from image in file `fn`."
with warnings.catch_warnings():
warnings.simplefilter("ignore", UserWarning) # EXIF warning from TiffPlugin
#x= PIL.Image.open(fn).convert(convert_mode)
# code added for opening dcm images
dicom_file = pydicom.dcmread(str(fn))
arr = dicom_file.pixel_array.copy()
arr = arr * int(dicom_file.RescaleSlope) + int(dicom_file.RescaleIntercept)
level = 40; window = 80
arr = np.clip(arr, level - window // 2, level + window // 2)
x = Image.fromarray(arr).convert(convert_mode)
if after_open: x = after_open(x)
x = pil2tensor(x,np.float32)
if div: x.div_(255)
return cls(x)
Hi ! Fastai v2 include a full support for working with dicom images. Are these changed from 16 bits to 8 bits during common builtin transforms when loading?