Difference between revisions of "Moffitt 2014"

From NAMIC Wiki
Jump to: navigation, search
m (Text replacement - "http://www.slicer.org/slicerWiki/index.php/" to "https://www.slicer.org/wiki/")
 
(12 intermediate revisions by one other user not shown)
Line 1: Line 1:
 
==Logistics==
 
==Logistics==
 
SPL personnel: Andrey Fedorov, Ph.D.
 
SPL personnel: Andrey Fedorov, Ph.D.
 +
 
Local hosts: Robert Gillies, Ph.D., Olya Grove, Ph.D.
 
Local hosts: Robert Gillies, Ph.D., Olya Grove, Ph.D.
  
Line 9: Line 10:
 
* Wed 9-10:30am
 
* Wed 9-10:30am
 
* Wed 1-3pm
 
* Wed 1-3pm
 +
 +
[[File:Moffitt-Slicer-Workshop-2014-pic1.jpg|350px]]
 +
[[File:Moffitt-Slicer-Workshop-2014-pic2.jpg|350px]]
 +
 +
[[File:Moffitt-Slicer-Workshop-2014-pic3.jpg|350px]]
 +
[[File:Moffitt-Slicer-Workshop-2014-pic4.jpg|350px]]
 +
 +
[[File:Moffitt-Slicer-Workshop-2014-pic5.jpg|350px]]
 +
  
 
==Notes and references for the meeting==
 
==Notes and references for the meeting==
Line 30: Line 40:
 
* Interfacing Matlab
 
* Interfacing Matlab
 
** MatlabBridge extension
 
** MatlabBridge extension
** Tutorial, documentation, teaching videos: http://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Extensions/MatlabBridge
+
** Tutorial, documentation, teaching videos: https://www.slicer.org/wiki/Documentation/Nightly/Extensions/MatlabBridge
  
 
* General introduction user tutorials: http://wiki.slicer.org/slicerWiki/index.php/Documentation/4.3/Training#General_Introduction
 
* General introduction user tutorials: http://wiki.slicer.org/slicerWiki/index.php/Documentation/4.3/Training#General_Introduction
 
* Developer tutorials: http://wiki.slicer.org/slicerWiki/index.php/Documentation/4.3/Training#Tutorials_for_software_developers
 
* Developer tutorials: http://wiki.slicer.org/slicerWiki/index.php/Documentation/4.3/Training#Tutorials_for_software_developers
 +
* Feature extraction: HeterogeneityCAD extension: http://wiki.slicer.org/slicerWiki/index.php/Documentation/Nightly/Modules/HeterogeneityCAD
 +
 +
Batch processing needed:
 +
# Load DICOM volume and corresponding label
 +
# Extract features
 +
# save features in txt file
 +
 +
===Follow-up items===
 +
 +
* Lung and nodule segmentation and feature extraction screencast: http://youtu.be/koHKAJWGNhU
 +
 +
* Scripts for converting legacy PGM segmentations into Slicer-compatible format:
  
* Feature extraction: HeterogeneityCAD extension: http://wiki.slicer.org/slicerWiki/index.php/Documentation/Nightly/Modules/HeterogeneityCAD
+
First, convert PGM into PNG (PGM is not recognized by Slicer image readers). Python script to do this is below. Save as a .py file, make sure python is installed, run from command line (modify the input and output directories as needed):
 +
 
 +
<pre>
 +
import Image
 +
input = '/Users/fedorov/ImageData/Moffitt/Label_conversion/MOFFITT/P2/lung/'
 +
output = '/Users/fedorov/ImageData/Moffitt/Label_conversion/MOFFITT/P2/lung-png/'
 +
for fn in range(len(input)):
 +
  flong = "%06i" % (fn)
 +
  print flong
 +
  Image.open(input+str(fn)+'.pgm').save(output+flong+'.png')
 +
</pre>
 +
 
 +
Once converted to PNG, run the following script to convert the label slices into 3d format:
 +
 
 +
import sys, os, slicer, vtk
 +
 
 +
<pre>
 +
'''
 +
Usage:
 +
  Slicer.exe --no-splash --no-main-window --python-script converter.py <directory with DICOM files> <directory with segmentation files> <output directory>
 +
 
 +
'''
 +
 
 +
dcmDir = sys.argv[1]
 +
segDir = sys.argv[2]
 +
outputDir = sys.argv[3]
 +
 
 +
print(dcmDir)
 +
print(segDir)
 +
print(outputDir)
 +
 
 +
# get lists of DICOM and seg files with full path names
 +
# DICOM files fill be sorted by the slice positions for volume reconstruction
 +
dcmList = []
 +
for dcm in os.listdir(dcmDir):
 +
  if len(dcm)-dcm.rfind('.dcm') == 4:
 +
    dcmList.append(dcmDir+'/'+dcm)
 +
 
 +
# segmentation files need to be sorted,
 +
# assuming here that alphabetical sorting is consistent with the sorting
 +
# applied to DICOM files
 +
segList = []
 +
for seg in os.listdir(segDir):
 +
  # assume segmentations are saved in PNG format, change here if another one
 +
  segList.append(segDir+'/'+seg)
 +
segList.sort()
 +
segList.reverse()
 +
 
 +
print(str(segList))
 +
 
 +
scalarVolumePlugin = slicer.modules.dicomPlugins['DICOMScalarVolumePlugin']()
 +
 
 +
# index input DICOM series
 +
indexer = ctk.ctkDICOMIndexer()
 +
indexer.addDirectory(slicer.dicomDatabase, dcmDir)
 +
indexer.waitForImportFinished()
 +
 
 +
loadables = scalarVolumePlugin.examine([dcmList])
 +
 
 +
if len(loadables) == 0:
 +
  print 'Could not parse the DICOM Study!'
 +
  exit()
 +
 
 +
# load input DICOM volume
 +
dcmVolume = scalarVolumePlugin.load(loadables[0])
 +
 
 +
# save DICOM volume as single file nrrd format
 +
dcmStorage = slicer.vtkMRMLVolumeArchetypeStorageNode()
 +
dcmStorage.SetWriteFileFormat('nrrd')
 +
dcmStorage.SetFileName(os.path.join(outputDir,'dcm_volume.nrrd'))
 +
dcmStorage.WriteData(dcmVolume)
 +
 
 +
print('Before instantiating')
 +
segStorage = slicer.vtkMRMLVolumeArchetypeStorageNode()
 +
segStorage.ResetFileNameList()
 +
for seg in segList:
 +
  segStorage.AddFileName(seg)
 +
segStorage.SetFileName(segList[0])
 +
print(str(segList))
 +
segStorage.SetSingleFile(0)
 +
segVolume = slicer.vtkMRMLScalarVolumeNode()
 +
print('Before reading')
 +
segStorage.ReadData(segVolume)
 +
print('After reading')
 +
 
 +
# convert to unsigned short pixel type
 +
cast = vtk.vtkImageCast()
 +
if vtk.vtkVersion().GetVTKMajorVersion() < 6:
 +
  cast.SetInput(segVolume.GetImageData())
 +
else:
 +
  cast.SetInputData(segVolume.GetImageData())
 +
cast.SetOutputScalarTypeToShort()
 +
cast.Update()
 +
 
 +
# assign segmentation the same geometry as the DICOM volume
 +
ijkToRAS = vtk.vtkMatrix4x4()
 +
dcmVolume.GetIJKToRASMatrix(ijkToRAS)
 +
 
 +
segVolume.SetIJKToRASMatrix(ijkToRAS)
 +
segVolume.SetAndObserveImageData(cast.GetOutput())
 +
 
 +
# save segmentation as a 3d volume in nrrd format
 +
segStorage.SetWriteFileFormat('nrrd')
 +
segStorage.SetFileName(os.path.join(outputDir,'seg_volume.nrrd'))
 +
segStorage.WriteData(segVolume)
 +
 
 +
sys.exit()
 +
</pre>
 +
 
 +
Raul San Jose: Airway inspector development in Slicer: http://lmi.bwh.harvard.edu/~rjosest/
 +
 
 +
==Slicer bugs identified during the visit==
 +
* LabelStatistics does not work occasionally. Not always reproducible. Workaround suggested: Install IASEM extension, use "Label Object Statistics" module instead.
 +
* Volume rendering of a segmented label volume is not automatically updated when editing is done: reproducible, bug reported: http://www.na-mic.org/Bug/view.php?id=3928
 +
* It seems that the image slice rendered in the 3d viewer does not go through the middle of the slice, at least when examined with slice segmentation volume rendered. May be related to existing issue: http://www.na-mic.org/Bug/view.php?id=3886
 +
*

Latest revision as of 18:07, 10 July 2017

Home < Moffitt 2014

Logistics

SPL personnel: Andrey Fedorov, Ph.D.

Local hosts: Robert Gillies, Ph.D., Olya Grove, Ph.D.

Dates: Dec 16-17, 2014

Working meeting times:

  • Tue 3-4pm
  • Wed 9-10:30am
  • Wed 1-3pm

Moffitt-Slicer-Workshop-2014-pic1.jpg Moffitt-Slicer-Workshop-2014-pic2.jpg

Moffitt-Slicer-Workshop-2014-pic3.jpg Moffitt-Slicer-Workshop-2014-pic4.jpg

Moffitt-Slicer-Workshop-2014-pic5.jpg


Notes and references for the meeting

  • DICOM RT conversion
    • Prerequisites: SlicerRT extension, conversion script added in the last week's version of SlicerRT
    • extensions are located on Windows in
 C:\Users\<your_user_name>\AppData\Roaming\NA-MIC
 Slicer.exe --no-splash --no-main-window --python-script <script> <arguments>
    • to see console messages (in python interactor), run without --no-main-window flag
    • make sure script name has '/', not '\', as path separator
    • make sure image volume for the RTSTRUCT is in the input folder
  • Lung and lesion segmentation
    • FastMarching effect in Editor module
    • GrowCut effect in Editor module, FastGrowCut extension

Batch processing needed:

  1. Load DICOM volume and corresponding label
  2. Extract features
  3. save features in txt file

Follow-up items

  • Scripts for converting legacy PGM segmentations into Slicer-compatible format:

First, convert PGM into PNG (PGM is not recognized by Slicer image readers). Python script to do this is below. Save as a .py file, make sure python is installed, run from command line (modify the input and output directories as needed):

import Image
input = '/Users/fedorov/ImageData/Moffitt/Label_conversion/MOFFITT/P2/lung/'
output = '/Users/fedorov/ImageData/Moffitt/Label_conversion/MOFFITT/P2/lung-png/'
for fn in range(len(input)):
  flong = "%06i" % (fn)
  print flong
  Image.open(input+str(fn)+'.pgm').save(output+flong+'.png')

Once converted to PNG, run the following script to convert the label slices into 3d format:

import sys, os, slicer, vtk

'''
 Usage:
  Slicer.exe --no-splash --no-main-window --python-script converter.py <directory with DICOM files> <directory with segmentation files> <output directory>

'''

dcmDir = sys.argv[1]
segDir = sys.argv[2]
outputDir = sys.argv[3]

print(dcmDir)
print(segDir)
print(outputDir)

# get lists of DICOM and seg files with full path names
# DICOM files fill be sorted by the slice positions for volume reconstruction
dcmList = []
for dcm in os.listdir(dcmDir):
  if len(dcm)-dcm.rfind('.dcm') == 4:
    dcmList.append(dcmDir+'/'+dcm)

# segmentation files need to be sorted,
# assuming here that alphabetical sorting is consistent with the sorting
# applied to DICOM files
segList = []
for seg in os.listdir(segDir):
  # assume segmentations are saved in PNG format, change here if another one
  segList.append(segDir+'/'+seg)
segList.sort()
segList.reverse()

print(str(segList))

scalarVolumePlugin = slicer.modules.dicomPlugins['DICOMScalarVolumePlugin']()

# index input DICOM series
indexer = ctk.ctkDICOMIndexer()
indexer.addDirectory(slicer.dicomDatabase, dcmDir)
indexer.waitForImportFinished()

loadables = scalarVolumePlugin.examine([dcmList])

if len(loadables) == 0:
  print 'Could not parse the DICOM Study!'
  exit()

# load input DICOM volume
dcmVolume = scalarVolumePlugin.load(loadables[0])

# save DICOM volume as single file nrrd format
dcmStorage = slicer.vtkMRMLVolumeArchetypeStorageNode()
dcmStorage.SetWriteFileFormat('nrrd')
dcmStorage.SetFileName(os.path.join(outputDir,'dcm_volume.nrrd'))
dcmStorage.WriteData(dcmVolume)

print('Before instantiating')
segStorage = slicer.vtkMRMLVolumeArchetypeStorageNode()
segStorage.ResetFileNameList()
for seg in segList:
  segStorage.AddFileName(seg)
segStorage.SetFileName(segList[0])
print(str(segList))
segStorage.SetSingleFile(0)
segVolume = slicer.vtkMRMLScalarVolumeNode()
print('Before reading')
segStorage.ReadData(segVolume)
print('After reading')

# convert to unsigned short pixel type
cast = vtk.vtkImageCast()
if vtk.vtkVersion().GetVTKMajorVersion() < 6:
  cast.SetInput(segVolume.GetImageData())
else:
  cast.SetInputData(segVolume.GetImageData())
cast.SetOutputScalarTypeToShort()
cast.Update()

# assign segmentation the same geometry as the DICOM volume
ijkToRAS = vtk.vtkMatrix4x4()
dcmVolume.GetIJKToRASMatrix(ijkToRAS)

segVolume.SetIJKToRASMatrix(ijkToRAS)
segVolume.SetAndObserveImageData(cast.GetOutput())

# save segmentation as a 3d volume in nrrd format
segStorage.SetWriteFileFormat('nrrd')
segStorage.SetFileName(os.path.join(outputDir,'seg_volume.nrrd'))
segStorage.WriteData(segVolume)

sys.exit()

Raul San Jose: Airway inspector development in Slicer: http://lmi.bwh.harvard.edu/~rjosest/

Slicer bugs identified during the visit

  • LabelStatistics does not work occasionally. Not always reproducible. Workaround suggested: Install IASEM extension, use "Label Object Statistics" module instead.
  • Volume rendering of a segmented label volume is not automatically updated when editing is done: reproducible, bug reported: http://www.na-mic.org/Bug/view.php?id=3928
  • It seems that the image slice rendered in the 3d viewer does not go through the middle of the slice, at least when examined with slice segmentation volume rendered. May be related to existing issue: http://www.na-mic.org/Bug/view.php?id=3886