def createGlyph(self): self.polyData = vtk.vtkPolyData() points = vtk.vtkPoints() lines = vtk.vtkCellArray() self.polyData.SetPoints( points ) self.polyData.SetLines( lines ) prevPoint = None firstPoint = None for x,y in ((0,0),)*4: p = points.InsertNextPoint( x, y, 0 ) if prevPoint != None: idList = vtk.vtkIdList() idList.InsertNextId( prevPoint ) idList.InsertNextId( p ) self.polyData.InsertNextCell( vtk.VTK_LINE, idList ) prevPoint = p if firstPoint == None: firstPoint = p # make the last line in the polydata idList = vtk.vtkIdList() idList.InsertNextId( p ) idList.InsertNextId( firstPoint ) self.polyData.InsertNextCell( vtk.VTK_LINE, idList )
def createGlyph(self, polyData): """ create a brush circle of the right radius in XY space - assume uniform scaling between XY and RAS which is enforced by the view interactors """ sliceNode = self.sliceWidget.sliceLogic().GetSliceNode() self.rasToXY.DeepCopy(sliceNode.GetXYToRAS()) self.rasToXY.Invert() maximum, maxIndex = 0,0 for index in range(3): if abs(self.rasToXY.GetElement(0, index)) > maximum: maximum = abs(self.rasToXY.GetElement(0, index)) maxIndex = index point = [0, 0, 0, 0] point[maxIndex] = self.radius xyRadius = self.rasToXY.MultiplyPoint(point) import math xyRadius = math.sqrt( xyRadius[0]**2 + xyRadius[1]**2 + xyRadius[2]**2 ) if self.pixelMode: xyRadius = 0.01 # make a circle paint brush points = vtk.vtkPoints() lines = vtk.vtkCellArray() polyData.SetPoints(points) polyData.SetLines(lines) PI = 3.1415926 TWOPI = PI * 2 PIoverSIXTEEN = PI / 16 prevPoint = -1 firstPoint = -1 angle = 0 while angle <= TWOPI: x = xyRadius * math.cos(angle) y = xyRadius * math.sin(angle) p = points.InsertNextPoint( x, y, 0 ) if prevPoint != -1: idList = vtk.vtkIdList() idList.InsertNextId(prevPoint) idList.InsertNextId(p) polyData.InsertNextCell( vtk.VTK_LINE, idList ) prevPoint = p if firstPoint == -1: firstPoint = p angle = angle + PIoverSIXTEEN # make the last line in the circle idList = vtk.vtkIdList() idList.InsertNextId(p) idList.InsertNextId(firstPoint) polyData.InsertNextCell( vtk.VTK_LINE, idList )
def createGlyph(self, polyData): """ create a brush circle of the right radius in XY space - assume uniform scaling between XY and RAS which is enforced by the view interactors """ sliceNode = self.sliceWidget.sliceLogic().GetSliceNode() self.rasToXY.DeepCopy(sliceNode.GetXYToRAS()) self.rasToXY.Invert() maximum, maxIndex = 0, 0 for index in range(3): if abs(self.rasToXY.GetElement(0, index)) > maximum: maximum = abs(self.rasToXY.GetElement(0, index)) maxIndex = index point = [0, 0, 0, 0] point[maxIndex] = self.radius xyRadius = self.rasToXY.MultiplyPoint(point) import math xyRadius = math.sqrt(xyRadius[0]**2 + xyRadius[1]**2 + xyRadius[2]**2) if self.pixelMode: xyRadius = 0.01 # make a circle paint brush points = vtk.vtkPoints() lines = vtk.vtkCellArray() polyData.SetPoints(points) polyData.SetLines(lines) PI = 3.1415926 TWOPI = PI * 2 PIoverSIXTEEN = PI / 16 prevPoint = -1 firstPoint = -1 angle = 0 while angle <= TWOPI: x = xyRadius * math.cos(angle) y = xyRadius * math.sin(angle) p = points.InsertNextPoint(x, y, 0) if prevPoint != -1: idList = vtk.vtkIdList() idList.InsertNextId(prevPoint) idList.InsertNextId(p) polyData.InsertNextCell(vtk.VTK_LINE, idList) prevPoint = p if firstPoint == -1: firstPoint = p angle = angle + PIoverSIXTEEN # make the last line in the circle idList = vtk.vtkIdList() idList.InsertNextId(p) idList.InsertNextId(firstPoint) polyData.InsertNextCell(vtk.VTK_LINE, idList)
def calculateLineLength(self, poly): lines = poly.GetLines() points = poly.GetPoints() pts = vtk.vtkIdList() lines.GetCell(0, pts) ip = numpy.array(points.GetPoint(pts.GetId(0))) n = pts.GetNumberOfIds() # Check if there is overlap between the first and last segments # (for making sure to close the loop for spline curves) if n > 2: slp = numpy.array(points.GetPoint(pts.GetId(n - 2))) # Check distance between the first point and the second last point if numpy.linalg.norm(slp - ip) < 0.00001: n = n - 1 length = 0.0 pp = ip for i in range(1, n): p = numpy.array(points.GetPoint(pts.GetId(i))) length = length + numpy.linalg.norm(pp - p) pp = p return length
def getCurveLength(self, numberOfCurvePoints=-1, startPointIndex=0): """Get length of the curve or a section of the curve :param n: if specified then distances up to the first n points are computed :return: sum of distances between the curve points """ pointIds = vtk.vtkIdList() self.curvePoly.GetLines().GetCell(0, pointIds) points = self.curvePoly.GetPoints() # Check if there is overlap between the first and last segments # if there is, then ignore the last segment (only needed for smooth spline # interpolation) totalNumberOfCurvePoints = pointIds.GetNumberOfIds() if totalNumberOfCurvePoints > 2: firstPoint = np.array(points.GetPoint(pointIds.GetId(0))) lastPoint = np.array( points.GetPoint(pointIds.GetId(totalNumberOfCurvePoints - 2))) # Check distance between the first point and the second last point if np.linalg.norm(lastPoint - firstPoint) < 0.00001: totalNumberOfCurvePoints -= 1 if numberOfCurvePoints < 0 or startPointIndex + numberOfCurvePoints > totalNumberOfCurvePoints: numberOfCurvePoints = totalNumberOfCurvePoints - startPointIndex length = 0.0 previousPoint = np.array( points.GetPoint(pointIds.GetId(startPointIndex))) for i in range(startPointIndex + 1, startPointIndex + numberOfCurvePoints): nextPoint = np.array(points.GetPoint(pointIds.GetId(i))) length += np.linalg.norm(previousPoint - nextPoint) previousPoint = nextPoint return length
def convertFiducialHierarchyToVtkIdList(hierarchyNode,volumeNode): ''' ''' outputIds = vtk.vtkIdList() if not hierarchyNode or not volumeNode: return outputIds if isinstance(hierarchyNode,slicer.vtkMRMLAnnotationHierarchyNode) and isinstance(volumeNode,slicer.vtkMRMLScalarVolumeNode): childrenNodes = vtk.vtkCollection() image = volumeNode.GetImageData() hierarchyNode.GetChildrenDisplayableNodes(childrenNodes) # now we have the children which are fiducialNodes - let's loop! for n in range(childrenNodes.GetNumberOfItems()): currentFiducial = childrenNodes.GetItemAsObject(n) currentCoordinatesRAS = [0,0,0] # grab the current coordinates currentFiducial.GetFiducialCoordinates(currentCoordinatesRAS) # convert the RAS to IJK currentCoordinatesIJK = Helper.ConvertRAStoIJK(volumeNode,currentCoordinatesRAS) # strip the last element since we need a 3based tupel currentCoordinatesIJKlist = (int(currentCoordinatesIJK[0]),int(currentCoordinatesIJK[1]),int(currentCoordinatesIJK[2])) outputIds.InsertNextId(int(image.ComputePointId(currentCoordinatesIJKlist))) # IdList was created, return it even if it might be empty return outputIds
def testDefineNeighborsFunction(self): sphereModel = self.defineSphere() polyData = sphereModel.GetPolyData() closestPointIndexList = [9, 35, 1] connectedVerticesReferenceList = list() connectedVerticesReferenceList.append([9, 2, 3, 8, 10, 15, 16]) connectedVerticesReferenceList.append( [35, 28, 29, 34, 36, 41, 42, 21, 22, 27, 23, 30, 33, 40, 37, 43, 47, 48, 49]) connectedVerticesReferenceList.append( [1, 7, 13, 19, 25, 31, 37, 43, 49, 6, 48, 12, 18, 24, 30, 36, 42, 5, 47, 41, 11, 17, 23, 29, 35]) connectedVerticesTestedList = list() for i in range(0, 3): inter = vtk.vtkIdList() self.ShapeQuantifierCore.defineNeighbor(inter, polyData, closestPointIndexList[i], i + 1) connectedVerticesTestedList.append(inter) list1 = list() for j in range(0, connectedVerticesTestedList[i].GetNumberOfIds()): list1.append(int(connectedVerticesTestedList[i].GetId(j))) connectedVerticesTestedList[i] = list1 if connectedVerticesTestedList[i] != connectedVerticesReferenceList[i]: print "test ",i ," AddArrayFromIdList: failed" return False else: print "test ",i ," AddArrayFromIdList: succeed" return True
def addPointToPolyData(self, polyData, ras): pid = vtk.vtkIdList() pid.SetNumberOfIds(1); temp = polyData.GetPoints().InsertNextPoint(ras[0], ras[1], ras[2]) pid.SetId(0, temp) polyData.GetVerts().InsertNextCell(pid) polyData.Modified()
def onCalculateLength(self): self.inputPolyData = self.vtkNode.GetPolyData() points = self.inputPolyData.GetPoints() lines = self.inputPolyData.GetLines() lines.InitTraversal() i = 0 for i in range(self.inputPolyData.GetNumberOfCells()): fiberLength = 0 ids = vtk.vtkIdList() lines.GetNextCell(ids) for j in range(ids.GetNumberOfIds()-1): point1 = [0,0,0] point2 = [0,0,0] points.GetPoint(ids.GetId(j), point1) points.GetPoint(ids.GetId(j+1), point2) x = point2[0] - point1[0] y = point2[1] - point1[1] z = point2[2] - point1[2] step = (x*x + y*y + z*z)**.5 fiberLength += step self.distanceTable.append(fiberLength) i += 1 min,max=self.getDistanceBound() self.thresholdMin.setValue(min) self.thresholdMin.enabled = True self.thresholdMax.setValue(max+1) self.thresholdMax.enabled = True self.applyThresholdButton.enabled = True
def convertFiducialHierarchyToVtkIdList(hierarchyNode,volumeNode): ''' ''' outputIds = vtk.vtkIdList() if not hierarchyNode or not volumeNode: return outputIds if isinstance(hierarchyNode,slicer.vtkMRMLMarkupsFiducialNode) and isinstance(volumeNode,slicer.vtkMRMLScalarVolumeNode): image = volumeNode.GetImageData() # now we have the children which are fiducialNodes - let's loop! for n in range(hierarchyNode.GetNumberOfFiducials()): currentCoordinatesRAS = [0,0,0] # grab the current coordinates hierarchyNode.GetNthFiducialPosition(n,currentCoordinatesRAS) # convert the RAS to IJK currentCoordinatesIJK = Helper.ConvertRAStoIJK(volumeNode,currentCoordinatesRAS) # strip the last element since we need a 3based tupel currentCoordinatesIJKlist = (int(currentCoordinatesIJK[0]),int(currentCoordinatesIJK[1]),int(currentCoordinatesIJK[2])) outputIds.InsertNextId(int(image.ComputePointId(currentCoordinatesIJKlist))) # IdList was created, return it even if it might be empty return outputIds
def calculateLineLength(self, poly): lines = poly.GetLines() points = poly.GetPoints() pts = vtk.vtkIdList() lines.GetCell(0, pts) ip = numpy.array(points.GetPoint(pts.GetId(0))) n = pts.GetNumberOfIds() # Check if there is overlap between the first and last segments # (for making sure to close the loop for spline curves) if n > 2: slp = numpy.array(points.GetPoint(pts.GetId(n-2))) # Check distance between the first point and the second last point if numpy.linalg.norm(slp-ip) < 0.00001: n = n - 1 length = 0.0 pp = ip for i in range(1,n): p = numpy.array(points.GetPoint(pts.GetId(i))) length = length + numpy.linalg.norm(pp-p) pp = p return length
def testAddArrayFromIdListFunction(self): sphereModel = self.defineSphere() polyData = sphereModel.GetPolyData() closestPointIndexList = [9, 35, 1] for i in range(0, 3): inter = vtk.vtkIdList() self.ShapeQuantifierCore.defineNeighbor(inter, polyData, closestPointIndexList[i], i + 1) self.ShapeQuantifierCore.addArrayFromIdList(inter, sphereModel, 'Test_' + str(i + 1)) if polyData.GetPointData().HasArray('Test_' + str(i + 1)) != 1: print "test ",i ," AddArrayFromIdList: failed" return False else: print "test ",i ," AddArrayFromIdList: succeed" return True
def addPointToPolyData(self, polyData, ras): pid = vtk.vtkIdList() pid.SetNumberOfIds(1); temp = polyData.GetPoints().InsertNextPoint(ras[0], ras[1], ras[2]) pid.SetId(0, temp) polyData.GetVerts().InsertNextCell(pid) if self.direction > -1: color = [0, 0, 0, 0] tableValue = 1 + (ras[self.direction] - self.min) * self.normalizingConstant if tableValue > 255: tableValue = 255 elif tableValue < 0: tableValue = 0 self.colorTable.GetColor(int(tableValue), color) # 0 -> 255 self.recordedModelNode.GetPolyData().GetPointData().GetScalars('Colors').InsertTuple(self.recordedModelNode.GetPolyData().GetPoints().GetNumberOfPoints() - 1, color) if self.addColours: self.showColouring() self.addColours = False polyData.Modified()
def PointsToPolyData(self, listOfPoints): """ Converts 3D list of points of an array into a polyData line The connections between this line are simply the order in which they are provided """ points = vtk.vtkPoints() idlist = vtk.vtkIdList() numOfPoints = len(listOfPoints) if numOfPoints == 0: print("WARNING:No points to convert to polyData") return vtk.vtkPolyData() #returning Blank PolyData points.SetNumberOfPoints(numOfPoints) for i in range(numOfPoints): points.InsertPoint(i, listOfPoints[i]) #Add the points idlist.InsertNextId(i) polyData = vtk.vtkPolyData() polyData.Allocate() polyData.InsertNextCell(vtk.VTK_LINE, idlist) polyData.SetPoints(points) return polyData
def PointsToPolyData(self,listOfPoints): """ Converts 3D list of points of an array into a polyData line The connections between this line are simply the order in which they are provided """ points=vtk.vtkPoints() idlist = vtk.vtkIdList() numOfPoints=len(listOfPoints) if numOfPoints==0: print ("WARNING:No points to convert to polyData") return vtk.vtkPolyData() #returning Blank PolyData points.SetNumberOfPoints(numOfPoints) for i in range (numOfPoints): points.InsertPoint(i, listOfPoints[i]) #Add the points idlist.InsertNextId(i) polyData=vtk.vtkPolyData() polyData.Allocate() polyData.InsertNextCell(vtk.VTK_LINE,idlist) polyData.SetPoints(points) return polyData
def addPointToPolyData(self, polyData, ras): print "nuevo punto!!!" self.pointCounter = self.pointCounter + 1; pid = vtk.vtkIdList() pid.SetNumberOfIds(1); temp = polyData.GetPoints().InsertNextPoint(ras[0], ras[1], ras[2]) pid.SetId(0, temp) polyData.GetVerts().InsertNextCell(pid) polyData.Modified() # check every 30 recorded points if the standard deviation is low if (self.pointCounter%30) == 0: sd = self.testStandardDeviation(polyData) if sd < 1: self.record = False if self.pointCounter>100: self.calculateSurface(self.recordedModelNode) print "El standard deviation es bajo ya no se mueve"
def copyNodeContentToNewScriptedModuleNode(oldDataNode, shNode): newDataNode = slicer.vtkMRMLScriptedModuleNode() newDataNode.HideFromEditorsOff() # Copy node attributes attributeNames = vtk.vtkStringArray() oldDataNode.GetAttributeNames(attributeNames) for index in range(attributeNames.GetNumberOfValues()): attributeName = attributeNames.GetValue(index) newDataNode.SetAttribute(attributeName, oldDataNode.GetAttribute(attributeName)) slicer.mrmlScene.AddNode(newDataNode) newDataNode.SetName(oldDataNode.GetName()) # Copy node references newDataNode.CopyReferences(oldDataNode) # Move children childItemIDs = vtk.vtkIdList() #shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene) shNode.GetItemChildren(shNode.GetItemByDataNode(oldDataNode), childItemIDs) for index in range(childItemIDs.GetNumberOfIds()): childItemID = childItemIDs.GetId(index) shNode.ReparentItemByDataNode(childItemID, newDataNode) return newDataNode
def convertFiducialHierarchyToVtkIdList(hierarchyNode, volumeNode): ''' ''' outputIds = vtk.vtkIdList() if not hierarchyNode or not volumeNode: return outputIds if isinstance(hierarchyNode, slicer.vtkMRMLAnnotationHierarchyNode) and isinstance( volumeNode, slicer.vtkMRMLScalarVolumeNode): childrenNodes = vtk.vtkCollection() image = volumeNode.GetImageData() hierarchyNode.GetChildrenDisplayableNodes(childrenNodes) # now we have the children which are fiducialNodes - let's loop! for n in range(childrenNodes.GetNumberOfItems()): currentFiducial = childrenNodes.GetItemAsObject(n) currentCoordinatesRAS = [0, 0, 0] # grab the current coordinates currentFiducial.GetFiducialCoordinates(currentCoordinatesRAS) # convert the RAS to IJK currentCoordinatesIJK = Helper.ConvertRAStoIJK( volumeNode, currentCoordinatesRAS) # strip the last element since we need a 3based tupel currentCoordinatesIJKlist = (int(currentCoordinatesIJK[0]), int(currentCoordinatesIJK[1]), int(currentCoordinatesIJK[2])) outputIds.InsertNextId( int(image.ComputePointId(currentCoordinatesIJKlist))) # IdList was created, return it even if it might be empty return outputIds
def calcApproachScore(self, point, skinPolyData, obstacleBspTree, skinModelNode=None): pTarget = point polyData = skinPolyData nPoints = polyData.GetNumberOfPoints() nCells = polyData.GetNumberOfCells() pSurface = [0.0, 0.0, 0.0] minDistancePoint = [0.0, 0.0, 0.0] tolerance = 0.001 t = vtk.mutable(0.0) x = [0.0, 0.0, 0.0] pcoords = [0.0, 0.0, 0.0] subId = vtk.mutable(0) #print ("nPoints = %d" % (nPoints)) #print ("nCells = %d" % (nCells)) # Map surface model if skinModelNode != None: pointValue = vtk.vtkDoubleArray() pointValue.SetName("Colors") pointValue.SetNumberOfComponents(1) pointValue.SetNumberOfTuples(nPoints) pointValue.Reset() pointValue.FillComponent(0, 0.0) bspTree = obstacleBspTree cp0 = [0.0, 0.0, 0.0] cp1 = [0.0, 0.0, 0.0] cp2 = [0.0, 0.0, 0.0] accessibleArea = 0.0 inaccessibleArea = 0.0 ids = vtk.vtkIdList() minDistance = -1 for index in range(nCells): cell = polyData.GetCell(index) if cell.GetCellType() == vtk.VTK_TRIANGLE: area = cell.ComputeArea() polyData.GetCellPoints(index, ids) polyData.GetPoint(ids.GetId(0), cp0) polyData.GetPoint(ids.GetId(1), cp1) polyData.GetPoint(ids.GetId(2), cp2) vtk.vtkTriangle.TriangleCenter(cp0, cp1, cp2, pSurface) iD = bspTree.IntersectWithLine(pSurface, pTarget, tolerance, t, x, pcoords, subId) if iD < 1: if skinModelNode != None: d = vtk.vtkMath.Distance2BetweenPoints( pSurface, pTarget) d = math.sqrt(d) if d < minDistance or minDistance < 0: minDistance = d minDistancePoint = [ pSurface[0], pSurface[1], pSurface[2] ] v = d + 101 pointValue.InsertValue(ids.GetId(0), v) pointValue.InsertValue(ids.GetId(1), v) pointValue.InsertValue(ids.GetId(2), v) accessibleArea = accessibleArea + area else: if skinModelNode != None: v = -1.0 pointValue.InsertValue(ids.GetId(0), v) pointValue.InsertValue(ids.GetId(1), v) pointValue.InsertValue(ids.GetId(2), v) inaccessibleArea = inaccessibleArea + area else: print("ERROR: Non-triangular cell.") score = accessibleArea / (accessibleArea + inaccessibleArea) if skinModelNode != None: skinModelNode.AddPointScalars(pointValue) skinModelNode.SetActivePointScalars( "Colors", vtk.vtkDataSetAttributes.SCALARS) skinModelNode.Modified() displayNode = skinModelNode.GetModelDisplayNode() displayNode.SetActiveScalarName("Colors") displayNode.SetScalarRange(0.0, 200.0) return (score, minDistance, minDistancePoint)
def distanceToPoint(self, point, extrapolate): # distanceToPoint() calculates the approximate minimum distance between # the specified point and the closest segment of the curve. # It calculates the minimum distance between the point and each segment # of the curve (approxmated as a straight line) and select the segment with # the minimum distance from the point as a closest segment. npoint = numpy.array(point) if self.CurvePoly == None: return numpy.Inf lines = self.CurvePoly.GetLines() points = self.CurvePoly.GetPoints() pts = vtk.vtkIdList() lines.GetCell(0, pts) ip = numpy.array(points.GetPoint(pts.GetId(0))) n = pts.GetNumberOfIds() # First point on the segment p1 = ip minMag2 = numpy.Inf minIndex = -1 minErrVec = numpy.array([0.0, 0.0, 0.0]) errVec = numpy.array([0.0, 0.0, 0.0]) for i in range(1, n): # Second point on the segment p2 = numpy.array(points.GetPoint(pts.GetId(i))) # Normal vector along the segment nvec = p2 - p1 norm = numpy.linalg.norm(nvec) if norm != 0: nnvec = nvec / norm # Calculate the distance between the point and the segment mag2 = 0.0 op = npoint - p1 aproj = numpy.inner(op, nnvec) if extrapolate and ((i == 1 and aproj < 0.0) or (i == n - 1 and aproj > 0.0)): # extrapolate first or last segment errVec = op - aproj * nnvec # perpendicular mag2 = numpy.inner(errVec, errVec) # magnitude^2 else: if aproj < 0.0: errVec = npoint - p1 mag2 = numpy.inner(errVec, errVec) # magnitude^2 elif aproj > norm: errVec = npoint - p2 mag2 = numpy.inner(errVec, errVec) # magnitude^2 else: errVec = op - aproj * nnvec # perpendicular mag2 = numpy.inner(errVec, errVec) # magnitude^2 if mag2 < minMag2: minMag2 = mag2 minIndex = i minErrVec = errVec p1 = p2 distance = numpy.sqrt(minMag2) return (distance, minErrVec)
def computeCurvatures(self, poly, curvatureValues): # Calculate point-by-point curvature of the curve # Returns mean/min/max curvature lines = poly.GetLines() points = poly.GetPoints() pts = vtk.vtkIdList() lines.GetCell(0, pts) ip = numpy.array(points.GetPoint(pts.GetId(0))) n = pts.GetNumberOfIds() ## Check if there is overlap between the first and last segments ## (for making sure to close the loop for spline curves) #if n > 2: # slp = numpy.array(points.GetPoint(pts.GetId(n-2))) # # Check distance between the first point and the second last point # if numpy.linalg.norm(slp-ip) < 0.00001: # n = n - 1 curvatureValues.Initialize() curvatureValues.SetName("Curvature") curvatureValues.SetNumberOfComponents(1) curvatureValues.SetNumberOfTuples(n) curvatureValues.Reset() curvatureValues.FillComponent(0, 0.0) minKappa = 0.0 maxKappa = 0.0 meanKappa = 0.0 # NOTE: mean is weighted by the lengh of each segment pp = numpy.array(points.GetPoint(pts.GetId(0))) p = numpy.array(points.GetPoint(pts.GetId(1))) ds = numpy.linalg.norm(p - pp) pT = (p - pp) / ds pp = p pm = (p + pp) / 2.0 length = 0.0 + numpy.linalg.norm(pm - pp) curvatureValues.InsertValue( pts.GetId(0), 0.0) # The curvature for the first cell is 0.0 for i in range(1, n - 1): p = numpy.array(points.GetPoint(pts.GetId(i + 1))) ds = numpy.linalg.norm(p - pp) T = (p - pp) / ds kappa = numpy.linalg.norm(T - pT) / ds # Curvature curvatureValues.InsertValue( pts.GetId(i), kappa) # The curvature for the first cell is 0.0 m = (p + pp) / 2.0 l = numpy.linalg.norm(m - pm) # length for this segment if kappa < minKappa: minKappa = kappa elif kappa > maxKappa: maxKappa = kappa meanKappa = meanKappa + kappa * l # weighted mean length = length + l pp = p pm = m pT = T curvatureValues.InsertValue( pts.GetId(n - 1), 0.0) # The curvature for the last cell is 0.0 length = length + numpy.linalg.norm(pp - pm) meanKappa = meanKappa / length # TODO: This routin does not consider a closed loop. If a closed loop is specified, # It needs to calculate the curveture of two ends differently. return (meanKappa, minKappa, maxKappa)
def clipSurfaceAtEndPoints( self, networkPolyData, surfacePolyData ): ''' Clips the surfacePolyData on the endpoints identified using the networkPolyData. Returns a tupel of the form [clippedPolyData, endpointsPoints] ''' # import the vmtk libraries try: import vtkvmtkComputationalGeometryPython as vtkvmtkComputationalGeometry import vtkvmtkMiscPython as vtkvmtkMisc except ImportError: logging.error("Unable to import the SlicerVmtk libraries") cleaner = vtk.vtkCleanPolyData() cleaner.SetInputData( networkPolyData ) cleaner.Update() network = cleaner.GetOutput() network.BuildCells() network.BuildLinks( 0 ) endpointIds = vtk.vtkIdList() radiusArray = network.GetPointData().GetArray( 'Radius' ) endpoints = vtk.vtkPolyData() endpointsPoints = vtk.vtkPoints() endpointsRadius = vtk.vtkDoubleArray() endpointsRadius.SetName( 'Radius' ) endpoints.SetPoints( endpointsPoints ) endpoints.GetPointData().AddArray( endpointsRadius ) radiusFactor = 1.2 minRadius = 0.01 for i in range( network.GetNumberOfCells() ): numberOfCellPoints = network.GetCell( i ).GetNumberOfPoints() pointId0 = network.GetCell( i ).GetPointId( 0 ) pointId1 = network.GetCell( i ).GetPointId( numberOfCellPoints - 1 ) pointCells = vtk.vtkIdList() network.GetPointCells( pointId0, pointCells ) numberOfEndpoints = endpointIds.GetNumberOfIds() if pointCells.GetNumberOfIds() == 1: pointId = endpointIds.InsertUniqueId( pointId0 ) if pointId == numberOfEndpoints: point = network.GetPoint( pointId0 ) radius = radiusArray.GetValue( pointId0 ) radius = max( radius, minRadius ) endpointsPoints.InsertNextPoint( point ) endpointsRadius.InsertNextValue( radiusFactor * radius ) pointCells = vtk.vtkIdList() network.GetPointCells( pointId1, pointCells ) numberOfEndpoints = endpointIds.GetNumberOfIds() if pointCells.GetNumberOfIds() == 1: pointId = endpointIds.InsertUniqueId( pointId1 ) if pointId == numberOfEndpoints: point = network.GetPoint( pointId1 ) radius = radiusArray.GetValue( pointId1 ) radius = max( radius, minRadius ) endpointsPoints.InsertNextPoint( point ) endpointsRadius.InsertNextValue( radiusFactor * radius ) polyBall = vtkvmtkComputationalGeometry.vtkvmtkPolyBall() #polyBall.SetInputData( endpoints ) polyBall.SetInput( endpoints ) polyBall.SetPolyBallRadiusArrayName( 'Radius' ) clipper = vtk.vtkClipPolyData() clipper.SetInputData( surfacePolyData ) clipper.SetClipFunction( polyBall ) clipper.Update() connectivityFilter = vtk.vtkPolyDataConnectivityFilter() connectivityFilter.SetInputData( clipper.GetOutput() ) connectivityFilter.ColorRegionsOff() connectivityFilter.SetExtractionModeToLargestRegion() connectivityFilter.Update() clippedSurface = connectivityFilter.GetOutput() outPolyData = vtk.vtkPolyData() outPolyData.DeepCopy( clippedSurface ) return [outPolyData, endpointsPoints]
def start(self, preview=False): ''' ''' SlicerVmtkCommonLib.Helper.Debug("Starting Level Set Segmentation..") # first we need the nodes currentVolumeNode = self.__inputVolumeNodeSelector.currentNode() currentSeedsNode = self.__seedFiducialsNodeSelector.currentNode() currentVesselnessNode = self.__vesselnessVolumeNodeSelector.currentNode( ) currentStoppersNode = self.__stopperFiducialsNodeSelector.currentNode() currentLabelMapNode = self.__outputVolumeNodeSelector.currentNode() currentModelNode = self.__outputModelNodeSelector.currentNode() if not currentVolumeNode: # we need a input volume node return 0 if not currentSeedsNode: # we need a seeds node return 0 if not currentStoppersNode or currentStoppersNode.GetID( ) == currentSeedsNode.GetID(): # we need a current stopper node # self.__stopperFiducialsNodeSelector.addNode() pass if not currentLabelMapNode or currentLabelMapNode.GetID( ) == currentVolumeNode.GetID(): # we need a current labelMap node newLabelMapDisplayNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLLabelMapVolumeDisplayNode") newLabelMapDisplayNode.SetScene(slicer.mrmlScene) newLabelMapDisplayNode.SetDefaultColorMap() slicer.mrmlScene.AddNode(newLabelMapDisplayNode) newLabelMapNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLScalarVolumeNode") newLabelMapNode.CopyOrientation(currentVolumeNode) newLabelMapNode.SetScene(slicer.mrmlScene) newLabelMapNode.SetName( slicer.mrmlScene.GetUniqueNameByString( self.__outputVolumeNodeSelector.baseName)) newLabelMapNode.LabelMapOn() newLabelMapNode.SetAndObserveDisplayNodeID( newLabelMapDisplayNode.GetID()) slicer.mrmlScene.AddNode(newLabelMapNode) currentLabelMapNode = newLabelMapNode self.__outputVolumeNodeSelector.setCurrentNode(currentLabelMapNode) if not currentModelNode: # we need a current model node, the display node is created later newModelNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelNode") newModelNode.SetScene(slicer.mrmlScene) newModelNode.SetName( slicer.mrmlScene.GetUniqueNameByString( self.__outputModelNodeSelector.baseName)) slicer.mrmlScene.AddNode(newModelNode) currentModelNode = newModelNode self.__outputModelNodeSelector.setCurrentNode(currentModelNode) # now we need to convert the fiducials to vtkIdLists seeds = SlicerVmtkCommonLib.Helper.convertFiducialHierarchyToVtkIdList( currentSeedsNode, currentVolumeNode) # stoppers = SlicerVmtkCommonLib.Helper.convertFiducialHierarchyToVtkIdList(currentStoppersNode, currentVolumeNode) stoppers = vtk.vtkIdList() # TODO # the input image for the initialization inputImage = vtk.vtkImageData() # check if we have a vesselnessNode - this will be our input for the initialization then if currentVesselnessNode: # yes, there is one inputImage.DeepCopy(currentVesselnessNode.GetImageData()) else: # no, there is none - we use the original image inputImage.DeepCopy(currentVolumeNode.GetImageData()) inputImage.Update() # initialization initImageData = vtk.vtkImageData() # evolution evolImageData = vtk.vtkImageData() # perform the initialization initImageData.DeepCopy(self.GetLogic().performInitialization( inputImage, self.__thresholdSlider.minimumValue, self.__thresholdSlider.maximumValue, seeds, stoppers, 0)) # TODO sidebranch ignore feature initImageData.Update() if not initImageData.GetPointData().GetScalars(): # something went wrong, the image is empty SlicerVmtkCommonLib.Helper.Info( "Segmentation failed - the output was empty..") return -1 # check if it is a preview call if preview: # if this is a preview call, we want to skip the evolution evolImageData.DeepCopy(initImageData) else: # no preview, run the whole thing! we never use the vesselness node here, just the original one evolImageData.DeepCopy(self.GetLogic().performEvolution( currentVolumeNode.GetImageData(), initImageData, self.__iterationSpinBox.value, self.__inflationSlider.value, self.__curvatureSlider.value, self.__attractionSlider.value, 'geodesic')) evolImageData.Update() # create segmentation labelMap labelMap = vtk.vtkImageData() labelMap.DeepCopy(self.GetLogic().buildSimpleLabelMap( evolImageData, 0, 5)) labelMap.Update() currentLabelMapNode.CopyOrientation(currentVolumeNode) # propagate the label map to the node currentLabelMapNode.SetAndObserveImageData(labelMap) currentLabelMapNode.Modified() # deactivate the threshold in the GUI self.resetThresholdOnDisplayNode() # self.onInputVolumeChanged() # show the segmentation results in the GUI selectionNode = slicer.app.applicationLogic().GetSelectionNode() if preview and currentVesselnessNode: # if preview and a vesselnessNode was configured, show it selectionNode.SetReferenceActiveVolumeID( currentVesselnessNode.GetID()) else: # if not preview, show the original volume if currentVesselnessNode: selectionNode.SetReferenceSecondaryVolumeID( currentVesselnessNode.GetID()) selectionNode.SetReferenceActiveVolumeID(currentVolumeNode.GetID()) selectionNode.SetReferenceActiveLabelVolumeID( currentLabelMapNode.GetID()) slicer.app.applicationLogic().PropagateVolumeSelection() # generate 3D model model = vtk.vtkPolyData() # we need the ijkToRas transform for the marching cubes call ijkToRasMatrix = vtk.vtkMatrix4x4() currentLabelMapNode.GetIJKToRASMatrix(ijkToRasMatrix) # call marching cubes model.DeepCopy(self.GetLogic().marchingCubes(evolImageData, ijkToRasMatrix, 0.0)) model.Update() # propagate model to nodes currentModelNode.SetAndObservePolyData(model) currentModelNode.Modified() currentModelDisplayNode = currentModelNode.GetDisplayNode() if not currentModelDisplayNode: # create new displayNode currentModelDisplayNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelDisplayNode") slicer.mrmlScene.AddNode(currentModelDisplayNode) # always configure the displayNode to show the model currentModelDisplayNode.SetInputPolyData( currentModelNode.GetPolyData()) currentModelDisplayNode.SetColor(1.0, 0.55, 0.4) # red currentModelDisplayNode.SetBackfaceCulling(0) currentModelDisplayNode.SetSliceIntersectionVisibility(0) currentModelDisplayNode.SetVisibility(1) currentModelDisplayNode.SetOpacity(1.0) currentModelDisplayNode.Modified() # update the reference between model node and it's display node currentModelNode.SetAndObserveDisplayNodeID( currentModelDisplayNode.GetID()) currentModelNode.Modified() # fit slice to all sliceviewers slicer.app.applicationLogic().FitSliceToAll() # jump all sliceViewers to the first fiducial point, if one was used if currentSeedsNode: currentCoordinatesRAS = [0, 0, 0] if isinstance(currentSeedsNode, slicer.vtkMRMLAnnotationHierarchyNode): childrenNodes = vtk.vtkCollection() currentSeedsNode.GetChildrenDisplayableNodes(childrenNodes) # now we have the children, let's get the first one currentFiducial = childrenNodes.GetItemAsObject(0) # grab the current coordinates currentFiducial.GetFiducialCoordinates(currentCoordinatesRAS) elif isinstance(currentSeedsNode, slicer.vtkMRMLAnnotationFiducialNode): # grab the current coordinates currentSeedsNode.GetFiducialCoordinates(currentCoordinatesRAS) numberOfSliceNodes = slicer.mrmlScene.GetNumberOfNodesByClass( 'vtkMRMLSliceNode') for n in xrange(numberOfSliceNodes): sliceNode = slicer.mrmlScene.GetNthNodeByClass( n, "vtkMRMLSliceNode") if sliceNode: sliceNode.JumpSliceByOffsetting(currentCoordinatesRAS[0], currentCoordinatesRAS[1], currentCoordinatesRAS[2]) # center 3D view(s) on the new model if currentCoordinatesRAS: for d in range(slicer.app.layoutManager().threeDViewCount): threeDView = slicer.app.layoutManager().threeDWidget( d).threeDView() # reset the focal point threeDView.resetFocalPoint() # and fly to our seed point interactor = threeDView.interactor() renderer = threeDView.renderWindow().GetRenderers( ).GetItemAsObject(0) interactor.FlyTo(renderer, currentCoordinatesRAS[0], currentCoordinatesRAS[1], currentCoordinatesRAS[2]) SlicerVmtkCommonLib.Helper.Debug("End of Level Set Segmentation..")
def onCalculateLength(self): self.inputPolyData = self.vtkNode.GetPolyData() points = self.inputPolyData.GetPoints() lines = self.inputPolyData.GetLines() lines.InitTraversal() self.distanceTable = list() for i in range(self.inputPolyData.GetNumberOfCells()): fiberLength = 0 ids = vtk.vtkIdList() lines.GetNextCell(ids) #print(ids.GetNumberOfIds()) for j in range(ids.GetNumberOfIds() - 1): point1 = [0, 0, 0] point2 = [0, 0, 0] points.GetPoint(ids.GetId(j), point1) points.GetPoint(ids.GetId(j + 1), point2) x = point2[0] - point1[0] y = point2[1] - point1[1] z = point2[2] - point1[2] step = (x * x + y * y + z * z)**.5 fiberLength += step self.distanceTable.append(fiberLength) min, max = self.getDistanceBound() self.thresholdMin.setValue(min) self.thresholdMin.enabled = True self.thresholdMax.setValue(max + 1) self.thresholdMax.enabled = True self.applyThresholdButton.enabled = True layoutNodes = slicer.mrmlScene.GetNodesByClass('vtkMRMLLayoutNode') layoutNodes.InitTraversal() layoutNode = layoutNodes.GetNextItemAsObject() layoutNode.SetViewArrangement( slicer.vtkMRMLLayoutNode.SlicerLayoutConventionalQuantitativeView) chartViewNodes = slicer.mrmlScene.GetNodesByClass( 'vtkMRMLChartViewNode') chartViewNodes.InitTraversal() chartViewNode = chartViewNodes.GetNextItemAsObject() arrayNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLDoubleArrayNode()) array = arrayNode.GetArray() array.SetNumberOfTuples(10) step = (max - min) / 10 interMin = min interMax = min + step for i in range(10): numberOfFibers = 0 for length in self.distanceTable: if length <= interMax and length >= interMin and length <= self.thresholdMax.value and length >= self.thresholdMin.value: numberOfFibers += 1 array.SetComponent(i, 0, (interMin + interMax) / 2) array.SetComponent(i, 1, numberOfFibers) array.SetComponent(i, 2, 0) interMin += step interMax += step chartNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLChartNode()) chartNode.AddArray("Fiber Length", arrayNode.GetID()) chartViewNode.SetChartNodeID(chartNode.GetID()) chartNode.SetProperty('default', 'title', 'Length Distribution') chartNode.SetProperty('default', 'xAxisLabel', 'Length') chartNode.SetProperty('default', 'yAxisLabel', 'Distribution') chartNode.SetProperty('default', 'type', 'Bar')
def onCalculateLength(self): self.inputPolyData = self.vtkNode.GetPolyData() points = self.inputPolyData.GetPoints() lines = self.inputPolyData.GetLines() lines.InitTraversal() self.distanceTable = list() for i in range(self.inputPolyData.GetNumberOfCells()): fiberLength = 0 ids = vtk.vtkIdList() lines.GetNextCell(ids) #print(ids.GetNumberOfIds()) for j in range(ids.GetNumberOfIds() - 1): point1 = [0,0,0] point2 = [0,0,0] points.GetPoint(ids.GetId(j), point1) points.GetPoint(ids.GetId(j+1), point2) x = point2[0] - point1[0] y = point2[1] - point1[1] z = point2[2] - point1[2] step = (x*x + y*y + z*z)**.5 fiberLength += step self.distanceTable.append(fiberLength) min,max=self.getDistanceBound() self.thresholdMin.setValue(min) self.thresholdMin.enabled = True self.thresholdMax.setValue(max+1) self.thresholdMax.enabled = True self.applyThresholdButton.enabled = True layoutNodes = slicer.mrmlScene.GetNodesByClass('vtkMRMLLayoutNode') layoutNodes.InitTraversal() layoutNode = layoutNodes.GetNextItemAsObject() layoutNode.SetViewArrangement(slicer.vtkMRMLLayoutNode.SlicerLayoutConventionalQuantitativeView) chartViewNodes = slicer.mrmlScene.GetNodesByClass('vtkMRMLChartViewNode') chartViewNodes.InitTraversal() chartViewNode = chartViewNodes.GetNextItemAsObject() arrayNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLDoubleArrayNode()) array = arrayNode.GetArray() array.SetNumberOfTuples(10) step = (max-min)/10 interMin = min interMax = min+step for i in range(10): numberOfFibers = 0 for length in self.distanceTable: if length<=interMax and length>=interMin and length<=self.thresholdMax.value and length>=self.thresholdMin.value: numberOfFibers += 1 array.SetComponent(i,0,(interMin+interMax)/2) array.SetComponent(i,1,numberOfFibers) array.SetComponent(i,2,0) interMin += step interMax += step chartNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLChartNode()) chartNode.AddArray("Fiber Length",arrayNode.GetID()) chartViewNode.SetChartNodeID(chartNode.GetID()) chartNode.SetProperty('default', 'title', 'Length Distribution') chartNode.SetProperty('default', 'xAxisLabel', 'Length') chartNode.SetProperty('default', 'yAxisLabel', 'Distribution') chartNode.SetProperty('default', 'type', 'Bar')
def onApplyThreshold(self): min,max = self.getDistanceBound() newPoints = vtk.vtkPoints() newLines = vtk.vtkCellArray() newTensors = vtk.vtkFloatArray() newTensors.SetNumberOfComponents(9) newScalars = vtk.vtkFloatArray() points = self.inputPolyData.GetPoints() lines = self.inputPolyData.GetLines() tensors = self.inputPolyData.GetPointData().GetTensors() lines.InitTraversal() newId = 0 for length in self.distanceTable: if length<=self.thresholdMax.value and length>=self.thresholdMin.value: ids = vtk.vtkIdList() lines.GetNextCell(ids) newLine = vtk.vtkPolyLine() #print(ids.GetNumberOfIds()) newLine.GetPointIds().SetNumberOfIds(ids.GetNumberOfIds()) #print(((length-min)/(max-min))*100) for i in range(ids.GetNumberOfIds()): newPoints.InsertNextPoint(points.GetPoint(ids.GetId(i))) newLine.GetPointIds().SetId(i,newId) newScalars.InsertNextValue(((length-min)/(max-min))) newId += 1 tensorValue = [0]*9 if(tensors != None): for j in range(9): tensorValue[j] = tensors.GetComponent(ids.GetId(i),j) newTensors.InsertNextTuple(tensorValue) newLines.InsertNextCell(newLine) self.outputPolyData = vtk.vtkPolyData() self.outputPolyData.SetPoints(newPoints) self.outputPolyData.SetLines(newLines) self.outputPolyData.GetPointData().SetTensors(newTensors) newScalars.SetName("Length") self.outputPolyData.GetPointData().AddArray(newScalars) self.outputNode.SetAndObservePolyData(self.outputPolyData) chartViewNodes = slicer.mrmlScene.GetNodesByClass('vtkMRMLChartViewNode') chartViewNodes.InitTraversal() chartViewNode = chartViewNodes.GetNextItemAsObject() arrayNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLDoubleArrayNode()) array = arrayNode.GetArray() array.SetNumberOfTuples(10) step = (max-min)/10 interMin = min interMax = min+step for i in range(10): numberOfFibers = 0 for length in self.distanceTable: if length<=interMax and length>=interMin and length<=self.thresholdMax.value and length>=self.thresholdMin.value: numberOfFibers += 1 array.SetComponent(i,0,(interMin+interMax)/2) array.SetComponent(i,1,numberOfFibers) array.SetComponent(i,2,0) interMin += step interMax += step chartNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLChartNode()) chartNode.AddArray("Fiber Length",arrayNode.GetID()) chartViewNode.SetChartNodeID(chartNode.GetID()) chartNode.SetProperty('default', 'title', 'Length Distribution') chartNode.SetProperty('default', 'xAxisLabel', 'Length') chartNode.SetProperty('default', 'yAxisLabel', 'Distribution') chartNode.SetProperty('default', 'type', 'Bar')
def findNeighbors(self, pointId): #for i in range(0, self.moulagePolys.GetNumberOfCells()): neighbors = vtk.vtkIdList() self.moulagePolys.GetCell(pointId, neighbors) return neighbors
def computeCurvatures(self, poly, curvatureValues): # Calculate point-by-point curvature of the curve # Returns mean/min/max curvature lines = poly.GetLines() points = poly.GetPoints() pts = vtk.vtkIdList() lines.GetCell(0, pts) ip = numpy.array(points.GetPoint(pts.GetId(0))) n = pts.GetNumberOfIds() ## Check if there is overlap between the first and last segments ## (for making sure to close the loop for spline curves) #if n > 2: # slp = numpy.array(points.GetPoint(pts.GetId(n-2))) # # Check distance between the first point and the second last point # if numpy.linalg.norm(slp-ip) < 0.00001: # n = n - 1 curvatureValues.Initialize() curvatureValues.SetName("Curvature") curvatureValues.SetNumberOfComponents(1) curvatureValues.SetNumberOfTuples(n) curvatureValues.Reset() curvatureValues.FillComponent(0,0.0) minKappa = 0.0 maxKappa = 0.0 meanKappa = 0.0 # NOTE: mean is weighted by the lengh of each segment pp = numpy.array(points.GetPoint(pts.GetId(0))) p = numpy.array(points.GetPoint(pts.GetId(1))) ds = numpy.linalg.norm(p-pp) pT = (p-pp) / ds pp = p pm = (p+pp)/2.0 length = 0.0 + numpy.linalg.norm(pm-pp) curvatureValues.InsertValue(pts.GetId(0), 0.0) # The curvature for the first cell is 0.0 for i in range(1,n-1): p = numpy.array(points.GetPoint(pts.GetId(i+1))) ds = numpy.linalg.norm(p-pp) T = (p-pp) / ds kappa = numpy.linalg.norm(T-pT) / ds # Curvature curvatureValues.InsertValue(pts.GetId(i), kappa) # The curvature for the first cell is 0.0 m = (p+pp)/2.0 l = numpy.linalg.norm(m-pm) # length for this segment if kappa < minKappa: minKappa = kappa elif kappa > maxKappa: maxKappa = kappa meanKappa = meanKappa + kappa * l # weighted mean length = length + l pp = p pm = m pT = T curvatureValues.InsertValue(pts.GetId(n-1), 0.0) # The curvature for the last cell is 0.0 length = length + numpy.linalg.norm(pp-pm) meanKappa = meanKappa / length # TODO: This routin does not consider a closed loop. If a closed loop is specified, # It needs to calculate the curveture of two ends differently. return (meanKappa, minKappa, maxKappa)
def calcApproachScore(self, targetPointNode, skinPolyData, obstacleBspTree, skinModelNode=None): #pTargetA = targetPointNode.GetMarkupPointVector(0, 0) tListNumber = targetPointNode.GetNumberOfFiducials() #pTargetA = pointA #pTargetB = pointB #pTargetC = pointC polyData = skinPolyData nPoints = polyData.GetNumberOfPoints() nCells = polyData.GetNumberOfCells() pSurface = [0.0, 0.0, 0.0] minDistancePoint = [0.0, 0.0, 0.0] tolerance = 0.001 t = vtk.mutable(0.0) x = [0.0, 0.0, 0.0] pcoords = [0.0, 0.0, 0.0] subId = vtk.mutable(0) #print ("nPoints = %d" % (nPoints)) #print ("nCells = %d" % (nCells)) # Map surface model if skinModelNode != None: pointValue = vtk.vtkDoubleArray() pointValue.SetName("Colors") pointValue.SetNumberOfComponents(1) pointValue.SetNumberOfTuples(nPoints) pointValue.Reset() pointValue.FillComponent(0, 0.0) bspTree = obstacleBspTree cp0 = [0.0, 0.0, 0.0] cp1 = [0.0, 0.0, 0.0] cp2 = [0.0, 0.0, 0.0] accessibleArea = 0.0 inaccessibleArea = 0.0 ids = vtk.vtkIdList() minDistance = -1 #iDA = 0 #iDAFlag = 0 #d = 0 for index in range(nCells): iDA = 0 iDAFlag = 0 d = 0 i = 0 j = 0 cell = polyData.GetCell(index) if cell.GetCellType() == vtk.VTK_TRIANGLE: area = cell.ComputeArea() polyData.GetCellPoints(index, ids) polyData.GetPoint(ids.GetId(0), cp0) polyData.GetPoint(ids.GetId(1), cp1) polyData.GetPoint(ids.GetId(2), cp2) vtk.vtkTriangle.TriangleCenter(cp0, cp1, cp2, pSurface) ##### for i in range(0, tListNumber, 1): pTargetA = targetPointNode.GetMarkupPointVector(i, 0) iDA = bspTree.IntersectWithLine(pSurface, pTargetA, tolerance, t, x, pcoords, subId) if iDA >= 1: iDAFlag = 10 ##### if iDAFlag < 1: if skinModelNode != None: for j in range(0, tListNumber, 1): pTargetA = targetPointNode.GetMarkupPointVector( j, 0) d += (vtk.vtkMath.Distance2BetweenPoints( pSurface, pTargetA)) d = d / tListNumber d = math.sqrt(d) if 100 < d < 240: if d < minDistance or minDistance < 0: minDistance = d minDistancePoint = [ pSurface[0], pSurface[1], pSurface[2] ] v = d + 51 pointValue.InsertValue(ids.GetId(0), v) pointValue.InsertValue(ids.GetId(1), v) pointValue.InsertValue(ids.GetId(2), v) accessibleArea = accessibleArea + area else: v = -1.0 pointValue.InsertValue(ids.GetId(0), v) pointValue.InsertValue(ids.GetId(1), v) pointValue.InsertValue(ids.GetId(2), v) inaccessibleArea = inaccessibleArea + area else: if skinModelNode != None: v = -1.0 pointValue.InsertValue(ids.GetId(0), v) pointValue.InsertValue(ids.GetId(1), v) pointValue.InsertValue(ids.GetId(2), v) inaccessibleArea = inaccessibleArea + area else: print("ERROR: Non-triangular cell.") score = accessibleArea if skinModelNode != None: skinModelNode.AddPointScalars(pointValue) skinModelNode.SetActivePointScalars( "Colors", vtk.vtkDataSetAttributes.SCALARS) skinModelNode.Modified() displayNode = skinModelNode.GetModelDisplayNode() displayNode.SetActiveScalarName("Colors") displayNode.SetScalarRange(0.0, 200.0) return (score, minDistance, minDistancePoint)
def distanceToPoint(self, point, extrapolate): # distanceToPoint() calculates the approximate minimum distance between # the specified point and the closest segment of the curve. # It calculates the minimum distance between the point and each segment # of the curve (approxmated as a straight line) and select the segment with # the minimum distance from the point as a closest segment. npoint = numpy.array(point) if self.CurvePoly == None: return numpy.Inf lines = self.CurvePoly.GetLines() points = self.CurvePoly.GetPoints() pts = vtk.vtkIdList() lines.GetCell(0, pts) ip = numpy.array(points.GetPoint(pts.GetId(0))) n = pts.GetNumberOfIds() # First point on the segment p1 = ip minMag2 = numpy.Inf minIndex = -1 minErrVec = numpy.array([0.0, 0.0, 0.0]) errVec = numpy.array([0.0, 0.0, 0.0]) for i in range(1,n): # Second point on the segment p2 = numpy.array(points.GetPoint(pts.GetId(i))) # Normal vector along the segment nvec = p2-p1 norm = numpy.linalg.norm(nvec) if norm != 0: nnvec = nvec / norm # Calculate the distance between the point and the segment mag2 = 0.0 op = npoint - p1 aproj = numpy.inner(op, nnvec) if extrapolate and ((i == 1 and aproj < 0.0) or (i == n-1 and aproj > 0.0)): # extrapolate first or last segment errVec = op-aproj*nnvec # perpendicular mag2 = numpy.inner(errVec,errVec) # magnitude^2 else: if aproj < 0.0: errVec = npoint - p1 mag2 = numpy.inner(errVec, errVec) # magnitude^2 elif aproj > norm: errVec = npoint - p2 mag2 = numpy.inner(errVec, errVec) # magnitude^2 else: errVec = op-aproj*nnvec # perpendicular mag2 = numpy.inner(errVec,errVec) # magnitude^2 if mag2 < minMag2: minMag2 = mag2 minIndex = i minErrVec = errVec p1 = p2 distance = numpy.sqrt(minMag2) return (distance, minErrVec)
def start( self, preview=False ): ''' ''' SlicerVmtkCommonLib.Helper.Debug( "Starting Level Set Segmentation.." ) # first we need the nodes currentVolumeNode = self.__inputVolumeNodeSelector.currentNode() currentSeedsNode = self.__seedFiducialsNodeSelector.currentNode() currentVesselnessNode = self.__vesselnessVolumeNodeSelector.currentNode() currentStoppersNode = self.__stopperFiducialsNodeSelector.currentNode() currentLabelMapNode = self.__outputVolumeNodeSelector.currentNode() currentModelNode = self.__outputModelNodeSelector.currentNode() if not currentVolumeNode: # we need a input volume node return 0 if not currentSeedsNode: # we need a seeds node return 0 if not currentStoppersNode or currentStoppersNode.GetID() == currentSeedsNode.GetID(): # we need a current stopper node # self.__stopperFiducialsNodeSelector.addNode() pass if not currentLabelMapNode or currentLabelMapNode.GetID() == currentVolumeNode.GetID(): # we need a current labelMap node newLabelMapDisplayNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLLabelMapVolumeDisplayNode" ) newLabelMapDisplayNode.SetScene( slicer.mrmlScene ) newLabelMapDisplayNode.SetDefaultColorMap() slicer.mrmlScene.AddNode( newLabelMapDisplayNode ) newLabelMapNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLScalarVolumeNode" ) newLabelMapNode.CopyOrientation( currentVolumeNode ) newLabelMapNode.SetScene( slicer.mrmlScene ) newLabelMapNode.SetName( slicer.mrmlScene.GetUniqueNameByString( self.__outputVolumeNodeSelector.baseName ) ) newLabelMapNode.LabelMapOn() newLabelMapNode.SetAndObserveDisplayNodeID( newLabelMapDisplayNode.GetID() ) slicer.mrmlScene.AddNode( newLabelMapNode ) currentLabelMapNode = newLabelMapNode self.__outputVolumeNodeSelector.setCurrentNode( currentLabelMapNode ) if not currentModelNode: # we need a current model node, the display node is created later newModelNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelNode" ) newModelNode.SetScene( slicer.mrmlScene ) newModelNode.SetName( slicer.mrmlScene.GetUniqueNameByString( self.__outputModelNodeSelector.baseName ) ) slicer.mrmlScene.AddNode( newModelNode ) currentModelNode = newModelNode self.__outputModelNodeSelector.setCurrentNode( currentModelNode ) # now we need to convert the fiducials to vtkIdLists seeds = SlicerVmtkCommonLib.Helper.convertFiducialHierarchyToVtkIdList( currentSeedsNode, currentVolumeNode ) # stoppers = SlicerVmtkCommonLib.Helper.convertFiducialHierarchyToVtkIdList(currentStoppersNode, currentVolumeNode) stoppers = vtk.vtkIdList() # TODO # the input image for the initialization inputImage = vtk.vtkImageData() # check if we have a vesselnessNode - this will be our input for the initialization then if currentVesselnessNode: # yes, there is one inputImage.DeepCopy( currentVesselnessNode.GetImageData() ) else: # no, there is none - we use the original image inputImage.DeepCopy( currentVolumeNode.GetImageData() ) inputImage.Update() # initialization initImageData = vtk.vtkImageData() # evolution evolImageData = vtk.vtkImageData() # perform the initialization initImageData.DeepCopy( self.GetLogic().performInitialization( inputImage, self.__thresholdSlider.minimumValue, self.__thresholdSlider.maximumValue, seeds, stoppers, 0 ) ) # TODO sidebranch ignore feature initImageData.Update() if not initImageData.GetPointData().GetScalars(): # something went wrong, the image is empty SlicerVmtkCommonLib.Helper.Info( "Segmentation failed - the output was empty.." ) return -1 # check if it is a preview call if preview: # if this is a preview call, we want to skip the evolution evolImageData.DeepCopy( initImageData ) else: # no preview, run the whole thing! we never use the vesselness node here, just the original one evolImageData.DeepCopy( self.GetLogic().performEvolution( currentVolumeNode.GetImageData(), initImageData, self.__iterationSpinBox.value, self.__inflationSlider.value, self.__curvatureSlider.value, self.__attractionSlider.value, 'geodesic' ) ) evolImageData.Update() # create segmentation labelMap labelMap = vtk.vtkImageData() labelMap.DeepCopy( self.GetLogic().buildSimpleLabelMap( evolImageData, 0, 5 ) ) labelMap.Update() currentLabelMapNode.CopyOrientation( currentVolumeNode ) # propagate the label map to the node currentLabelMapNode.SetAndObserveImageData( labelMap ) currentLabelMapNode.Modified() # deactivate the threshold in the GUI self.resetThresholdOnDisplayNode() # self.onInputVolumeChanged() # show the segmentation results in the GUI selectionNode = slicer.app.applicationLogic().GetSelectionNode() if preview and currentVesselnessNode: # if preview and a vesselnessNode was configured, show it selectionNode.SetReferenceActiveVolumeID( currentVesselnessNode.GetID() ) else: # if not preview, show the original volume if currentVesselnessNode: selectionNode.SetReferenceSecondaryVolumeID( currentVesselnessNode.GetID() ) selectionNode.SetReferenceActiveVolumeID( currentVolumeNode.GetID() ) selectionNode.SetReferenceActiveLabelVolumeID( currentLabelMapNode.GetID() ) slicer.app.applicationLogic().PropagateVolumeSelection() # generate 3D model model = vtk.vtkPolyData() # we need the ijkToRas transform for the marching cubes call ijkToRasMatrix = vtk.vtkMatrix4x4() currentLabelMapNode.GetIJKToRASMatrix( ijkToRasMatrix ) # call marching cubes model.DeepCopy( self.GetLogic().marchingCubes( evolImageData, ijkToRasMatrix, 0.0 ) ) model.Update() # propagate model to nodes currentModelNode.SetAndObservePolyData( model ) currentModelNode.Modified() currentModelDisplayNode = currentModelNode.GetDisplayNode() if not currentModelDisplayNode: # create new displayNode currentModelDisplayNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelDisplayNode" ) slicer.mrmlScene.AddNode( currentModelDisplayNode ) # always configure the displayNode to show the model currentModelDisplayNode.SetInputPolyData( currentModelNode.GetPolyData() ) currentModelDisplayNode.SetColor( 1.0, 0.55, 0.4 ) # red currentModelDisplayNode.SetBackfaceCulling( 0 ) currentModelDisplayNode.SetSliceIntersectionVisibility( 0 ) currentModelDisplayNode.SetVisibility( 1 ) currentModelDisplayNode.SetOpacity( 1.0 ) currentModelDisplayNode.Modified() # update the reference between model node and it's display node currentModelNode.SetAndObserveDisplayNodeID( currentModelDisplayNode.GetID() ) currentModelNode.Modified() # fit slice to all sliceviewers slicer.app.applicationLogic().FitSliceToAll() # jump all sliceViewers to the first fiducial point, if one was used if currentSeedsNode: currentCoordinatesRAS = [0, 0, 0] if isinstance( currentSeedsNode, slicer.vtkMRMLAnnotationHierarchyNode ): childrenNodes = vtk.vtkCollection() currentSeedsNode.GetChildrenDisplayableNodes( childrenNodes ) # now we have the children, let's get the first one currentFiducial = childrenNodes.GetItemAsObject( 0 ) # grab the current coordinates currentFiducial.GetFiducialCoordinates( currentCoordinatesRAS ) elif isinstance( currentSeedsNode, slicer.vtkMRMLAnnotationFiducialNode ): # grab the current coordinates currentSeedsNode.GetFiducialCoordinates( currentCoordinatesRAS ) numberOfSliceNodes = slicer.mrmlScene.GetNumberOfNodesByClass( 'vtkMRMLSliceNode' ) for n in xrange( numberOfSliceNodes ): sliceNode = slicer.mrmlScene.GetNthNodeByClass( n, "vtkMRMLSliceNode" ) if sliceNode: sliceNode.JumpSliceByOffsetting( currentCoordinatesRAS[0], currentCoordinatesRAS[1], currentCoordinatesRAS[2] ) # center 3D view(s) on the new model if currentCoordinatesRAS: for d in range( slicer.app.layoutManager().threeDViewCount ): threeDView = slicer.app.layoutManager().threeDWidget( d ).threeDView() # reset the focal point threeDView.resetFocalPoint() # and fly to our seed point interactor = threeDView.interactor() renderer = threeDView.renderWindow().GetRenderers().GetItemAsObject( 0 ) interactor.FlyTo( renderer, currentCoordinatesRAS[0], currentCoordinatesRAS[1], currentCoordinatesRAS[2] ) SlicerVmtkCommonLib.Helper.Debug( "End of Level Set Segmentation.." )
def mkVtkIdList(it): vil = vtk.vtkIdList() for i in it: vil.InsertNextId(int(i)) return vil
def start( self, preview=False ): ''' ''' SlicerVmtk4CommonLib.Helper.Debug( "Starting Centerline Computation.." ) # first we need the nodes currentModelNode = self.__inputModelNodeSelector.currentNode() currentSeedsNode = self.__seedFiducialsNodeSelector.currentNode() currentOutputModelNode = self.__outputModelNodeSelector.currentNode() currentVoronoiModelNode = self.__voronoiModelNodeSelector.currentNode() if not currentModelNode: # we need a input volume node return 0 if not currentSeedsNode: # we need a seeds node return 0 if not currentOutputModelNode or currentOutputModelNode.GetID() == currentModelNode.GetID(): # we need a current model node, the display node is created later newModelNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelNode" ) newModelNode.SetScene( slicer.mrmlScene ) newModelNode.SetName( slicer.mrmlScene.GetUniqueNameByString( self.__outputModelNodeSelector.baseName ) ) slicer.mrmlScene.AddNode( newModelNode ) currentOutputModelNode = newModelNode self.__outputModelNodeSelector.setCurrentNode( currentOutputModelNode ) if not currentVoronoiModelNode or currentVoronoiModelNode.GetID() == currentModelNode.GetID() or currentVoronoiModelNode.GetID() == currentOutputModelNode.GetID(): # we need a current model node, the display node is created later newModelNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelNode" ) newModelNode.SetScene( slicer.mrmlScene ) newModelNode.SetName( slicer.mrmlScene.GetUniqueNameByString( self.__voronoiModelNodeSelector.baseName ) ) slicer.mrmlScene.AddNode( newModelNode ) currentVoronoiModelNode = newModelNode self.__voronoiModelNodeSelector.setCurrentNode( currentVoronoiModelNode ) # the output models preparedModel = vtk.vtkPolyData() model = vtk.vtkPolyData() network = vtk.vtkPolyData() voronoi = vtk.vtkPolyData() currentCoordinatesRAS = [0, 0, 0] # grab the current coordinates currentSeedsNode.GetFiducialCoordinates( currentCoordinatesRAS ) # prepare the model preparedModel.DeepCopy( self.GetLogic().prepareModel( currentModelNode.GetPolyData() ) ) preparedModel.Update() # decimate the model (only for network extraction) model.DeepCopy( self.GetLogic().decimateSurface( preparedModel ) ) model.Update() # open the model at the seed (only for network extraction) model.DeepCopy( self.GetLogic().openSurfaceAtPoint( model, currentCoordinatesRAS ) ) model.Update() # extract Network network.DeepCopy( self.GetLogic().extractNetwork( model ) ) network.Update() # # # not preview mode: real computation! if not preview: # here we start the actual centerline computation which is mathematically more robust and accurate but takes longer than the network extraction # clip surface at endpoints identified by the network extraction tupel = self.GetLogic().clipSurfaceAtEndPoints( network, currentModelNode.GetPolyData() ) clippedSurface = tupel[0] endpoints = tupel[1] # now find the one endpoint which is closest to the seed and use it as the source point for centerline computation # all other endpoints are the target points sourcePoint = [0, 0, 0] # the following arrays have the same indexes and are synchronized at all times distancesToSeed = [] targetPoints = [] # we now need to loop through the endpoints two times # first loop is to detect the endpoint resulting in the tiny hole we poked in the surface # this is very close to our seed but not the correct sourcePoint for i in range( endpoints.GetNumberOfPoints() ): currentPoint = endpoints.GetPoint( i ) # get the euclidean distance currentDistanceToSeed = math.sqrt( math.pow( ( currentPoint[0] - currentCoordinatesRAS[0] ), 2 ) + math.pow( ( currentPoint[1] - currentCoordinatesRAS[1] ), 2 ) + math.pow( ( currentPoint[2] - currentCoordinatesRAS[2] ), 2 ) ) targetPoints.append( currentPoint ) distancesToSeed.append( currentDistanceToSeed ) # now we have a list of distances with the corresponding points # the index with the most minimal distance is the holePoint, we want to ignore it # the index with the second minimal distance is the point closest to the seed, we want to set it as sourcepoint # all other points are the targetpoints # get the index of the holePoint, which we want to remove from our endPoints holePointIndex = distancesToSeed.index( min( distancesToSeed ) ) # .. and remove it distancesToSeed.pop( holePointIndex ) targetPoints.pop( holePointIndex ) # now find the sourcepoint sourcePointIndex = distancesToSeed.index( min( distancesToSeed ) ) # .. and remove it after saving it as the sourcePoint sourcePoint = targetPoints[sourcePointIndex] distancesToSeed.pop( sourcePointIndex ) targetPoints.pop( sourcePointIndex ) # again, at this point we have a) the sourcePoint and b) a list of real targetPoints # now create the sourceIdList and targetIdList for the actual centerline computation sourceIdList = vtk.vtkIdList() targetIdList = vtk.vtkIdList() pointLocator = vtk.vtkPointLocator() pointLocator.SetDataSet( preparedModel ) pointLocator.BuildLocator() # locate the source on the surface sourceId = pointLocator.FindClosestPoint( sourcePoint ) sourceIdList.InsertNextId( sourceId ) f = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLAnnotationFiducialNode" ) f.SetFiducialCoordinates( sourcePoint ) f.Initialize( slicer.mrmlScene ) f.SelectedOn() # locate the endpoints on the surface for p in targetPoints: f = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLAnnotationFiducialNode" ) f.SetFiducialCoordinates( p ) f.Initialize( slicer.mrmlScene ) id = pointLocator.FindClosestPoint( p ) targetIdList.InsertNextId( id ) tupel = self.GetLogic().computeCenterlines( preparedModel, sourceIdList, targetIdList ) network.DeepCopy( tupel[0] ) voronoi.DeepCopy( tupel[1] ) # # # update the display of the original model in terms of opacity currentModelDisplayNode = currentModelNode.GetDisplayNode() if not currentModelDisplayNode: # create new displayNode currentModelDisplayNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelDisplayNode" ) slicer.mrmlScene.AddNode( currentModelDisplayNode ) currentModelDisplayNode.SetOpacity( 0.4 ) currentModelDisplayNode.Modified() currentModelDisplayNode.SetModifiedSinceRead( 1 ) # update the reference between model node and it's display node currentModelNode.SetAndObserveDisplayNodeID( currentModelDisplayNode.GetID() ) currentModelNode.Modified() currentModelNode.SetModifiedSinceRead( 1 ) # # finally: # propagate output model to nodes currentOutputModelNode.SetAndObservePolyData( network ) currentOutputModelNode.Modified() currentOutputModelNode.SetModifiedSinceRead( 1 ) currentOutputModelDisplayNode = currentOutputModelNode.GetDisplayNode() if not currentOutputModelDisplayNode: # create new displayNode currentOutputModelDisplayNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelDisplayNode" ) slicer.mrmlScene.AddNode( currentOutputModelDisplayNode ) # always configure the displayNode to show the model currentOutputModelDisplayNode.SetPolyData( currentOutputModelNode.GetPolyData() ) currentOutputModelDisplayNode.SetColor( 0.0, 0.0, 0.4 ) # red currentOutputModelDisplayNode.SetBackfaceCulling( 0 ) currentOutputModelDisplayNode.SetSliceIntersectionVisibility( 0 ) currentOutputModelDisplayNode.SetVisibility( 1 ) currentOutputModelDisplayNode.SetOpacity( 1.0 ) currentOutputModelDisplayNode.Modified() currentOutputModelDisplayNode.SetModifiedSinceRead( 1 ) # update the reference between model node and it's display node currentOutputModelNode.SetAndObserveDisplayNodeID( currentOutputModelDisplayNode.GetID() ) currentOutputModelNode.Modified() currentOutputModelNode.SetModifiedSinceRead( 1 ) # only update the voronoi node if we are not in preview mode if not preview: currentVoronoiModelNode.SetAndObservePolyData( voronoi ) currentVoronoiModelNode.Modified() currentVoronoiModelNode.SetModifiedSinceRead( 1 ) currentVoronoiModelDisplayNode = currentVoronoiModelNode.GetDisplayNode() if not currentVoronoiModelDisplayNode: # create new displayNode currentVoronoiModelDisplayNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelDisplayNode" ) slicer.mrmlScene.AddNode( currentVoronoiModelDisplayNode ) # always configure the displayNode to show the model currentVoronoiModelDisplayNode.SetPolyData( currentVoronoiModelNode.GetPolyData() ) currentVoronoiModelDisplayNode.SetScalarVisibility( 1 ) currentVoronoiModelDisplayNode.SetBackfaceCulling( 0 ) currentVoronoiModelDisplayNode.SetActiveScalarName( "Radius" ) currentVoronoiModelDisplayNode.SetAndObserveColorNodeID( slicer.mrmlScene.GetNodesByName( "Labels" ).GetItemAsObject( 0 ).GetID() ) currentVoronoiModelDisplayNode.SetSliceIntersectionVisibility( 0 ) currentVoronoiModelDisplayNode.SetVisibility( 1 ) currentVoronoiModelDisplayNode.SetOpacity( 0.5 ) currentVoronoiModelDisplayNode.Modified() currentVoronoiModelDisplayNode.SetModifiedSinceRead( 1 ) # update the reference between model node and it's display node currentVoronoiModelNode.SetAndObserveDisplayNodeID( currentVoronoiModelDisplayNode.GetID() ) currentVoronoiModelNode.Modified() currentVoronoiModelNode.SetModifiedSinceRead( 1 ) SlicerVmtk4CommonLib.Helper.Debug( "End of Centerline Computation.." )
def clipSurfaceAtEndPoints(self, networkPolyData, surfacePolyData): ''' Clips the surfacePolyData on the endpoints identified using the networkPolyData. Returns a tupel of the form [clippedPolyData, endpointsPoints] ''' # import the vmtk libraries try: from libvtkvmtkComputationalGeometryPython import * from libvtkvmtkMiscPython import * except ImportError: print "FAILURE: Unable to import the SlicerVmtk4 libraries!" cleaner = vtk.vtkCleanPolyData() cleaner.SetInput(networkPolyData) cleaner.Update() network = cleaner.GetOutput() network.BuildCells() network.BuildLinks(0) endpointIds = vtk.vtkIdList() radiusArray = network.GetPointData().GetArray('Radius') endpoints = vtk.vtkPolyData() endpointsPoints = vtk.vtkPoints() endpointsRadius = vtk.vtkDoubleArray() endpointsRadius.SetName('Radius') endpoints.SetPoints(endpointsPoints) endpoints.GetPointData().AddArray(endpointsRadius) radiusFactor = 1.2 minRadius = 0.01 for i in range(network.GetNumberOfCells()): numberOfCellPoints = network.GetCell(i).GetNumberOfPoints() pointId0 = network.GetCell(i).GetPointId(0) pointId1 = network.GetCell(i).GetPointId(numberOfCellPoints - 1) pointCells = vtk.vtkIdList() network.GetPointCells(pointId0, pointCells) numberOfEndpoints = endpointIds.GetNumberOfIds() if pointCells.GetNumberOfIds() == 1: pointId = endpointIds.InsertUniqueId(pointId0) if pointId == numberOfEndpoints: point = network.GetPoint(pointId0) radius = radiusArray.GetValue(pointId0) radius = max(radius, minRadius) endpointsPoints.InsertNextPoint(point) endpointsRadius.InsertNextValue(radiusFactor * radius) pointCells = vtk.vtkIdList() network.GetPointCells(pointId1, pointCells) numberOfEndpoints = endpointIds.GetNumberOfIds() if pointCells.GetNumberOfIds() == 1: pointId = endpointIds.InsertUniqueId(pointId1) if pointId == numberOfEndpoints: point = network.GetPoint(pointId1) radius = radiusArray.GetValue(pointId1) radius = max(radius, minRadius) endpointsPoints.InsertNextPoint(point) endpointsRadius.InsertNextValue(radiusFactor * radius) polyBall = vtkvmtkPolyBall() polyBall.SetInput(endpoints) polyBall.SetPolyBallRadiusArrayName('Radius') clipper = vtk.vtkClipPolyData() clipper.SetInput(surfacePolyData) clipper.SetClipFunction(polyBall) clipper.Update() connectivityFilter = vtk.vtkPolyDataConnectivityFilter() connectivityFilter.SetInput(clipper.GetOutput()) connectivityFilter.ColorRegionsOff() connectivityFilter.SetExtractionModeToLargestRegion() connectivityFilter.Update() clippedSurface = connectivityFilter.GetOutput() outPolyData = vtk.vtkPolyData() outPolyData.DeepCopy(clippedSurface) outPolyData.Update() return [outPolyData, endpointsPoints]
def calcApproachScore(self, point, skinPolyData, obstacleBspTree, skinModelNode=None): pTarget = point polyData = skinPolyData nPoints = polyData.GetNumberOfPoints() nCells = polyData.GetNumberOfCells() pSurface=[0.0, 0.0, 0.0] minDistancePoint = [0.0, 0.0, 0.0] tolerance = 0.001 t = vtk.mutable(0.0) x = [0.0, 0.0, 0.0] pcoords = [0.0, 0.0, 0.0] subId = vtk.mutable(0) #print ("nPoints = %d" % (nPoints)) #print ("nCells = %d" % (nCells)) # Map surface model if skinModelNode != None: pointValue = vtk.vtkDoubleArray() pointValue.SetName("Colors") pointValue.SetNumberOfComponents(1) pointValue.SetNumberOfTuples(nPoints) pointValue.Reset() pointValue.FillComponent(0,0.0); bspTree = obstacleBspTree cp0=[0.0, 0.0, 0.0] cp1=[0.0, 0.0, 0.0] cp2=[0.0, 0.0, 0.0] accessibleArea = 0.0 inaccessibleArea = 0.0 ids=vtk.vtkIdList() minDistance = -1; for index in range(nCells): cell = polyData.GetCell(index) if cell.GetCellType() == vtk.VTK_TRIANGLE: area = cell.ComputeArea() polyData.GetCellPoints(index, ids) polyData.GetPoint(ids.GetId(0), cp0) polyData.GetPoint(ids.GetId(1), cp1) polyData.GetPoint(ids.GetId(2), cp2) vtk.vtkTriangle.TriangleCenter(cp0, cp1, cp2, pSurface) iD = bspTree.IntersectWithLine(pSurface, pTarget, tolerance, t, x, pcoords, subId) if iD < 1: if skinModelNode != None: d = vtk.vtkMath.Distance2BetweenPoints(pSurface, pTarget) d = math.sqrt(d) if d < minDistance or minDistance < 0: minDistance = d minDistancePoint = [pSurface[0],pSurface[1],pSurface[2]] v = d+101 pointValue.InsertValue(ids.GetId(0), v) pointValue.InsertValue(ids.GetId(1), v) pointValue.InsertValue(ids.GetId(2), v) accessibleArea = accessibleArea + area else: if skinModelNode != None: v = -1.0 pointValue.InsertValue(ids.GetId(0), v) pointValue.InsertValue(ids.GetId(1), v) pointValue.InsertValue(ids.GetId(2), v) inaccessibleArea = inaccessibleArea + area else: print ("ERROR: Non-triangular cell.") score = accessibleArea / (accessibleArea + inaccessibleArea) if skinModelNode != None: skinModelNode.AddPointScalars(pointValue) skinModelNode.SetActivePointScalars("Colors", vtk.vtkDataSetAttributes.SCALARS) skinModelNode.Modified() displayNode = skinModelNode.GetModelDisplayNode() displayNode.SetActiveScalarName("Colors") displayNode.SetScalarRange(0.0,200.0) return (score, minDistance, minDistancePoint)
def onApplyThreshold(self): min, max = self.getDistanceBound() newPoints = vtk.vtkPoints() newLines = vtk.vtkCellArray() newTensors = vtk.vtkFloatArray() newTensors.SetNumberOfComponents(9) newScalars = vtk.vtkFloatArray() points = self.inputPolyData.GetPoints() lines = self.inputPolyData.GetLines() tensors = self.inputPolyData.GetPointData().GetTensors() lines.InitTraversal() newId = 0 for length in self.distanceTable: if length <= self.thresholdMax.value and length >= self.thresholdMin.value: ids = vtk.vtkIdList() lines.GetNextCell(ids) newLine = vtk.vtkPolyLine() #print(ids.GetNumberOfIds()) newLine.GetPointIds().SetNumberOfIds(ids.GetNumberOfIds()) #print(((length-min)/(max-min))*100) for i in range(ids.GetNumberOfIds()): newPoints.InsertNextPoint(points.GetPoint(ids.GetId(i))) newLine.GetPointIds().SetId(i, newId) newScalars.InsertNextValue(((length - min) / (max - min))) newId += 1 tensorValue = [0] * 9 if (tensors != None): for j in range(9): tensorValue[j] = tensors.GetComponent( ids.GetId(i), j) newTensors.InsertNextTuple(tensorValue) newLines.InsertNextCell(newLine) self.outputPolyData = vtk.vtkPolyData() self.outputPolyData.SetPoints(newPoints) self.outputPolyData.SetLines(newLines) self.outputPolyData.GetPointData().SetTensors(newTensors) newScalars.SetName("Length") self.outputPolyData.GetPointData().AddArray(newScalars) self.outputNode.SetAndObservePolyData(self.outputPolyData) chartViewNodes = slicer.mrmlScene.GetNodesByClass( 'vtkMRMLChartViewNode') chartViewNodes.InitTraversal() chartViewNode = chartViewNodes.GetNextItemAsObject() arrayNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLDoubleArrayNode()) array = arrayNode.GetArray() array.SetNumberOfTuples(10) step = (max - min) / 10 interMin = min interMax = min + step for i in range(10): numberOfFibers = 0 for length in self.distanceTable: if length <= interMax and length >= interMin and length <= self.thresholdMax.value and length >= self.thresholdMin.value: numberOfFibers += 1 array.SetComponent(i, 0, (interMin + interMax) / 2) array.SetComponent(i, 1, numberOfFibers) array.SetComponent(i, 2, 0) interMin += step interMax += step chartNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLChartNode()) chartNode.AddArray("Fiber Length", arrayNode.GetID()) chartViewNode.SetChartNodeID(chartNode.GetID()) chartNode.SetProperty('default', 'title', 'Length Distribution') chartNode.SetProperty('default', 'xAxisLabel', 'Length') chartNode.SetProperty('default', 'yAxisLabel', 'Distribution') chartNode.SetProperty('default', 'type', 'Bar')
def start(self, preview=False): ''' ''' SlicerVmtk4CommonLib.Helper.Debug("Starting Centerline Computation..") # first we need the nodes currentModelNode = self.__inputModelNodeSelector.currentNode() currentSeedsNode = self.__seedFiducialsNodeSelector.currentNode() currentOutputModelNode = self.__outputModelNodeSelector.currentNode() currentVoronoiModelNode = self.__voronoiModelNodeSelector.currentNode() if not currentModelNode: # we need a input volume node return 0 if not currentSeedsNode: # we need a seeds node return 0 if not currentOutputModelNode or currentOutputModelNode.GetID( ) == currentModelNode.GetID(): # we need a current model node, the display node is created later newModelNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelNode") newModelNode.SetScene(slicer.mrmlScene) newModelNode.SetName( slicer.mrmlScene.GetUniqueNameByString( self.__outputModelNodeSelector.baseName)) slicer.mrmlScene.AddNode(newModelNode) currentOutputModelNode = newModelNode self.__outputModelNodeSelector.setCurrentNode( currentOutputModelNode) if not currentVoronoiModelNode or currentVoronoiModelNode.GetID( ) == currentModelNode.GetID() or currentVoronoiModelNode.GetID( ) == currentOutputModelNode.GetID(): # we need a current model node, the display node is created later newModelNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelNode") newModelNode.SetScene(slicer.mrmlScene) newModelNode.SetName( slicer.mrmlScene.GetUniqueNameByString( self.__voronoiModelNodeSelector.baseName)) slicer.mrmlScene.AddNode(newModelNode) currentVoronoiModelNode = newModelNode self.__voronoiModelNodeSelector.setCurrentNode( currentVoronoiModelNode) # the output models preparedModel = vtk.vtkPolyData() model = vtk.vtkPolyData() network = vtk.vtkPolyData() voronoi = vtk.vtkPolyData() currentCoordinatesRAS = [0, 0, 0] # grab the current coordinates currentSeedsNode.GetFiducialCoordinates(currentCoordinatesRAS) # prepare the model preparedModel.DeepCopy(self.GetLogic().prepareModel( currentModelNode.GetPolyData())) preparedModel.Update() # decimate the model (only for network extraction) model.DeepCopy(self.GetLogic().decimateSurface(preparedModel)) model.Update() # open the model at the seed (only for network extraction) model.DeepCopy(self.GetLogic().openSurfaceAtPoint( model, currentCoordinatesRAS)) model.Update() # extract Network network.DeepCopy(self.GetLogic().extractNetwork(model)) network.Update() # # # not preview mode: real computation! if not preview: # here we start the actual centerline computation which is mathematically more robust and accurate but takes longer than the network extraction # clip surface at endpoints identified by the network extraction tupel = self.GetLogic().clipSurfaceAtEndPoints( network, currentModelNode.GetPolyData()) clippedSurface = tupel[0] endpoints = tupel[1] # now find the one endpoint which is closest to the seed and use it as the source point for centerline computation # all other endpoints are the target points sourcePoint = [0, 0, 0] # the following arrays have the same indexes and are synchronized at all times distancesToSeed = [] targetPoints = [] # we now need to loop through the endpoints two times # first loop is to detect the endpoint resulting in the tiny hole we poked in the surface # this is very close to our seed but not the correct sourcePoint for i in range(endpoints.GetNumberOfPoints()): currentPoint = endpoints.GetPoint(i) # get the euclidean distance currentDistanceToSeed = math.sqrt( math.pow((currentPoint[0] - currentCoordinatesRAS[0]), 2) + math.pow((currentPoint[1] - currentCoordinatesRAS[1]), 2) + math.pow((currentPoint[2] - currentCoordinatesRAS[2]), 2)) targetPoints.append(currentPoint) distancesToSeed.append(currentDistanceToSeed) # now we have a list of distances with the corresponding points # the index with the most minimal distance is the holePoint, we want to ignore it # the index with the second minimal distance is the point closest to the seed, we want to set it as sourcepoint # all other points are the targetpoints # get the index of the holePoint, which we want to remove from our endPoints holePointIndex = distancesToSeed.index(min(distancesToSeed)) # .. and remove it distancesToSeed.pop(holePointIndex) targetPoints.pop(holePointIndex) # now find the sourcepoint sourcePointIndex = distancesToSeed.index(min(distancesToSeed)) # .. and remove it after saving it as the sourcePoint sourcePoint = targetPoints[sourcePointIndex] distancesToSeed.pop(sourcePointIndex) targetPoints.pop(sourcePointIndex) # again, at this point we have a) the sourcePoint and b) a list of real targetPoints # now create the sourceIdList and targetIdList for the actual centerline computation sourceIdList = vtk.vtkIdList() targetIdList = vtk.vtkIdList() pointLocator = vtk.vtkPointLocator() pointLocator.SetDataSet(preparedModel) pointLocator.BuildLocator() # locate the source on the surface sourceId = pointLocator.FindClosestPoint(sourcePoint) sourceIdList.InsertNextId(sourceId) f = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLAnnotationFiducialNode") f.SetFiducialCoordinates(sourcePoint) f.Initialize(slicer.mrmlScene) f.SelectedOn() # locate the endpoints on the surface for p in targetPoints: f = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLAnnotationFiducialNode") f.SetFiducialCoordinates(p) f.Initialize(slicer.mrmlScene) id = pointLocator.FindClosestPoint(p) targetIdList.InsertNextId(id) tupel = self.GetLogic().computeCenterlines(preparedModel, sourceIdList, targetIdList) network.DeepCopy(tupel[0]) voronoi.DeepCopy(tupel[1]) # # # update the display of the original model in terms of opacity currentModelDisplayNode = currentModelNode.GetDisplayNode() if not currentModelDisplayNode: # create new displayNode currentModelDisplayNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelDisplayNode") slicer.mrmlScene.AddNode(currentModelDisplayNode) currentModelDisplayNode.SetOpacity(0.4) currentModelDisplayNode.Modified() currentModelDisplayNode.SetModifiedSinceRead(1) # update the reference between model node and it's display node currentModelNode.SetAndObserveDisplayNodeID( currentModelDisplayNode.GetID()) currentModelNode.Modified() currentModelNode.SetModifiedSinceRead(1) # # finally: # propagate output model to nodes currentOutputModelNode.SetAndObservePolyData(network) currentOutputModelNode.Modified() currentOutputModelNode.SetModifiedSinceRead(1) currentOutputModelDisplayNode = currentOutputModelNode.GetDisplayNode() if not currentOutputModelDisplayNode: # create new displayNode currentOutputModelDisplayNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelDisplayNode") slicer.mrmlScene.AddNode(currentOutputModelDisplayNode) # always configure the displayNode to show the model currentOutputModelDisplayNode.SetPolyData( currentOutputModelNode.GetPolyData()) currentOutputModelDisplayNode.SetColor(0.0, 0.0, 0.4) # red currentOutputModelDisplayNode.SetBackfaceCulling(0) currentOutputModelDisplayNode.SetSliceIntersectionVisibility(0) currentOutputModelDisplayNode.SetVisibility(1) currentOutputModelDisplayNode.SetOpacity(1.0) currentOutputModelDisplayNode.Modified() currentOutputModelDisplayNode.SetModifiedSinceRead(1) # update the reference between model node and it's display node currentOutputModelNode.SetAndObserveDisplayNodeID( currentOutputModelDisplayNode.GetID()) currentOutputModelNode.Modified() currentOutputModelNode.SetModifiedSinceRead(1) # only update the voronoi node if we are not in preview mode if not preview: currentVoronoiModelNode.SetAndObservePolyData(voronoi) currentVoronoiModelNode.Modified() currentVoronoiModelNode.SetModifiedSinceRead(1) currentVoronoiModelDisplayNode = currentVoronoiModelNode.GetDisplayNode( ) if not currentVoronoiModelDisplayNode: # create new displayNode currentVoronoiModelDisplayNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelDisplayNode") slicer.mrmlScene.AddNode(currentVoronoiModelDisplayNode) # always configure the displayNode to show the model currentVoronoiModelDisplayNode.SetPolyData( currentVoronoiModelNode.GetPolyData()) currentVoronoiModelDisplayNode.SetScalarVisibility(1) currentVoronoiModelDisplayNode.SetBackfaceCulling(0) currentVoronoiModelDisplayNode.SetActiveScalarName("Radius") currentVoronoiModelDisplayNode.SetAndObserveColorNodeID( slicer.mrmlScene.GetNodesByName("Labels").GetItemAsObject( 0).GetID()) currentVoronoiModelDisplayNode.SetSliceIntersectionVisibility(0) currentVoronoiModelDisplayNode.SetVisibility(1) currentVoronoiModelDisplayNode.SetOpacity(0.5) currentVoronoiModelDisplayNode.Modified() currentVoronoiModelDisplayNode.SetModifiedSinceRead(1) # update the reference between model node and it's display node currentVoronoiModelNode.SetAndObserveDisplayNodeID( currentVoronoiModelDisplayNode.GetID()) currentVoronoiModelNode.Modified() currentVoronoiModelNode.SetModifiedSinceRead(1) SlicerVmtk4CommonLib.Helper.Debug("End of Centerline Computation..")