def runMasking(self, ijkPoints, seedLabelmap, outputLabelmap): kernelSizePixel = self.getKernelSizePixel() self.floodFillingFilterIsland = vtk.vtkImageThresholdConnectivity() self.floodFillingFilterIsland.SetInputData(seedLabelmap) self.floodFillingFilterIsland.SetInValue(BACKGROUND_VALUE) self.floodFillingFilterIsland.ReplaceInOn() self.floodFillingFilterIsland.ReplaceOutOff() self.floodFillingFilterIsland.ThresholdBetween(LABEL_VALUE, LABEL_VALUE) self.floodFillingFilterIsland.SetSeedPoints(ijkPoints) self.dilate = vtk.vtkImageDilateErode3D() self.dilate.SetInputConnection(self.floodFillingFilterIsland.GetOutputPort()) self.dilate.SetDilateValue(LABEL_VALUE) self.dilate.SetErodeValue(BACKGROUND_VALUE) self.dilate.SetKernelSize( 2*kernelSizePixel[0]-1, 2*kernelSizePixel[1]-1, 2*kernelSizePixel[2]-1) self.dilate.Update() self.imageMask = vtk.vtkImageMask() self.imageMask.SetInputConnection(self.thresh.GetOutputPort()) self.imageMask.SetMaskedOutputValue(BACKGROUND_VALUE) self.imageMask.NotMaskOn() self.imageMask.SetMaskInputData(self.dilate.GetOutput()) self.floodFillingFilter = vtk.vtkImageThresholdConnectivity() self.floodFillingFilter.SetInputConnection(self.imageMask.GetOutputPort()) self.floodFillingFilter.SetInValue(LABEL_VALUE) self.floodFillingFilter.SetOutValue(BACKGROUND_VALUE) self.floodFillingFilter.ThresholdBetween(LABEL_VALUE, LABEL_VALUE) self.floodFillingFilter.SetSeedPoints(ijkPoints) self.floodFillingFilter.Update() outputLabelmap.ShallowCopy(self.floodFillingFilter.GetOutput())
def processInteractionEvents(self, callerInteractor, eventId, viewWidget): import vtkSegmentationCorePython as vtkSegmentationCore abortEvent = False # Only allow in modes where segment selection is needed if not self.currentOperationRequiresSegmentSelection(): return False # Only allow for slice views if viewWidget.className() != "qMRMLSliceWidget": return abortEvent if eventId != vtk.vtkCommand.LeftButtonPressEvent: return abortEvent abortEvent = True # Generate merged labelmap of all visible segments segmentationNode = self.scriptedEffect.parameterSetNode( ).GetSegmentationNode() visibleSegmentIds = vtk.vtkStringArray() segmentationNode.GetDisplayNode().GetVisibleSegmentIDs( visibleSegmentIds) if visibleSegmentIds.GetNumberOfValues() == 0: logging.info( "Smoothing operation skipped: there are no visible segments") return abortEvent self.scriptedEffect.saveStateForUndo() # This can be a long operation - indicate it to the user qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor) operationName = self.scriptedEffect.parameter("Operation") if operationName == ADD_SELECTED_ISLAND: inputLabelImage = vtkSegmentationCore.vtkOrientedImageData() if not segmentationNode.GenerateMergedLabelmapForAllSegments( inputLabelImage, vtkSegmentationCore.vtkSegmentation. EXTENT_UNION_OF_SEGMENTS_PADDED, None, visibleSegmentIds): logging.error( 'Failed to apply smoothing: cannot get list of visible segments' ) qt.QApplication.restoreOverrideCursor() return abortEvent else: selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap( ) # We need to know exactly the value of the segment voxels, apply threshold to make force the selected label value labelValue = 1 backgroundValue = 0 thresh = vtk.vtkImageThreshold() thresh.SetInputData(selectedSegmentLabelmap) thresh.ThresholdByLower(0) thresh.SetInValue(backgroundValue) thresh.SetOutValue(labelValue) thresh.SetOutputScalarType(selectedSegmentLabelmap.GetScalarType()) thresh.Update() # Create oriented image data from output import vtkSegmentationCorePython as vtkSegmentationCore inputLabelImage = vtkSegmentationCore.vtkOrientedImageData() inputLabelImage.ShallowCopy(thresh.GetOutput()) selectedSegmentLabelmapImageToWorldMatrix = vtk.vtkMatrix4x4() selectedSegmentLabelmap.GetImageToWorldMatrix( selectedSegmentLabelmapImageToWorldMatrix) inputLabelImage.SetImageToWorldMatrix( selectedSegmentLabelmapImageToWorldMatrix) xy = callerInteractor.GetEventPosition() ijk = self.xyToIjk(xy, viewWidget, inputLabelImage) pixelValue = inputLabelImage.GetScalarComponentAsFloat( ijk[0], ijk[1], ijk[2], 0) try: floodFillingFilter = vtk.vtkImageThresholdConnectivity() floodFillingFilter.SetInputData(inputLabelImage) seedPoints = vtk.vtkPoints() origin = inputLabelImage.GetOrigin() spacing = inputLabelImage.GetSpacing() seedPoints.InsertNextPoint(origin[0] + ijk[0] * spacing[0], origin[1] + ijk[1] * spacing[1], origin[2] + ijk[2] * spacing[2]) floodFillingFilter.SetSeedPoints(seedPoints) floodFillingFilter.ThresholdBetween(pixelValue, pixelValue) if operationName == ADD_SELECTED_ISLAND: floodFillingFilter.SetInValue(1) floodFillingFilter.SetOutValue(0) floodFillingFilter.Update() modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap( ) modifierLabelmap.DeepCopy(floodFillingFilter.GetOutput()) self.scriptedEffect.modifySelectedSegmentByLabelmap( modifierLabelmap, slicer. qSlicerSegmentEditorAbstractEffect.ModificationModeAdd) elif pixelValue != 0: # if clicked on empty part then there is nothing to remove or keep if operationName == KEEP_SELECTED_ISLAND: floodFillingFilter.SetInValue(1) floodFillingFilter.SetOutValue(0) else: # operationName == REMOVE_SELECTED_ISLAND: floodFillingFilter.SetInValue(1) floodFillingFilter.SetOutValue(0) floodFillingFilter.Update() modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap( ) modifierLabelmap.DeepCopy(floodFillingFilter.GetOutput()) if operationName == KEEP_SELECTED_ISLAND: self.scriptedEffect.modifySelectedSegmentByLabelmap( modifierLabelmap, slicer. qSlicerSegmentEditorAbstractEffect.ModificationModeSet) else: # operationName == REMOVE_SELECTED_ISLAND: self.scriptedEffect.modifySelectedSegmentByLabelmap( modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect. ModificationModeRemove) except IndexError: logging.error('apply: Failed to threshold master volume!') finally: qt.QApplication.restoreOverrideCursor() return abortEvent
def processInteractionEvents(self, callerInteractor, eventId, viewWidget): import vtkSegmentationCorePython as vtkSegmentationCore abortEvent = False # Only allow in modes where segment selection is needed if not self.currentOperationRequiresSegmentSelection(): return False # Only allow for slice views if viewWidget.className() != "qMRMLSliceWidget": return abortEvent if eventId != vtk.vtkCommand.LeftButtonPressEvent: return abortEvent abortEvent = True # Generate merged labelmap of all visible segments segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode() visibleSegmentIds = vtk.vtkStringArray() segmentationNode.GetDisplayNode().GetVisibleSegmentIDs(visibleSegmentIds) if visibleSegmentIds.GetNumberOfValues() == 0: logging.info("Smoothing operation skipped: there are no visible segments") return abortEvent self.scriptedEffect.saveStateForUndo() # This can be a long operation - indicate it to the user qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor) operationName = self.scriptedEffect.parameter("Operation") if operationName == ADD_SELECTED_ISLAND: inputLabelImage = vtkSegmentationCore.vtkOrientedImageData() if not segmentationNode.GenerateMergedLabelmapForAllSegments(inputLabelImage, vtkSegmentationCore.vtkSegmentation.EXTENT_UNION_OF_SEGMENTS_PADDED, None, visibleSegmentIds): logging.error('Failed to apply smoothing: cannot get list of visible segments') qt.QApplication.restoreOverrideCursor() return abortEvent else: selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap() # We need to know exactly the value of the segment voxels, apply threshold to make force the selected label value labelValue = 1 backgroundValue = 0 thresh = vtk.vtkImageThreshold() thresh.SetInputData(selectedSegmentLabelmap) thresh.ThresholdByLower(0) thresh.SetInValue(backgroundValue) thresh.SetOutValue(labelValue) thresh.SetOutputScalarType(selectedSegmentLabelmap.GetScalarType()) thresh.Update() # Create oriented image data from output import vtkSegmentationCorePython as vtkSegmentationCore inputLabelImage = vtkSegmentationCore.vtkOrientedImageData() inputLabelImage.ShallowCopy(thresh.GetOutput()) selectedSegmentLabelmapImageToWorldMatrix = vtk.vtkMatrix4x4() selectedSegmentLabelmap.GetImageToWorldMatrix(selectedSegmentLabelmapImageToWorldMatrix) inputLabelImage.SetImageToWorldMatrix(selectedSegmentLabelmapImageToWorldMatrix) xy = callerInteractor.GetEventPosition() ijk = self.xyToIjk(xy, viewWidget, inputLabelImage) pixelValue = inputLabelImage.GetScalarComponentAsFloat(ijk[0], ijk[1], ijk[2], 0) try: floodFillingFilter = vtk.vtkImageThresholdConnectivity() floodFillingFilter.SetInputData(inputLabelImage) seedPoints = vtk.vtkPoints() origin = inputLabelImage.GetOrigin() spacing = inputLabelImage.GetSpacing() seedPoints.InsertNextPoint(origin[0]+ijk[0]*spacing[0], origin[1]+ijk[1]*spacing[1], origin[2]+ijk[2]*spacing[2]) floodFillingFilter.SetSeedPoints(seedPoints) floodFillingFilter.ThresholdBetween(pixelValue, pixelValue) if operationName == ADD_SELECTED_ISLAND: floodFillingFilter.SetInValue(1) floodFillingFilter.SetOutValue(0) floodFillingFilter.Update() modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap() modifierLabelmap.DeepCopy(floodFillingFilter.GetOutput()) self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeAdd) elif pixelValue != 0: # if clicked on empty part then there is nothing to remove or keep if operationName == KEEP_SELECTED_ISLAND: floodFillingFilter.SetInValue(1) floodFillingFilter.SetOutValue(0) else: # operationName == REMOVE_SELECTED_ISLAND: floodFillingFilter.SetInValue(1) floodFillingFilter.SetOutValue(0) floodFillingFilter.Update() modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap() modifierLabelmap.DeepCopy(floodFillingFilter.GetOutput()) if operationName == KEEP_SELECTED_ISLAND: self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet) else: # operationName == REMOVE_SELECTED_ISLAND: self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeRemove) except IndexError: logging.error('apply: Failed to threshold master volume!') finally: qt.QApplication.restoreOverrideCursor() return abortEvent
cnt += 1 # Print idx and seed position coordinates print "idx: ", idx_seed print "seed position: ", pos_seed # Seed input seed = vtk.vtkPoints() for i in range(len(pos_seed)): ix = pos_seed[i][0] iy = pos_seed[i][1] iz = pos_seed[i][2] seed.InsertNextPoint([ix, iy, iz]) # Image Threshold Connectivity connectivityFilter = vtk.vtkImageThresholdConnectivity() connectivityFilter.SetInputConnection(reader.GetOutputPort()) connectivityFilter.SetSeedPoints(seed) connectivityFilter.ThresholdByUpper(1) connectivityFilter.ReplaceInOn() connectivityFilter.SetInValue(1) connectivityFilter.ReplaceOutOn() connectivityFilter.SetOutValue(0) connectivityFilter.Update() # Surface extraction using Marching Cube algorithm vmc2 = surfextract(connectivityFilter) # Write output as STL file saveSTL(vmc2, "bonus_connectivity_imgthresh")
def processInteractionEvents(self, callerInteractor, eventId, viewWidget): abortEvent = False # Only allow for slice views if viewWidget.className() != "qMRMLSliceWidget": return abortEvent if eventId == vtk.vtkCommand.LeftButtonPressEvent: self.scriptedEffect.saveStateForUndo() # Get master volume image data import vtkSegmentationCorePython as vtkSegmentationCore masterImageData = self.scriptedEffect.masterVolumeImageData() selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap( ) # Get modifier labelmap modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap() xy = callerInteractor.GetEventPosition() ijk = self.xyToIjk(xy, viewWidget, masterImageData) pixelValue = masterImageData.GetScalarComponentAsFloat( ijk[0], ijk[1], ijk[2], 0) useSegmentationAsStencil = False try: # This can be a long operation - indicate it to the user qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor) # Perform thresholding floodFillingFilter = vtk.vtkImageThresholdConnectivity() floodFillingFilter.SetInputData(masterImageData) seedPoints = vtk.vtkPoints() origin = masterImageData.GetOrigin() spacing = masterImageData.GetSpacing() seedPoints.InsertNextPoint(origin[0] + ijk[0] * spacing[0], origin[1] + ijk[1] * spacing[1], origin[2] + ijk[2] * spacing[2]) floodFillingFilter.SetSeedPoints(seedPoints) neighborhoodSizeMm = self.neighborhoodSizeMmSlider.value floodFillingFilter.SetNeighborhoodRadius( neighborhoodSizeMm, neighborhoodSizeMm, neighborhoodSizeMm) floodFillingFilter.SetNeighborhoodFraction(0.5) if useSegmentationAsStencil: stencilFilter = vtk.vtkImageToImageStencil() stencilFilter.SetInputData(selectedSegmentLabelmap) stencilFilter.ThresholdByLower(0) stencilFilter.Update() floodFillingFilter.SetStencilData( stencilFilter.GetOutput()) pixelValueTolerance = float( self.intensityToleranceSlider.value) floodFillingFilter.ThresholdBetween( pixelValue - pixelValueTolerance, pixelValue + pixelValueTolerance) floodFillingFilter.SetInValue(1) floodFillingFilter.SetOutValue(0) floodFillingFilter.Update() modifierLabelmap.DeepCopy(floodFillingFilter.GetOutput()) except IndexError: logging.error('apply: Failed to threshold master volume!') finally: qt.QApplication.restoreOverrideCursor() # Apply changes self.scriptedEffect.modifySelectedSegmentByLabelmap( modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeAdd) abortEvent = True return abortEvent
def segmentFromSeeds(self, images, image_pos_pat, image_ori_pat, seeds, iren, xplane, yplane, zplane): """ segmentFromSeeds: Extracts VOI from seeds INPUTS: ======= images: (vtkImageData) list of Input image to Transform seeds: vtkPoints list of seeded coordinates from picker OUTPUTS: ======= transformed_image (vtkImageData) Transformed imaged mapped to dicom coords frame transform (vtkTransform) Transform used """ for postS in range(1,len(images)): print "\n Segmenting image post no : %s " % str(postS) subimage = self.loadDisplay.subImage(images, postS) # Proceed to build reference frame for display objects based on DICOM coords [transformed_image, transform_cube] = self.loadDisplay.dicomTransform(subimage, image_pos_pat, image_ori_pat) # Calculate the center of the volume transformed_image.UpdateInformation() print "\nBoxwidget placed..." ################################################################# # The box widget observes the events invoked by the render window # interactor. These events come from user interaction in the render # window. # Place the interactor initially. The output of the reader is used to # place the box widget. self.boxWidget = vtk.vtkBoxWidget() self.boxWidget.SetInteractor(iren) self.boxWidget.SetPlaceFactor(1) self.boxWidget.SetInput(transformed_image) if( self.boundsPlane_presel != []): self.boxWidget.PlaceWidget( self.boundsPlane_presel ) # Construct a bounding box around the seeds init_seedsBounds = [0,0,0,0,0,0] seeds.GetBounds( init_seedsBounds ) if postS == 1: # polygonal data --> image stencil: # create a simple box VOI mask shape using previously found boundsPlane_preselected VOIStencil = vtk.vtkROIStencilSource() VOIStencil.SetShapeToBox() VOIStencil.SetBounds( init_seedsBounds ) VOIStencil.SetInformationInput(transformed_image) VOIStencil.Update() # cut the corresponding VOI region and set the background: extractVOI_imgstenc = vtk.vtkImageStencil() extractVOI_imgstenc.SetInput(transformed_image) extractVOI_imgstenc.SetStencil(VOIStencil.GetOutput()) extractVOI_imgstenc.ReverseStencilOff() extractVOI_imgstenc.SetBackgroundValue(0.0) extractVOI_imgstenc.Update() allSeededIm = vtk.vtkImageData() allSeededIm.DeepCopy( extractVOI_imgstenc.GetOutput() ) # Add some bounding box radius self.boxWidget.PlaceWidget( init_seedsBounds ) self.boundsPlane_presel = init_seedsBounds print "seeds.GetBounds" print init_seedsBounds self.boxWidget.AddObserver("InteractionEvent", self.SelectPolygons) self.boxWidget.On() # turn off planes xplane.Off() yplane.Off() iren.Start() self.boxWidget.Off() # polygonal data --> image stencil: print "\n Create vtkPolyDataToImageStencil with bounds:" print self.boundsPlane_presel # create a simple box VOI mask shape using previously found boundsPlane_preselected VOIStencil = vtk.vtkROIStencilSource() VOIStencil.SetShapeToBox() VOIStencil.SetBounds( self.boundsPlane_presel ) VOIStencil.SetInformationInput(transformed_image) VOIStencil.Update() # cut the corresponding VOI region and set the background: extractVOI_imgstenc = vtk.vtkImageStencil() extractVOI_imgstenc.SetInput(transformed_image) extractVOI_imgstenc.SetStencil(VOIStencil.GetOutput()) extractVOI_imgstenc.ReverseStencilOff() extractVOI_imgstenc.SetBackgroundValue(0.0) extractVOI_imgstenc.Update() # add subsecuent VOI stencils addsegROI = vtk.vtkImageMathematics() addsegROI.SetInput(0, allSeededIm) addsegROI.SetInput(1, extractVOI_imgstenc.GetOutput()) addsegROI.SetOperationToAdd() addsegROI.Update() # turn off the box allSeededIm = addsegROI.GetOutput() avegSeededIm = vtk.vtkImageMathematics() avegSeededIm.SetInput(0, allSeededIm) avegSeededIm.SetOperationToMultiplyByK() avegSeededIm.SetConstantK( 0.2 ) avegSeededIm.Update() # take out average image finalSeedIm = avegSeededIm.GetOutput() xplane.SetInput( finalSeedIm ) yplane.SetInput( finalSeedIm ) zplane.SetInput( finalSeedIm ) image_scalar_range = finalSeedIm.GetScalarRange() lThre = image_scalar_range[0] uThre = image_scalar_range[1] print "\n Image Scalar Range:" print image_scalar_range[0], image_scalar_range[1] print "Uper thresholding by" print uThre*0.25 ## Display histogram scalars = finalSeedIm.GetPointData().GetScalars() np_scalars = vtk_to_numpy(scalars) pylab.figure() pylab.hist(np_scalars.flatten(), histtype='bar') pylab.show() # Now performed threshold on initialized VOI # vtkImageThresholdConnectivity will perform a flood fill on an image, given upper and lower pixel intensity # thresholds. It works similarly to vtkImageThreshold, but also allows the user to set seed points to limit # the threshold operation to contiguous regions of the image. The filled region, or the "inside", will be passed # through to the output by default, while the "outside" will be replaced with zeros. The scalar type of the output is the same as the input. thresh_sub = vtk.vtkImageThresholdConnectivity() thresh_sub.SetSeedPoints(seeds) thresh_sub.SetNeighborhoodRadius(3, 3, 2) #The radius of the neighborhood that must be within the threshold values in order for the voxel to be included in the mask. The default radius is zero (one single voxel). The radius is measured in voxels thresh_sub.SetNeighborhoodFraction(0.10) #The fraction of the neighborhood that must be within the thresholds. The default value is 0.5. thresh_sub.ThresholdBetween(0.25*uThre, uThre); thresh_sub.SetInput( finalSeedIm ) thresh_sub.Update() xplane.SetInput( thresh_sub.GetOutput() ) yplane.SetInput( thresh_sub.GetOutput() ) zplane.SetInput( thresh_sub.GetOutput() ) iren.Start() # Convert VOIlesion into polygonal struct VOIlesion_poly = vtk.vtkMarchingCubes() VOIlesion_poly.SetValue(0,255) VOIlesion_poly.SetInput(thresh_sub.GetOutput()) VOIlesion_poly.ComputeNormalsOff() VOIlesion_poly.Update() # Recalculate num_voxels and vol_lesion on VOI nvoxels = VOIlesion_poly.GetOutput().GetNumberOfCells() print "\n Number of Voxels: %d" % nvoxels # After the filter has executed, use GetNumberOfVoxels() to find out how many voxels were filled. return VOIlesion_poly.GetOutput()
def testImageThresholdConnectivity(self): # This script is for testing the 3D flood fill filter. # Image pipeline renWin = vtk.vtkRenderWindow() renWin.SetSize(192, 256) reader = vtk.vtkImageReader() reader.ReleaseDataFlagOff() reader.SetDataByteOrderToLittleEndian() reader.SetDataExtent(0, 63, 0, 63, 2, 5) reader.SetDataSpacing(3.2, 3.2, 1.5) reader.SetFilePrefix(VTK_DATA_ROOT + "/Data/headsq/quarter") reader.SetDataMask(0x7fff) seeds = vtk.vtkPoints() seeds.InsertNextPoint(0, 0, 0) seeds.InsertNextPoint(100.8, 100.8, 0) replacein = ["ReplaceInOn", "ReplaceInOff"] replaceout = ["ReplaceOutOn", "ReplaceOutOff"] thresholds = [ "ThresholdByLower(800)", "ThresholdByUpper(1200)", "ThresholdBetween(800, 1200)" ] thresh = list() map = list() act = list() ren = list() k = 0 for rin in replacein: for rout in replaceout: for t in thresholds: thresh.append(vtk.vtkImageThresholdConnectivity()) thresh[k].SetSeedPoints(seeds) thresh[k].SetInValue(2000) thresh[k].SetOutValue(0) eval('thresh[k].' + rin + '()') eval('thresh[k].' + rout + '()') thresh[k].SetInputConnection(reader.GetOutputPort()) eval('thresh[k].' + t) map.append(vtk.vtkImageMapper()) map[k].SetInputConnection(thresh[k].GetOutputPort()) if k < 3: map[k].SetColorWindow(255) map[k].SetColorLevel(127.5) else: map[k].SetColorWindow(2000) map[k].SetColorLevel(1000) act.append(vtk.vtkActor2D()) act[k].SetMapper(map[k]) ren.append(vtk.vtkRenderer()) ren[k].AddActor2D(act[k]) renWin.AddRenderer(ren[k]) k += 1 ren[0].SetViewport(0, 0, .33333, .25) ren[1].SetViewport(.33333, 0, .66667, .25) ren[2].SetViewport(.66667, 0, 1, .25) ren[3].SetViewport(0, .25, .33333, .5) ren[4].SetViewport(.33333, .25, .66667, .5) ren[5].SetViewport(.66667, .25, 1, .5) ren[6].SetViewport(0, .5, .33333, .75) ren[7].SetViewport(.33333, .5, .66667, .75) ren[8].SetViewport(.66667, .5, 1, .75) ren[9].SetViewport(0, .75, .33333, 1) ren[10].SetViewport(.33333, .75, .66667, 1) ren[11].SetViewport(.66667, .75, 1, 1) # render and interact with data iRen = vtk.vtkRenderWindowInteractor() iRen.SetRenderWindow(renWin) renWin.Render() img_file = "TestImageThresholdConnectivity.png" vtk.test.Testing.compareImage( iRen.GetRenderWindow(), vtk.test.Testing.getAbsImagePath(img_file), threshold=25) vtk.test.Testing.interact()
def apply(self, ijkPoints): kernelSizePixel = self.getKernelSizePixel() if kernelSizePixel[0]<=0 and kernelSizePixel[1]<=0 and kernelSizePixel[2]<=0: return qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor) # Get parameter set node parameterSetNode = self.scriptedEffect.parameterSetNode() # Get parameters minimumThreshold = self.scriptedEffect.doubleParameter("MinimumThreshold") maximumThreshold = self.scriptedEffect.doubleParameter("MaximumThreshold") # Get modifier labelmap modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap() # Get master volume image data masterImageData = self.scriptedEffect.masterVolumeImageData() # Set intensity range oldMasterVolumeIntensityMask = parameterSetNode.GetMasterVolumeIntensityMask() parameterSetNode.MasterVolumeIntensityMaskOn() oldIntensityMaskRange = parameterSetNode.GetMasterVolumeIntensityMaskRange() intensityRange = [265.00, 1009.00] if oldMasterVolumeIntensityMask: intensityRange = [max(oldIntensityMaskRange[0], minimumThreshold), min(oldIntensityMaskRange[1], maximumThreshold)] parameterSetNode.SetMasterVolumeIntensityMaskRange(intensityRange) roiNode = lumbarSeed ##self.roiSelector.currentNode() clippedMasterImageData = masterImageData if roiNode is not None: worldToImageMatrix = vtk.vtkMatrix4x4() masterImageData.GetWorldToImageMatrix(worldToImageMatrix) bounds = [0,0,0,0,0,0] roiNode.GetRASBounds(bounds) corner1RAS = [bounds[0], bounds[2], bounds[4], 1] corner1IJK = [0, 0, 0, 0] worldToImageMatrix.MultiplyPoint(corner1RAS, corner1IJK) corner2RAS = [bounds[1], bounds[3], bounds[5], 1] corner2IJK = [0, 0, 0, 0] worldToImageMatrix.MultiplyPoint(corner2RAS, corner2IJK) extent = [0, -1, 0, -1, 0, -1] for i in range(3): lowerPoint = min(corner1IJK[i], corner2IJK[i]) upperPoint = max(corner1IJK[i], corner2IJK[i]) extent[2*i] = int(math.floor(lowerPoint)) extent[2*i+1] = int(math.ceil(upperPoint)) imageToWorldMatrix = vtk.vtkMatrix4x4() masterImageData.GetImageToWorldMatrix(imageToWorldMatrix) clippedMasterImageData = slicer.vtkOrientedImageData() self.padder = vtk.vtkImageConstantPad() self.padder.SetInputData(masterImageData) self.padder.SetOutputWholeExtent(extent) self.padder.Update() clippedMasterImageData.ShallowCopy(self.padder.GetOutput()) clippedMasterImageData.SetImageToWorldMatrix(imageToWorldMatrix) # Pipeline self.thresh = vtk.vtkImageThreshold() self.thresh.SetInValue(LABEL_VALUE) self.thresh.SetOutValue(BACKGROUND_VALUE) self.thresh.SetInputData(clippedMasterImageData) self.thresh.ThresholdBetween(minimumThreshold, maximumThreshold) self.thresh.SetOutputScalarTypeToUnsignedChar() self.thresh.Update() self.erode = vtk.vtkImageDilateErode3D() self.erode.SetInputConnection(self.thresh.GetOutputPort()) self.erode.SetDilateValue(BACKGROUND_VALUE) self.erode.SetErodeValue(LABEL_VALUE) self.erode.SetKernelSize( kernelSizePixel[0], kernelSizePixel[1], kernelSizePixel[2]) self.erodeCast = vtk.vtkImageCast() self.erodeCast.SetInputConnection(self.erode.GetOutputPort()) self.erodeCast.SetOutputScalarTypeToUnsignedInt() self.erodeCast.Update() # Remove small islands self.islandMath = vtkITK.vtkITKIslandMath() self.islandMath.SetInputConnection(self.erodeCast.GetOutputPort()) self.islandMath.SetFullyConnected(False) self.islandMath.SetMinimumSize(125) # remove regions smaller than 5x5x5 voxels self.islandThreshold = vtk.vtkImageThreshold() self.islandThreshold.SetInputConnection(self.islandMath.GetOutputPort()) self.islandThreshold.ThresholdByLower(BACKGROUND_VALUE) self.islandThreshold.SetInValue(BACKGROUND_VALUE) self.islandThreshold.SetOutValue(LABEL_VALUE) self.islandThreshold.SetOutputScalarTypeToUnsignedChar() self.islandThreshold.Update() # Points may be outside the region after it is eroded. # Snap the points to LABEL_VALUE voxels, snappedIJKPoints = self.snapIJKPointsToLabel(ijkPoints, self.islandThreshold.GetOutput()) if snappedIJKPoints.GetNumberOfPoints() == 0: qt.QApplication.restoreOverrideCursor() return # Convert points to real data coordinates. Required for vtkImageThresholdConnectivity. seedPoints = vtk.vtkPoints() origin = masterImageData.GetOrigin() spacing = masterImageData.GetSpacing() for i in range(snappedIJKPoints.GetNumberOfPoints()): ijkPoint = snappedIJKPoints.GetPoint(i) seedPoints.InsertNextPoint( origin[0]+ijkPoint[0]*spacing[0], origin[1]+ijkPoint[1]*spacing[1], origin[2]+ijkPoint[2]*spacing[2]) segmentationAlgorithm = self.scriptedEffect.parameter(SEGMENTATION_ALGORITHM_PARAMETER_NAME) if segmentationAlgorithm == SEGMENTATION_ALGORITHM_MASKING: self.runMasking(seedPoints, self.islandThreshold.GetOutput(), modifierLabelmap) else: self.floodFillingFilterIsland = vtk.vtkImageThresholdConnectivity() self.floodFillingFilterIsland.SetInputConnection(self.islandThreshold.GetOutputPort()) self.floodFillingFilterIsland.SetInValue(SELECTED_ISLAND_VALUE) self.floodFillingFilterIsland.ReplaceInOn() self.floodFillingFilterIsland.ReplaceOutOff() self.floodFillingFilterIsland.ThresholdBetween(265.00, 1009.00) self.floodFillingFilterIsland.SetSeedPoints(seedPoints) self.floodFillingFilterIsland.Update() self.maskCast = vtk.vtkImageCast() self.maskCast.SetInputData(self.thresh.GetOutput()) self.maskCast.SetOutputScalarTypeToUnsignedChar() self.maskCast.Update() self.imageMask = vtk.vtkImageMask() self.imageMask.SetInputConnection(self.floodFillingFilterIsland.GetOutputPort()) self.imageMask.SetMaskedOutputValue(OUTSIDE_THRESHOLD_VALUE) self.imageMask.SetMaskInputData(self.maskCast.GetOutput()) self.imageMask.Update() imageMaskOutput = slicer.vtkOrientedImageData() imageMaskOutput.ShallowCopy(self.imageMask.GetOutput()) imageMaskOutput.CopyDirections(clippedMasterImageData) imageToWorldMatrix = vtk.vtkMatrix4x4() imageMaskOutput.GetImageToWorldMatrix(imageToWorldMatrix) segmentOutputLabelmap = slicer.vtkOrientedImageData() if segmentationAlgorithm == SEGMENTATION_ALGORITHM_GROWCUT: self.runGrowCut(clippedMasterImageData, imageMaskOutput, segmentOutputLabelmap) elif segmentationAlgorithm == SEGMENTATION_ALGORITHM_WATERSHED: self.runWatershed(clippedMasterImageData, imageMaskOutput, segmentOutputLabelmap) else: logging.error("Unknown segmentation algorithm: \"" + segmentationAlgorithm + "\"") segmentOutputLabelmap.SetImageToWorldMatrix(imageToWorldMatrix) self.selectedSegmentThreshold = vtk.vtkImageThreshold() self.selectedSegmentThreshold.SetInputData(segmentOutputLabelmap) self.selectedSegmentThreshold.ThresholdBetween(SELECTED_ISLAND_VALUE, SELECTED_ISLAND_VALUE) self.selectedSegmentThreshold.SetInValue(LABEL_VALUE) self.selectedSegmentThreshold.SetOutValue(BACKGROUND_VALUE) self.selectedSegmentThreshold.SetOutputScalarType(modifierLabelmap.GetScalarType()) self.selectedSegmentThreshold.Update() modifierLabelmap.ShallowCopy(self.selectedSegmentThreshold.GetOutput()) self.scriptedEffect.saveStateForUndo() self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeAdd) parameterSetNode.SetMasterVolumeIntensityMask(oldMasterVolumeIntensityMask) parameterSetNode.SetMasterVolumeIntensityMaskRange(oldIntensityMaskRange) qt.QApplication.restoreOverrideCursor()
def testImageThresholdConnectivity(self): # This script is for testing the 3D flood fill filter. # Image pipeline renWin = vtk.vtkRenderWindow() renWin.SetSize(192, 256) reader = vtk.vtkImageReader() reader.ReleaseDataFlagOff() reader.SetDataByteOrderToLittleEndian() reader.SetDataExtent(0, 63, 0, 63, 2, 5) reader.SetDataSpacing(3.2, 3.2, 1.5) reader.SetFilePrefix(VTK_DATA_ROOT + "/Data/headsq/quarter") reader.SetDataMask(0x7fff) seeds = vtk.vtkPoints() seeds.InsertNextPoint(0, 0, 0) seeds.InsertNextPoint(100.8, 100.8, 0) replacein = ["ReplaceInOn", "ReplaceInOff"] replaceout = ["ReplaceOutOn", "ReplaceOutOff"] thresholds = ["ThresholdByLower(800)", "ThresholdByUpper(1200)", "ThresholdBetween(800, 1200)"] thresh = list() map = list() act = list() ren = list() k = 0 for rin in replacein: for rout in replaceout: for t in thresholds: thresh.append(vtk.vtkImageThresholdConnectivity()) thresh[k].SetSeedPoints(seeds) thresh[k].SetInValue(2000) thresh[k].SetOutValue(0) eval('thresh[k].' + rin + '()') eval('thresh[k].' + rout + '()') thresh[k].SetInputConnection(reader.GetOutputPort()) eval('thresh[k].' + t) map.append(vtk.vtkImageMapper()) map[k].SetInputConnection(thresh[k].GetOutputPort()) if k < 3: map[k].SetColorWindow(255) map[k].SetColorLevel(127.5) else: map[k].SetColorWindow(2000) map[k].SetColorLevel(1000) act.append(vtk.vtkActor2D()) act[k].SetMapper(map[k]) ren.append(vtk.vtkRenderer()) ren[k].AddActor2D(act[k]) renWin.AddRenderer(ren[k]) k += 1 ren[0].SetViewport(0, 0, .33333, .25) ren[1].SetViewport(.33333, 0, .66667, .25) ren[2].SetViewport(.66667, 0, 1, .25) ren[3].SetViewport(0, .25, .33333, .5) ren[4].SetViewport(.33333, .25, .66667, .5) ren[5].SetViewport(.66667, .25, 1, .5) ren[6].SetViewport(0, .5, .33333, .75) ren[7].SetViewport(.33333, .5, .66667, .75) ren[8].SetViewport(.66667, .5, 1, .75) ren[9].SetViewport(0, .75, .33333, 1) ren[10].SetViewport(.33333, .75, .66667, 1) ren[11].SetViewport(.66667, .75, 1, 1) # render and interact with data iRen = vtk.vtkRenderWindowInteractor() iRen.SetRenderWindow(renWin); renWin.Render() img_file = "TestImageThresholdConnectivity.png" vtk.test.Testing.compareImage(iRen.GetRenderWindow(), vtk.test.Testing.getAbsImagePath(img_file), threshold=25) vtk.test.Testing.interact()
def floodFillFromPoint(self, ijk): """Fills the segment taking based on the current master volume. Input IJK position is voxel coordinates of master volume. """ self.scriptedEffect.saveStateForUndo() # Get master volume image data import vtkSegmentationCorePython as vtkSegmentationCore masterImageData = self.getClippedMasterImageData() selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap() # Get modifier labelmap modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap() pixelValue = masterImageData.GetScalarComponentAsFloat( ijk[0], ijk[1], ijk[2], 0) useSegmentationAsStencil = False # Perform thresholding floodFillingFilter = vtk.vtkImageThresholdConnectivity() floodFillingFilter.SetInputData(masterImageData) seedPoints = vtk.vtkPoints() origin = masterImageData.GetOrigin() spacing = masterImageData.GetSpacing() seedPoints.InsertNextPoint(origin[0] + ijk[0] * spacing[0], origin[1] + ijk[1] * spacing[1], origin[2] + ijk[2] * spacing[2]) floodFillingFilter.SetSeedPoints(seedPoints) maskImageData = vtkSegmentationCore.vtkOrientedImageData() intensityBasedMasking = self.scriptedEffect.parameterSetNode( ).GetMasterVolumeIntensityMask() segmentationNode = self.scriptedEffect.parameterSetNode( ).GetSegmentationNode() success = segmentationNode.GenerateEditMask( maskImageData, self.scriptedEffect.parameterSetNode().GetMaskMode(), masterImageData, # reference geometry self.scriptedEffect.parameterSetNode().GetSelectedSegmentID(), self.scriptedEffect.parameterSetNode().GetMaskSegmentID() if self.scriptedEffect.parameterSetNode().GetMaskSegmentID() else "", masterImageData if intensityBasedMasking else None, self.scriptedEffect.parameterSetNode( ).GetMasterVolumeIntensityMaskRange() if intensityBasedMasking else None) if success: stencil = vtk.vtkImageToImageStencil() stencil.SetInputData(maskImageData) stencil.ThresholdByLower(0) stencil.Update() floodFillingFilter.SetStencilData(stencil.GetOutput()) else: logging.error("Failed to create edit mask") neighborhoodSizeMm = self.neighborhoodSizeMmSlider.value floodFillingFilter.SetNeighborhoodRadius(neighborhoodSizeMm, neighborhoodSizeMm, neighborhoodSizeMm) floodFillingFilter.SetNeighborhoodFraction(0.5) if useSegmentationAsStencil: stencilFilter = vtk.vtkImageToImageStencil() stencilFilter.SetInputData(selectedSegmentLabelmap) stencilFilter.ThresholdByLower(0) stencilFilter.Update() floodFillingFilter.SetStencilData(stencilFilter.GetOutput()) pixelValueTolerance = float(self.intensityToleranceSlider.value) floodFillingFilter.ThresholdBetween(pixelValue - pixelValueTolerance, pixelValue + pixelValueTolerance) floodFillingFilter.SetInValue(1) floodFillingFilter.SetOutValue(0) floodFillingFilter.Update() modifierLabelmap.DeepCopy(floodFillingFilter.GetOutput()) # Apply changes self.scriptedEffect.modifySelectedSegmentByLabelmap( modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeAdd)