def execute_module(self): # get the vtkDICOMVolumeReader to try and execute self._reader.Update() # now get some metadata out and insert it in our output stream # first determine axis labels based on IOP #################### iop = self._reader.GetImageOrientationPatient() row = iop[0:3] col = iop[3:6] # the cross product (plane normal) based on the row and col will # also be in the LPH coordinate system norm = [0,0,0] vtk.vtkMath.Cross(row, col, norm) xl = misc_utils.major_axis_from_iop_cosine(row) yl = misc_utils.major_axis_from_iop_cosine(col) zl = misc_utils.major_axis_from_iop_cosine(norm) lut = {'L' : 0, 'R' : 1, 'P' : 2, 'A' : 3, 'F' : 4, 'H' : 5} if xl and yl and zl: # add this data as a vtkFieldData fd = self._reader.GetOutput().GetFieldData() axis_labels_array = vtk.vtkIntArray() axis_labels_array.SetName('axis_labels_array') for l in xl + yl + zl: axis_labels_array.InsertNextValue(lut[l]) fd.AddArray(axis_labels_array)
def execute_module(self): # get the vtkDICOMVolumeReader to try and execute self._reader.Update() # now get some metadata out and insert it in our output stream # first determine axis labels based on IOP #################### iop = self._reader.GetImageOrientationPatient() row = iop[0:3] col = iop[3:6] # the cross product (plane normal) based on the row and col will # also be in the LPH coordinate system norm = [0, 0, 0] vtk.vtkMath.Cross(row, col, norm) xl = misc_utils.major_axis_from_iop_cosine(row) yl = misc_utils.major_axis_from_iop_cosine(col) zl = misc_utils.major_axis_from_iop_cosine(norm) lut = {'L': 0, 'R': 1, 'P': 2, 'A': 3, 'F': 4, 'H': 5} if xl and yl and zl: # add this data as a vtkFieldData fd = self._reader.GetOutput().GetFieldData() axis_labels_array = vtk.vtkIntArray() axis_labels_array.SetName('axis_labels_array') for l in xl + yl + zl: axis_labels_array.InsertNextValue(lut[l]) fd.AddArray(axis_labels_array)
def _update_image(self, gdcm_reader): """Given a vtkGDCMImageReader instance that has read the given file, update the image viewer. """ r = gdcm_reader self._image_viewer.SetInput(r.GetOutput()) #if r.GetNumberOfOverlays(): # self._image_viewer.AddInput(r.GetOverlay(0)) # now make the nice text overlay thingies! # DirectionCosines: first two columns are X and Y in the LPH # coordinate system dc = r.GetDirectionCosines() x_cosine = \ dc.GetElement(0,0), dc.GetElement(1,0), dc.GetElement(2,0) lph = misc_utils.major_axis_from_iop_cosine(x_cosine) if lph: self._image_viewer.xl_text_actor.SetInput(lph[0]) self._image_viewer.xr_text_actor.SetInput(lph[1]) else: self._image_viewer.xl_text_actor.SetInput('X') self._image_viewer.xr_text_actor.SetInput('X') y_cosine = \ dc.GetElement(0,1), dc.GetElement(1,1), dc.GetElement(2,1) lph = misc_utils.major_axis_from_iop_cosine(y_cosine) if lph: if r.GetFileLowerLeft(): # no swap b = lph[0] t = lph[1] else: # we have to swap these around because VTK has the # convention of image origin at the upper left and GDCM # dutifully swaps the images when loading to follow this # convention. Direction cosines (IOP) is not swapped, so # we have to compensate here. b = lph[1] t = lph[0] self._image_viewer.yb_text_actor.SetInput(b) self._image_viewer.yt_text_actor.SetInput(t) else: self._image_viewer.yb_text_actor.SetInput('X') self._image_viewer.yt_text_actor.SetInput('X') mip = r.GetMedicalImageProperties() d = r.GetOutput().GetDimensions() ul = self._image_viewer.ul_text_actor ul.imsize = (d[0], d[1]) ul.imnum = mip.GetImageNumber() # string ul.frnum = self._image_viewer.GetSlice() self._update_image_ul_text() ur = self._image_viewer.ur_text_actor ur.SetInput('%s\n%s\n%s\n%s' % ( mip.GetPatientName(), mip.GetPatientID(), mip.GetStudyDescription(), mip.GetSeriesDescription())) br = self._image_viewer.br_text_actor br.SetInput('DeVIDE\nTU Delft') # we have a new image in the image_viewer, so we have to reset # the camera so that the image is visible. if not self._config.lock_pz: self._reset_image_pz() # also reset window level if not self._config.lock_wl: self._reset_image_wl() self._image_viewer.Render()
def execute_module(self): # have to cast to normal strings (from unicode) filenames = [str(i) for i in self._config.dicom_filenames] # make sure all is zeroed. self._reader.SetFileName(None) self._reader.SetFileNames(None) # we only sort and derive slice-based spacing if there are # more than 1 filenames if len(filenames) > 1: sorter = gdcm.IPPSorter() sorter.SetComputeZSpacing(True) sorter.SetZSpacingTolerance(1e-2) ret = sorter.Sort(filenames) alpha_sorted = False if not ret: if self._config.robust_spacing: self._module_manager.log_warning( 'Could not sort DICOM filenames by IPP. Doing alphabetical sorting.') filenames.sort() alpha_sorted = True else: raise RuntimeError( 'Could not sort DICOM filenames before loading.') if sorter.GetZSpacing() == 0.0 and not alpha_sorted: msg = 'DICOM IPP sorting yielded incorrect results.' raise RuntimeError(msg) # then give the reader the sorted list of files sa = vtk.vtkStringArray() if alpha_sorted: flist = filenames else: flist = sorter.GetFilenames() for fn in flist: sa.InsertNextValue(fn) self._reader.SetFileNames(sa) elif len(filenames) == 1: self._reader.SetFileName(filenames[0]) else: raise RuntimeError( 'No DICOM filenames to read.') # now do the actual reading self._reader.Update() # see what the reader thinks the spacing is spacing = list(self._reader.GetDataSpacing()) if len(filenames) > 1 and not alpha_sorted: # after the reader has done its thing, # impose derived spacing on the vtkImageChangeInformation # (by default it takes the SpacingBetweenSlices, which is # not always correct) spacing[2] = sorter.GetZSpacing() # single or multiple filenames, we have to set the correct # output spacing on the image change information print "SPACING: ", spacing self._ici.SetOutputSpacing(spacing) self._ici.Update() # integrate DirectionCosines into output data ############### # DirectionCosines: first two columns are X and Y in the LPH # coordinate system dc = self._reader.GetDirectionCosines() x_cosine = \ dc.GetElement(0,0), dc.GetElement(1,0), dc.GetElement(2,0) y_cosine = \ dc.GetElement(0,1), dc.GetElement(1,1), dc.GetElement(2,1) # calculate plane normal (z axis) in LPH coordinate system by taking the cross product norm = [0,0,0] vtk.vtkMath.Cross(x_cosine, y_cosine, norm) xl = misc_utils.major_axis_from_iop_cosine(x_cosine) yl = misc_utils.major_axis_from_iop_cosine(y_cosine) # vtkGDCMImageReader swaps the y (to fit the VTK convention), # but does not flip the DirectionCosines here, so we do that. # (only if the reader is flipping) if yl and not self._reader.GetFileLowerLeft(): yl = tuple((yl[1], yl[0])) zl = misc_utils.major_axis_from_iop_cosine(norm) lut = {'L' : 0, 'R' : 1, 'P' : 2, 'A' : 3, 'F' : 4, 'H' : 5} if xl and yl and zl: # add this data as a vtkFieldData fd = self._ici.GetOutput().GetFieldData() axis_labels_array = vtk.vtkIntArray() axis_labels_array.SetName('axis_labels_array') for l in xl + yl + zl: axis_labels_array.InsertNextValue(lut[l]) fd.AddArray(axis_labels_array)
def _update_image(self, gdcm_reader): """Given a vtkGDCMImageReader instance that has read the given file, update the image viewer. """ r = gdcm_reader self._image_viewer.SetInput(r.GetOutput()) #if r.GetNumberOfOverlays(): # self._image_viewer.AddInput(r.GetOverlay(0)) # now make the nice text overlay thingies! # DirectionCosines: first two columns are X and Y in the LPH # coordinate system dc = r.GetDirectionCosines() x_cosine = \ dc.GetElement(0,0), dc.GetElement(1,0), dc.GetElement(2,0) lph = misc_utils.major_axis_from_iop_cosine(x_cosine) if lph: self._image_viewer.xl_text_actor.SetInput(lph[0]) self._image_viewer.xr_text_actor.SetInput(lph[1]) else: self._image_viewer.xl_text_actor.SetInput('X') self._image_viewer.xr_text_actor.SetInput('X') y_cosine = \ dc.GetElement(0,1), dc.GetElement(1,1), dc.GetElement(2,1) lph = misc_utils.major_axis_from_iop_cosine(y_cosine) if lph: if r.GetFileLowerLeft(): # no swap b = lph[0] t = lph[1] else: # we have to swap these around because VTK has the # convention of image origin at the upper left and GDCM # dutifully swaps the images when loading to follow this # convention. Direction cosines (IOP) is not swapped, so # we have to compensate here. b = lph[1] t = lph[0] self._image_viewer.yb_text_actor.SetInput(b) self._image_viewer.yt_text_actor.SetInput(t) else: self._image_viewer.yb_text_actor.SetInput('X') self._image_viewer.yt_text_actor.SetInput('X') mip = r.GetMedicalImageProperties() d = r.GetOutput().GetDimensions() ul = self._image_viewer.ul_text_actor ul.imsize = (d[0], d[1]) ul.imnum = mip.GetImageNumber() # string ul.frnum = self._image_viewer.GetSlice() self._update_image_ul_text() ur = self._image_viewer.ur_text_actor ur.SetInput('%s\n%s\n%s\n%s' % (mip.GetPatientName(), mip.GetPatientID(), mip.GetStudyDescription(), mip.GetSeriesDescription())) br = self._image_viewer.br_text_actor br.SetInput('DeVIDE\nTU Delft') # we have a new image in the image_viewer, so we have to reset # the camera so that the image is visible. if not self._config.lock_pz: self._reset_image_pz() # also reset window level if not self._config.lock_wl: self._reset_image_wl() self._image_viewer.Render()