Example #1
0
def get_thin_plate_spline_deform(input_target_mesh, input_source_mesh):
    ## sparsen boundary points to speed up computation
    # clean_ratio = 0.1
    # clean_data_polydata = vtk.vtkCleanPolyData()
    # clean_data_polydata.SetInputData(input_target_mesh)
    # clean_data_polydata.SetTolerance(clean_ratio)
    # clean_data_polydata.Update()
    # target_mesh = clean_data_polydata.GetOutput()
    
    # source_clean_data_polydata = vtk.vtkCleanPolyData()
    # source_clean_data_polydata.SetTolerance(clean_ratio)
    # source_clean_data_polydata.SetInputData(input_source_mesh)
    # source_clean_data_polydata.Update()
    # source_mesh = source_clean_data_polydata.GetOutput()

    target_mesh = input_target_mesh
    source_mesh = input_source_mesh
#    compute_distance_between_poly(target_mesh, source_mesh)
    source_pts = vtk.vtkPoints()
    target_pts = vtk.vtkPoints()
    for i in range(target_mesh.GetNumberOfPoints()):
        source_pts.InsertNextPoint(source_mesh.GetPoint(i))
        target_pts.InsertNextPoint(target_mesh.GetPoint(i))
    tps = vtk.vtkThinPlateSplineTransform()
    tps.SetSourceLandmarks(source_pts)
    tps.SetTargetLandmarks(target_pts)
    tps.SetBasisToR()
    tps.Modified()
    return tps
Example #2
0
    def __init__(self, sliceWidget):

        # keep a flag since events such as sliceNode modified
        # may come during superclass construction, which will
        # invoke our processEvents method
        self.initialized = False

        PointerEffectTool.__init__(self, sliceWidget)

        # interaction state variables
        self.activeSlice = None
        self.lastInsertSLiceNodeMTime = None
        self.actionState = None

        # initialization
        self.xyPoints = vtk.vtkPoints()
        self.rasPoints = vtk.vtkPoints()
        self.polyData = self.createPolyData()

        self.mapper = vtk.vtkPolyDataMapper2D()
        self.actor = vtk.vtkActor2D()
        self.mapper.SetInputData(self.polyData)
        self.actor.SetMapper(self.mapper)
        property_ = self.actor.GetProperty()
        property_.SetColor(1, 1, 0)
        property_.SetLineWidth(1)
        self.renderer.AddActor2D(self.actor)
        self.actors.append(self.actor)

        self.transform = vtk.vtkThinPlateSplineTransform()
        self.transform.SetBasisToR()
        self.transform.Inverse()
        self.auxNodes = []

        self.initialized = True
def spline(source_mesh, source_landmarks, target_landmarks):
    """
    Applies a thin plate spline transform to the source mesh

    “Principal warps: thin-plate splines and the decomposition of deformations”

    F. L. Bookstein

    :param source_mesh: vtkPolyData to be transformed
    :param source_landmarks: array of shape [n,3]
    :param target_landmarks: array of shape [n,3]
    :return: the transformed source mesh
    """

    src = utils.np_to_vtkPoints(source_landmarks)
    tar = utils.np_to_vtkPoints(target_landmarks)

    spline = vtk.vtkThinPlateSplineTransform()
    spline.SetBasisToR()
    spline.SetTargetLandmarks(tar)
    spline.SetSourceLandmarks(src)
    spline.Update()

    transform = vtk.vtkTransformPolyDataFilter()
    transform.SetTransform(spline)
    transform.SetInputData(source_mesh)
    transform.Update()

    return transform.GetOutput()
    def thinPlateSplineTransform(self, breastBoundPolyData,plane, modelNode):
        # Creates thin plate spline transform between target points
        # which are the breast boundary points (or code can be uncommented
        # to include more points) and the source points which are on
        # the plane of best fit

        # Target points using breast boundary points
        targetPoints = vtk.vtkPoints()
        for i in range(breastBoundPolyData.GetNumberOfPoints()):
            targetPoints.InsertNextPoint(breastBoundPolyData.GetPoint(i))

        # Create source point set for thin plate spline by getting points on plane
        sourcePoints = vtk.vtkPoints()
        sourcePointsPolyData = vtk.vtkPolyData()
        NumberOfPoints = targetPoints.GetNumberOfPoints()
        for i in range(NumberOfPoints):
            p = targetPoints.GetPoint(i)
            pProj = [0, 0, 0]
            plane.ProjectPoint(p, pProj)
            sourcePoints.InsertNextPoint(pProj)
        sourcePointsPolyData.SetPoints(sourcePoints)

        # creates a thinPlate spline transform between the target and source points
        splineTransform = vtk.vtkThinPlateSplineTransform()
        splineTransform.SetSourceLandmarks(sourcePoints)
        splineTransform.SetTargetLandmarks(targetPoints)
        splineTransform.SetBasisToR()  # Since our points are 3D

        return splineTransform
Example #5
0
def compute_thin_plate_spline_transform(source_points, target_points):
    """Produce an output vtkThinPlateSplineTransform.
    Input is a vtkPoints object of source (moving) landmarks and a vtkPoints
    object of target (fixed) landmarks.
    """
    vtktrans = vtk.vtkThinPlateSplineTransform()
    vtktrans.SetSourceLandmarks(source_points)
    vtktrans.SetTargetLandmarks(target_points)
    vtktrans.SetBasisToR()
    
    return vtktrans
    def DeformSurface(self):
        # interpolate and sample the displacement norms over the surface
        rbf = vtkvmtkcontrib.vtkvmtkRBFInterpolation2()
        rbf.SetSource(self.SourceSpheres)
        rbf.SetRBFTypeToBiharmonic()
        rbf.ComputeCoefficients()
        sampler = vtkvmtkcontrib.vtkvmtkPolyDataSampleFunction()
        sampler.SetInput(self.Surface)
        sampler.SetImplicitFunction(rbf)
        sampler.SetSampleArrayName("DisplacementNorms")
        sampler.Update()

        sampArray = sampler.GetOutput().GetPointData().GetArray("DisplacementNorms")

        ##Clamp the negative values to 0 and the positive values to one in a weight array
        calculator = vtk.vtkArrayCalculator()
        calculator.SetInput(sampler.GetOutput())
        calculator.AddScalarArrayName("DisplacementNorms")
        calculator.SetFunction("if( DisplacementNorms > 0 , iHat, jHat)")
        calculator.SetResultArrayName("Weights")
        calculator.SetResultArrayType(vtk.VTK_FLOAT)
        calculator.Update()

        # Create the transform
        thinPlateSplineTransform = vtk.vtkThinPlateSplineTransform()
        thinPlateSplineTransform.SetBasisToR()
        thinPlateSplineTransform.SetSourceLandmarks(self.SourcePoints)
        thinPlateSplineTransform.SetTargetLandmarks(self.TargetPoints)

        transform = vtk.vtkTransform()
        transform.Identity()
        transform2 = vtk.vtkTransform()
        transform2.Identity()

        # Apply weighted transform
        transformFilter = vtk.vtkWeightedTransformFilter()
        transformFilter.SetInput(calculator.GetOutput())
        transformFilter.SetNumberOfTransforms(3)
        transformFilter.SetWeightArray("Weights")
        transformFilter.SetTransform(thinPlateSplineTransform, 0)
        transformFilter.SetTransform(transform, 1)
        transformFilter.SetTransform(transform2, 2)
        transformFilter.Update()

        normalsFilter = vtk.vtkPolyDataNormals()
        normalsFilter.SetInput(transformFilter.GetOutput())
        normalsFilter.Update()

        # FIXME: the normal filter apparently introduced some holes in some meshes (wtf?). This filter cleans the mesh
        cleanFilter = vtk.vtkCleanPolyData()
        cleanFilter.SetInput(normalsFilter.GetOutput())
        cleanFilter.Update()

        self.DeformedSurface = cleanFilter.GetOutput()
Example #7
0
def warp(srcLandmark,dstLandmark,subj):
  tps = vtkThinPlateSplineTransform()
  tps.SetSourceLandmarks(srcLandmark.GetPoints())
  tps.SetTargetLandmarks(dstLandmark.GetPoints())
  tps.SetBasisToR()

  t1 = vtkGeneralTransform()
  t1.SetInput(tps)

  tf = vtkTransformPolyDataFilter()
  tf.SetInput(subj)
  tf.SetTransform(t1)
  tf.Update()

  warped = tf.GetOutput()
  return warped
Example #8
0
def warp(srcLandmark, dstLandmark, subj):
    tps = vtkThinPlateSplineTransform()
    tps.SetSourceLandmarks(srcLandmark.GetPoints())
    tps.SetTargetLandmarks(dstLandmark.GetPoints())
    tps.SetBasisToR()

    t1 = vtkGeneralTransform()
    t1.SetInput(tps)

    tf = vtkTransformPolyDataFilter()
    tf.SetInput(subj)
    tf.SetTransform(t1)
    tf.Update()

    warped = tf.GetOutput()
    return warped
Example #9
0
 def computePreviewWarp(self, sourceFiducial, targetFiducial):
     # points
     sourcePoints = vtk.vtkPoints()
     targetPoints = vtk.vtkPoints()
     # add drawing
     sourceFiducial.GetControlPointPositionsWorld(sourcePoints)
     targetFiducial.GetControlPointPositionsWorld(targetPoints)
     # thin plate
     transform = vtk.vtkThinPlateSplineTransform()
     transform.SetSourceLandmarks(sourcePoints)
     transform.SetTargetLandmarks(targetPoints)
     transform.SetBasisToR()
     transform.Inverse()
     transformNode = slicer.mrmlScene.AddNewNodeByClass(
         'vtkMRMLTransformNode')
     transformNode.SetAndObserveTransformFromParent(transform)
     return transformNode
Example #10
0
    def applyTPSTransform(self, sourcePoints, targetPoints, modelNode,
                          nodeName):
        transform = vtk.vtkThinPlateSplineTransform()
        transform.SetSourceLandmarks(sourcePoints)
        transform.SetTargetLandmarks(targetPoints)
        transform.SetBasisToR()  # for 3D transform

        transformFilter = vtk.vtkTransformPolyDataFilter()
        transformFilter.SetInputData(modelNode.GetPolyData())
        transformFilter.SetTransform(transform)
        transformFilter.Update()

        warpedPolyData = transformFilter.GetOutput()
        warpedModelNode = slicer.mrmlScene.AddNewNodeByClass(
            'vtkMRMLModelNode', nodeName)
        warpedModelNode.CreateDefaultDisplayNodes()
        warpedModelNode.SetAndObservePolyData(warpedPolyData)
        #self.RAS2LPSTransform(warpedModelNode)
        return warpedModelNode
def define_transform(source_landmarks, target_landmarks, volume_size=[1024, 1024, 1023]):

    """
    Defines a non-linear warp between a set of source and target landmarks

    Parameters
    ==========
    source_landmarks - np.ndarray (N x 3)
    target_landmarks - np.ndarray (N x 3)
    volume_size - list of x, y, z max dimensions

    Returns
    =======
    transform - vtkThinPlateSplineTransform

    """

    transform = vtk.vtkThinPlateSplineTransform()

    source_points = vtk.vtkPoints()
    target_points = vtk.vtkPoints()

    for x in [0,volume_size[0]]:
        for y in [0,volume_size[1]]:
            for z in [0,volume_size[2]]:
                source_points.InsertNextPoint([z,x,y])
                target_points.InsertNextPoint([z,x,y])

    for i in range(source_landmarks.shape[0]):
        if source_landmarks[i,0] > -1 and target_landmarks[i,0] > -1:
            source_points.InsertNextPoint(source_landmarks[i,:])
        
    for i in range(target_landmarks.shape[0]):
        if source_landmarks[i,0] > -1 and target_landmarks[i,0] > -1:
            target_points.InsertNextPoint(target_landmarks[i,:])

    transform.SetBasisToR() # for 3D transform
    transform.SetSourceLandmarks(source_points)
    transform.SetTargetLandmarks(target_points)
    transform.Update()

    return transform
Example #12
0
  def performThinPlateRegistration(self, state, landmarks):
    """Perform the thin plate transform using the vtkThinPlateSplineTransform class"""

    volumeNodes = (state.fixed, state.moving)
    fiducialNodes = (state.fixedFiducials,state.movingFiducials)
    points = state.logic.vtkPointsForVolumes( volumeNodes, fiducialNodes )

    # since this is a resample transform, source is the fixed (resampling target) space
    # and moving is the target space
    if not self.thinPlateTransform:
      self.thinPlateTransform = vtk.vtkThinPlateSplineTransform()
    self.thinPlateTransform.SetBasisToR() # for 3D transform
    self.thinPlateTransform.SetSourceLandmarks(points[state.moving])
    self.thinPlateTransform.SetTargetLandmarks(points[state.fixed])
    self.thinPlateTransform.Update()

    if points[state.moving].GetNumberOfPoints() != points[state.fixed].GetNumberOfPoints():
      raise hell

    state.transform.SetAndObserveTransformToParent(self.thinPlateTransform)
Example #13
0
    def runCleaning(self, projectedLM, sphere, spacingPercentage):
        # Convert projected surface points to a VTK array for transform
        p = [0, 0, 0]
        targetPoints = vtk.vtkPoints()
        for i in range(projectedLM.GetNumberOfFiducials()):
            projectedLM.GetMarkupPoint(0, i, p)
            targetPoints.InsertNextPoint(p)

        # Set up a transform between the sphere and the points projected to the surface
        transform = vtk.vtkThinPlateSplineTransform()
        transform.SetSourceLandmarks(sphere.GetPolyData().GetPoints())
        transform.SetTargetLandmarks(targetPoints)
        transform.SetBasisToR()

        # Apply the transform to the sphere to create a model with spherical topology
        transformNode = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLTransformNode", "TPS")
        transformNode.SetAndObserveTransformToParent(transform)
        sphere.SetAndObserveTransformNodeID(transformNode.GetID())
        slicer.vtkSlicerTransformLogic().hardenTransform(sphere)
        sphere.SetDisplayVisibility(False)

        # Clean up semi-landmarks within radius
        filter = vtk.vtkCleanPolyData()
        filter.SetToleranceIsAbsolute(False)
        filter.SetTolerance(spacingPercentage / 2)
        filter.SetInputData(sphere.GetPolyData())
        filter.Update()
        cleanPolyData = filter.GetOutput()

        # Create a landmark node from the cleaned polyData
        sphereSampleLMNode = slicer.mrmlScene.AddNewNodeByClass(
            'vtkMRMLMarkupsFiducialNode', "PseudoLandmarks")
        sphereSampleLMNode.CreateDefaultDisplayNodes()
        for i in range(cleanPolyData.GetNumberOfPoints()):
            point = cleanPolyData.GetPoint(i)
            sphereSampleLMNode.AddFiducialFromArray(point)

        landmarkTypeSemi = True
        self.setAllLandmarksType(sphereSampleLMNode, landmarkTypeSemi)
        return sphereSampleLMNode
Example #14
0
    def SurfaceXRayRegistration(self, szeLMReader, wrlLMReader, szeReader):

        # Rotate surface because it is not aligned with landmarks
        self.AlignSurfaceLM(szeReader)

        # 1st register the topo to the xray using tps and external landmarks
        thin_plate_trans = vtk.vtkThinPlateSplineTransform()
        thin_plate_trans.SetSourceLandmarks(szeLMReader.points)
        thin_plate_trans.SetTargetLandmarks(wrlLMReader.capteurs_points)
        thin_plate_trans.SetBasisToR2LogR()
        thin_plate_trans.Update()

        # Apply transformation to landmarks
        self.ApplyTransform(szeLMReader.actor, thin_plate_trans)
        print(
            "-----Performance Metrics of Surface Topography to X-Ray using Thin Plate Spline Registration-----"
        )
        self.getMetrics(szeLMReader, wrlLMReader, thin_plate_trans)
        # Apply transformation to Surface
        self.ApplyTransform(szeReader.actorCopy, thin_plate_trans)
        self.ApplyTransform(szeReader.actor, thin_plate_trans)
    def performThinPlateRegistration(self, state, landmarks):
        """Perform the thin plate transform using the vtkThinPlateSplineTransform class"""

        volumeNodes = (state.fixed, state.moving)
        fiducialNodes = (state.fixedFiducials, state.movingFiducials)
        points = state.logic.vtkPointsForVolumes(volumeNodes, fiducialNodes)

        # since this is a resample transform, source is the fixed (resampling target) space
        # and moving is the target space
        if not self.thinPlateTransform:
            self.thinPlateTransform = vtk.vtkThinPlateSplineTransform()
        self.thinPlateTransform.SetBasisToR()  # for 3D transform
        self.thinPlateTransform.SetSourceLandmarks(points[state.moving])
        self.thinPlateTransform.SetTargetLandmarks(points[state.fixed])
        self.thinPlateTransform.Update()

        if points[state.moving].GetNumberOfPoints() != points[
                state.fixed].GetNumberOfPoints():
            raise hell

        state.transform.SetAndObserveTransformToParent(self.thinPlateTransform)
Example #16
0
def previewWarp(sourceNode, targetNode, outNode):
    # points
    sourcePoints = vtk.vtkPoints()
    sourceNode.GetControlPointPositionsWorld(sourcePoints)
    targetPoints = vtk.vtkPoints()
    targetNode.GetControlPointPositionsWorld(targetPoints)
    # thin plate
    transform = vtk.vtkThinPlateSplineTransform()
    transform.SetSourceLandmarks(sourcePoints)
    transform.SetTargetLandmarks(targetPoints)
    transform.SetBasisToR()
    transform.Inverse()
    transformNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLTransformNode')
    transformNode.SetAndObserveTransformFromParent(transform)
    # display
    transformNode.CreateDefaultDisplayNodes()
    transformNode.GetDisplayNode().SetVisibility(1)
    transformNode.GetDisplayNode().SetVisibility3D(0)
    transformNode.GetDisplayNode().SetAndObserveGlyphPointsNode(sourceNode)
    transformNode.GetDisplayNode().SetVisibility2D(1)
    delay()  # update display
    return transformNode
    def __init__(self, sliceWidget):

        # keep a flag since events such as sliceNode modified
        # may come during superclass construction, which will
        # invoke our processEvents method
        self.initialized = False

        AbstractCircleEffect.__init__(self, sliceWidget)

        # interaction state variables
        self.actionState = None

        # initialization
        self.xyPoints = vtk.vtkPoints()
        self.rasPoints = vtk.vtkPoints()

        self.transform = vtk.vtkThinPlateSplineTransform()
        self.transform.SetBasisToR()
        self.transform.Inverse()
        self.auxNodes = []

        self.initialized = True
Example #18
0
 def previewWarp(self, source, target):
     if isinstance(source,
                   slicer.vtkMRMLMarkupsFiducialNode) and isinstance(
                       target, slicer.vtkMRMLMarkupsFiducialNode):
         sourcePoints = vtk.vtkPoints()
         targetPoints = vtk.vtkPoints()
         for i in range(target.GetNumberOfControlPoints()):
             if target.GetNthControlPointSelected(i):
                 sourcePoints.InsertNextPoint(
                     source.GetNthControlPointPosition(i))
                 targetPoints.InsertNextPoint(
                     target.GetNthControlPointPosition(i))
     else:
         sourcePoints = source
         targetPoints = target
     sourceDisplayFiducial = slicer.mrmlScene.AddNewNodeByClass(
         'vtkMRMLMarkupsFiducialNode')
     sourceDisplayFiducial.GetDisplayNode().SetVisibility(0)
     sourceDisplayFiducial.SetControlPointPositionsWorld(sourcePoints)
     # thin plate
     transform = vtk.vtkThinPlateSplineTransform()
     transform.SetSourceLandmarks(sourcePoints)
     transform.SetTargetLandmarks(targetPoints)
     transform.SetBasisToR()
     transform.Inverse()
     transformNode = slicer.mrmlScene.AddNewNodeByClass(
         'vtkMRMLTransformNode')
     transformNode.SetAndObserveTransformFromParent(transform)
     # display
     transformNode.CreateDefaultDisplayNodes()
     transformNode.GetDisplayNode().SetVisibility(1)
     transformNode.GetDisplayNode().SetVisibility3D(0)
     transformNode.GetDisplayNode().SetAndObserveGlyphPointsNode(
         sourceDisplayFiducial)
     transformNode.GetDisplayNode().SetVisibility2D(1)
     return transformNode, sourceDisplayFiducial
Example #19
0
    def warp(self, sourcePts=(), targetPts=(), transform=None, sigma=1,
             mirroring=False, bc='w', alpha=1):
        """
        Warp an image using thin-plate splines.

        Parameters
        ----------
        sourcePts : list, optional
            source points.
        targetPts : list, optional
            target points.
        transform : TYPE, optional
            a vtkTransform object can be supplied. The default is None.
        sigma : float, optional
            stiffness of the interpolation. The default is 1.
        mirroring : TYPE, optional
            fill the margins with a reflection of the original image. The default is False.
        bc : TYPE, optional
            fill the margins with a solid color. The default is 'w'.
        alpha : TYPE, optional
            opacity of the filled margins. The default is 1.
        """
        if transform is None:
            # source and target must be filled
            transform = vtk.vtkThinPlateSplineTransform()
            transform.SetBasisToR2LogR()
            if isinstance(sourcePts, vedo.Points):
                sourcePts = sourcePts.points()
            if isinstance(targetPts, vedo.Points):
                targetPts = targetPts.points()

            ns = len(sourcePts)
            nt = len(targetPts)
            if ns != nt:
                colors.printc("Error in picture.warp(): #source != #target points", ns, nt, c='r')
                raise RuntimeError()

            ptsou = vtk.vtkPoints()
            ptsou.SetNumberOfPoints(ns)

            pttar = vtk.vtkPoints()
            pttar.SetNumberOfPoints(nt)

            for i in range(ns):
                p = sourcePts[i]
                ptsou.SetPoint(i, [p[0],p[1],0])
                p = targetPts[i]
                pttar.SetPoint(i, [p[0],p[1],0])

            transform.SetSigma(sigma)
            transform.SetSourceLandmarks(pttar)
            transform.SetTargetLandmarks(ptsou)
        else:
            # ignore source and target
            pass

        reslice = vtk.vtkImageReslice()
        reslice.SetInputData(self._data)
        reslice.SetOutputDimensionality(2)
        reslice.SetResliceTransform(transform)
        reslice.SetInterpolationModeToCubic()
        reslice.SetMirror(mirroring)
        c = np.array(colors.getColor(bc))*255
        reslice.SetBackgroundColor([c[0],c[1],c[2], alpha*255])
        reslice.Update()
        self.transform = transform
        return self._update(reslice.GetOutput())
    def __init__(self):
        """
    Called when the logic class is instantiated. Can be used for initializing member variables.
    """
        ScriptedLoadableModuleLogic.__init__(self)

        self.inputCurveNode = None
        self.inputCurveNodeObservations = []
        self.inputSurfacePointsNode = None
        self.inputSurfacePointsNodeObservations = []

        self.numberOfCurveLandmarkPoints = 80

        self.printThreeDViewNode = None
        self.printThreeDWidget = None
        self.printViewWidth = 1024
        self.printViewHeight = 1024
        self.printXResolutionDpi = 300
        self.printYResolutionDpi = 300
        self.printScale = 2.0  #TODO: Workaround for scaling problem, see https://github.com/SlicerFab/SlicerFab/issues/13
        self.printTransparentBackground = False

        # Create triangulated flat disk that will be warped

        self.surfaceUnitDisk = vtk.vtkDiskSource()
        self.surfaceUnitDisk.SetOuterRadius(1.0)
        self.surfaceUnitDisk.SetInnerRadius(0.0)
        self.surfaceUnitDisk.SetCircumferentialResolution(
            self.numberOfCurveLandmarkPoints)
        self.surfaceUnitDisk.SetRadialResolution(60)

        self.surfaceTriangulator = vtk.vtkDelaunay2D()
        self.surfaceTriangulator.SetTolerance(
            0.01
        )  # get rid of the small triangles near the center of the unit disk
        self.surfaceTriangulator.SetInputConnection(
            self.surfaceUnitDisk.GetOutputPort())

        # Prepare transform object

        # points on the unit disk (circumference and surface)
        self.surfaceTransformSourcePoints = vtk.vtkPoints()

        self.surfaceTransformSourceCurvePoints = vtk.vtkPoints()
        self.surfaceTransformSourceCurvePoints.SetNumberOfPoints(
            self.numberOfCurveLandmarkPoints)
        import math
        angleIncrement = 2.0 * math.pi / float(
            self.numberOfCurveLandmarkPoints)
        for pointIndex in range(self.numberOfCurveLandmarkPoints):
            angle = float(pointIndex) * angleIncrement
            self.surfaceTransformSourceCurvePoints.SetPoint(
                pointIndex, math.cos(angle), math.sin(angle), 0)

        # points on the warped surface (curve points and surface points)
        self.surfaceTransformTargetPoints = vtk.vtkPoints()

        self.surfaceTransform = vtk.vtkThinPlateSplineTransform()
        self.surfaceTransform.SetSourceLandmarks(
            self.surfaceTransformSourcePoints)
        self.surfaceTransform.SetTargetLandmarks(
            self.surfaceTransformTargetPoints)

        # Transform polydata

        self.surfaceTransformFilter = vtk.vtkTransformPolyDataFilter()
        self.surfaceTransformFilter.SetTransform(self.surfaceTransform)
        self.surfaceTransformFilter.SetInputConnection(
            self.surfaceTriangulator.GetOutputPort())

        self.cleanPolyDataFilter = vtk.vtkCleanPolyData()
        self.cleanPolyDataFilter.SetInputConnection(
            self.surfaceTransformFilter.GetOutputPort())

        #

        self.surfacePolyDataNormalsThin = vtk.vtkPolyDataNormals()
        self.surfacePolyDataNormalsThin.SetInputConnection(
            self.cleanPolyDataFilter.GetOutputPort())
        # There are a few triangles in the triangulated unit disk with inconsistent
        # orientation. Enabling consistency check fixes them.
        self.surfacePolyDataNormalsThin.ConsistencyOn(
        )  # TODO: check if needed, probably not
        self.surfacePolyDataNormalsThin.SplittingOff(
        )  # this prevents stray normals at the edge  TODO: check

        # Add thickness to warped surface (if needed)

        # self.surfacePolyDataNormals = vtk.vtkPolyDataNormals()
        # self.surfacePolyDataNormals.SetInputConnection(self.cleanPolyDataFilter.GetOutputPort())
        # self.surfacePolyDataNormals.SplittingOff()  # this prevents stray normals at the edge  TODO: check

        self.surfaceOffset = vtk.vtkWarpVector()
        self.surfaceOffset.SetInputConnection(
            self.surfacePolyDataNormalsThin.GetOutputPort())
        self.surfaceOffset.SetInputArrayToProcess(
            0, 0, 0, vtk.vtkDataObject.FIELD_ASSOCIATION_POINTS,
            vtk.vtkDataSetAttributes.NORMALS)

        self.surfaceExtrude = vtk.vtkLinearExtrusionFilter()
        self.surfaceExtrude.SetInputConnection(
            self.surfaceOffset.GetOutputPort())
        self.surfaceExtrude.SetExtrusionTypeToNormalExtrusion()

        self.surfacePolyDataNormalsThick = vtk.vtkPolyDataNormals()
        self.surfacePolyDataNormalsThick.SetInputConnection(
            self.surfaceExtrude.GetOutputPort())
        self.surfacePolyDataNormalsThick.AutoOrientNormalsOn()
Example #21
0
    def run(self, meshNode, LMNode, gridLandmarks, sampleRate):
        surfacePolydata = meshNode.GetPolyData()

        gridPoints = vtk.vtkPoints()

        gridPoints.InsertNextPoint(0, 0, 0)
        gridPoints.InsertNextPoint(0, sampleRate - 1, 0)
        gridPoints.InsertNextPoint(sampleRate - 1, 0, 0)
        for row in range(1, sampleRate - 1):
            for col in range(1, sampleRate - 1):
                if (row + col) < (sampleRate - 1):
                    gridPoints.InsertNextPoint(row, col, 0)

        gridPolydata = vtk.vtkPolyData()
        gridPolydata.SetPoints(gridPoints)

        sourcePoints = vtk.vtkPoints()
        targetPoints = vtk.vtkPoints()

        #sourcePoints.InsertNextPoint(gridPoints.GetPoint(0))
        #sourcePoints.InsertNextPoint(gridPoints.GetPoint(sampleRate-1))
        #sourcePoints.InsertNextPoint(gridPoints.GetPoint(gridPoints.GetNumberOfPoints()-1))
        sourcePoints.InsertNextPoint(gridPoints.GetPoint(0))
        sourcePoints.InsertNextPoint(gridPoints.GetPoint(1))
        sourcePoints.InsertNextPoint(gridPoints.GetPoint(2))

        point = [0, 0, 0]
        for gridVertex in gridLandmarks:
            LMNode.GetMarkupPoint(int(gridVertex - 1), 0, point)
            targetPoints.InsertNextPoint(point)

        #transform grid to triangle
        transform = vtk.vtkThinPlateSplineTransform()
        transform.SetSourceLandmarks(sourcePoints)
        transform.SetTargetLandmarks(targetPoints)
        transform.SetBasisToR()

        transformNode = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLTransformNode", "TPS")
        transformNode.SetAndObserveTransformToParent(transform)

        model = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLModelNode",
                                                   "mesh_resampled")
        model.SetAndObservePolyData(gridPolydata)
        model.SetAndObserveTransformNodeID(transformNode.GetID())
        slicer.vtkSlicerTransformLogic().hardenTransform(model)

        resampledPolydata = model.GetPolyData()

        pointLocator = vtk.vtkPointLocator()
        pointLocator.SetDataSet(surfacePolydata)
        pointLocator.BuildLocator()

        #get surface normal from each landmark point
        rayDirection = [0, 0, 0]
        normalArray = surfacePolydata.GetPointData().GetArray("Normals")
        if (not normalArray):
            normalFilter = vtk.vtkPolyDataNormals()
            normalFilter.ComputePointNormalsOn()
            normalFilter.SetInputData(surfacePolydata)
            normalFilter.Update()
            normalArray = normalFilter.GetOutput().GetPointData().GetArray(
                "Normals")
            if (not normalArray):
                print("Error: no normal array")

        for gridVertex in gridLandmarks:
            LMNode.GetMarkupPoint(int(gridVertex - 1), 0, point)
            closestPointId = pointLocator.FindClosestPoint(point)
            tempNormal = normalArray.GetTuple(closestPointId)
            rayDirection[0] += tempNormal[0]
            rayDirection[1] += tempNormal[1]
            rayDirection[2] += tempNormal[2]

        #calculate average
        for dim in range(len(rayDirection)):
            rayDirection[dim] = rayDirection[dim] / 4

        #set up locater for intersection with normal vector rays
        obbTree = vtk.vtkOBBTree()
        obbTree.SetDataSet(surfacePolydata)
        obbTree.BuildLocator()

        #define new landmark sets
        semilandmarkNodeName = "semiLM_" + str(gridLandmarks[0]) + "_" + str(
            gridLandmarks[1]) + "_" + str(gridLandmarks[2])
        semilandmarkPoints = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLMarkupsFiducialNode", semilandmarkNodeName)

        #get a sample distance for quality control
        m1 = model.GetPolyData().GetPoint(0)
        m2 = model.GetPolyData().GetPoint(1)
        m3 = model.GetPolyData().GetPoint(1)
        d1 = math.sqrt(vtk.vtkMath().Distance2BetweenPoints(m1, m2))
        d2 = math.sqrt(vtk.vtkMath().Distance2BetweenPoints(m2, m3))
        d3 = math.sqrt(vtk.vtkMath().Distance2BetweenPoints(m1, m3))
        sampleDistance = (d1 + d2 + d3)

        # set initial three grid points
        for index in range(0, 3):
            origLMPoint = resampledPolydata.GetPoint(index)
            #landmarkLabel = LMNode.GetNthFiducialLabel(gridLandmarks[index]-1)
            landmarkLabel = str(gridLandmarks[index])
            semilandmarkPoints.AddFiducialFromArray(origLMPoint, landmarkLabel)

        # calculate maximum projection distance
        projectionTolerance = 2
        boundingBox = vtk.vtkBoundingBox()
        boundingBox.AddBounds(surfacePolydata.GetBounds())
        diagonalDistance = boundingBox.GetDiagonalLength()
        #rayLength = math.sqrt(diagonalDistance) * projectionTolerance
        rayLength = sampleDistance

        # get normal projection intersections for remaining semi-landmarks
        print("Target number of points: ",
              resampledPolydata.GetNumberOfPoints())
        for index in range(3, resampledPolydata.GetNumberOfPoints()):
            modelPoint = resampledPolydata.GetPoint(index)
            rayEndPoint = [0, 0, 0]
            for dim in range(len(rayEndPoint)):
                rayEndPoint[
                    dim] = modelPoint[dim] + rayDirection[dim] * rayLength
            intersectionIds = vtk.vtkIdList()
            intersectionPoints = vtk.vtkPoints()
            obbTree.IntersectWithLine(modelPoint, rayEndPoint,
                                      intersectionPoints, intersectionIds)
            #if there are intersections, update the point to most external one.
            if intersectionPoints.GetNumberOfPoints() > 0:
                exteriorPoint = intersectionPoints.GetPoint(
                    intersectionPoints.GetNumberOfPoints() - 1)
                #projectionDistance=math.sqrt(vtk.vtkMath().Distance2BetweenPoints(exteriorPoint, modelPoint))
                semilandmarkPoints.AddFiducialFromArray(exteriorPoint)
            #if there are no intersections, reverse the normal vector
            else:
                for dim in range(len(rayEndPoint)):
                    rayEndPoint[
                        dim] = modelPoint[dim] + rayDirection[dim] * -rayLength
                obbTree.IntersectWithLine(modelPoint, rayEndPoint,
                                          intersectionPoints, intersectionIds)
                if intersectionPoints.GetNumberOfPoints() > 0:
                    exteriorPoint = intersectionPoints.GetPoint(0)
                    semilandmarkPoints.AddFiducialFromArray(exteriorPoint)
                    #projectionDistance=math.sqrt(vtk.vtkMath().Distance2BetweenPoints(exteriorPoint, modelPoint))
                    #if projectionDistance < sampleDistance:
                    #  semilandmarkPoints.AddFiducialFromArray(exteriorPoint)
                    #else:
                    #  closestPointId = pointLocator.FindClosestPoint(modelPoint)
                    #  rayOrigin = surfacePolydata.GetPoint(closestPointId)
                    #  semilandmarkPoints.AddFiducialFromArray(rayOrigin)

                #if none in reverse direction, use closest mesh point
                else:
                    closestPointId = pointLocator.FindClosestPoint(modelPoint)
                    rayOrigin = surfacePolydata.GetPoint(closestPointId)
                    semilandmarkPoints.AddFiducialFromArray(rayOrigin)

        # update lock status and color
        semilandmarkPoints.SetLocked(True)
        semilandmarkPoints.GetDisplayNode().SetColor(random.random(),
                                                     random.random(),
                                                     random.random())
        semilandmarkPoints.GetDisplayNode().SetSelectedColor(
            random.random(), random.random(), random.random())
        semilandmarkPoints.GetDisplayNode().PointLabelsVisibilityOff()
        #clean up
        slicer.mrmlScene.RemoveNode(transformNode)
        slicer.mrmlScene.RemoveNode(model)
        print("Total points:", semilandmarkPoints.GetNumberOfFiducials())
        return semilandmarkPoints
Example #22
0
    def run(self, templateMesh, templateLM, templateSLM, meshDirectory,
            lmDirectory, slmDirectory, outDirectory, signedDistanceOption):

        if (bool(templateSLM) and bool(slmDirectory)):
            templateLMTotal = self.mergeLandmarks(templateLM, templateSLM)
        else:
            templateLMTotal = templateLM
        #get template points as vtk array
        templatePoints = vtk.vtkPoints()
        p = [0, 0, 0]
        for i in range(templateLMTotal.GetNumberOfMarkups()):
            templateLMTotal.GetMarkupPoint(0, i, p)
            templatePoints.InsertNextPoint(p)

        # write selected triangles to table
        tableNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLTableNode',
                                                       'Mean Mesh Distances')
        col1 = tableNode.AddColumn()
        col1.SetName('Subject ID')
        col2 = tableNode.AddColumn()
        col2.SetName('Mesh RMSE')
        tableNode.SetColumnType('Subject ID', vtk.VTK_STRING)
        tableNode.SetColumnType('Mean Mesh Distance', vtk.VTK_STRING)

        subjectCount = 0
        for meshFileName in os.listdir(meshDirectory):
            if (not meshFileName.startswith(".")):
                #get corresponding landmarks
                lmFilePath, subjectID = self.findCorrespondingFilePath(
                    lmDirectory, meshFileName)
                if (lmFilePath):
                    currentLMNode = slicer.util.loadMarkupsFiducialList(
                        lmFilePath)
                    if bool(slmDirectory):  # add semi-landmarks if present
                        slmFilePath, sID = self.findCorrespondingFilePath(
                            slmDirectory, meshFileName)
                        if (slmFilePath):
                            currentSLMNode = slicer.util.loadMarkupsFiducialList(
                                slmFilePath)
                            currentLMTotal = self.mergeLandmarks(
                                templateLM, currentSLMNode)
                        else:
                            print("problem with reading semi-landmarks")
                            return False
                    else:
                        currentLMTotal = currentLMNode
                else:
                    print("problem with reading landmarks")
                    return False
                    # if mesh and lm file with same subject id exist, load into scene
                meshFilePath = os.path.join(meshDirectory, meshFileName)
                currentMeshNode = slicer.util.loadModel(meshFilePath)

                #get subject points into vtk array
                subjectPoints = vtk.vtkPoints()
                p = [0, 0, 0]
                for i in range(currentLMTotal.GetNumberOfMarkups()):
                    currentLMTotal.GetMarkupPoint(0, i, p)
                    subjectPoints.InsertNextPoint(p)

                transform = vtk.vtkThinPlateSplineTransform()
                transform.SetSourceLandmarks(subjectPoints)
                transform.SetTargetLandmarks(templatePoints)
                transform.SetBasisToR()  # for 3D transform

                transformNode = slicer.mrmlScene.AddNewNodeByClass(
                    "vtkMRMLTransformNode", "TPS")
                transformNode.SetAndObserveTransformToParent(transform)

                currentMeshNode.SetAndObserveTransformNodeID(
                    transformNode.GetID())
                slicer.vtkSlicerTransformLogic().hardenTransform(
                    currentMeshNode)

                distanceFilter = vtk.vtkDistancePolyDataFilter()
                distanceFilter.SetInputData(0, templateMesh.GetPolyData())
                distanceFilter.SetInputData(1, currentMeshNode.GetPolyData())
                distanceFilter.SetSignedDistance(signedDistanceOption)
                distanceFilter.Update()

                distanceMap = distanceFilter.GetOutput()
                distanceArray = distanceMap.GetPointData().GetArray('Distance')
                #meanDistance = np.average(distanceArray)
                meanDistance = self.rmse(distanceArray)

                #save output distance map
                outputNode = slicer.mrmlScene.AddNewNodeByClass(
                    "vtkMRMLModelNode", "ouputDistanceMap")
                outputNode.SetAndObservePolyData(distanceMap)
                outputFilename = os.path.join(outDirectory,
                                              str(subjectID) + '.vtp')
                slicer.util.saveNode(outputNode, outputFilename)

                #update table and subjectCount
                tableNode.AddEmptyRow()
                tableNode.SetCellText(subjectCount, 0, str(subjectID))
                tableNode.SetCellText(subjectCount, 1, str(meanDistance))
                subjectCount += 1

                # clean up
                slicer.mrmlScene.RemoveNode(outputNode)
                slicer.mrmlScene.RemoveNode(transformNode)
                slicer.mrmlScene.RemoveNode(currentMeshNode)
                slicer.mrmlScene.RemoveNode(currentLMNode)
Example #23
0
def volumetric_spline_augmentation():
    out_name = 'C:/Users/lakri/Documents/BachelorProjekt/Spares MeshCNN/MeshCNN_sparse/datasets/DataAug/0079aug.vtk'
    file_name = 'C:/Users/lakri/Documents/BachelorProjekt/Spares MeshCNN/MeshCNN_sparse/datasets/LAA_segmentation/0079.vtk'
    out_name_grid = 'C:/Users/lakri/Documents/BachelorProjekt/Spares MeshCNN/MeshCNN_sparse/datasets/DataAug/0079_grid.vtk'
    out_name_grid_warped = 'C:/Users/lakri/Documents/BachelorProjekt/Spares MeshCNN/MeshCNN_sparse/datasets/DataAug/0079_grid_warped.vtk'

    pd_in = vtk.vtkPolyDataReader()
    pd_in.SetFileName(file_name)
    pd_in.Update()

    pd = pd_in.GetOutput()

    grid_3d = create_3d_grid(pd)
    print('writing grid')
    writer = vtk.vtkPolyDataWriter()
    writer.SetFileName(out_name_grid)
    writer.SetInputData(grid_3d)
    writer.Write()
    print('done writing')

    # Get bounding box
    bounds = pd.GetBounds()
    x_min = bounds[0]
    x_max = bounds[1]
    y_min = bounds[2]
    y_max = bounds[3]
    z_min = bounds[4]
    z_max = bounds[5]

    # get a measure of scale as the diagonal length
    scale = math.sqrt((x_max - x_min) * (x_max - x_min) + (y_max - y_min) *
                      (y_max - y_min) + (z_max - z_min) * (z_max - z_min))

    # Reference points
    # Here just corners of the bounding box
    # TODO: make more points
    n = 8
    i = 0
    p1 = vtk.vtkPoints()
    p1.SetNumberOfPoints(n * n * n)

    xlin = np.linspace(x_min, x_max, n)
    ylin = np.linspace(y_min, y_max, n)
    zlin = np.linspace(z_min, z_max, n)

    for x in xlin:
        for y in ylin:
            for z in zlin:
                p1.SetPoint(i, x, y, z)
                i += 1
    '''
    p1.SetPoint(0, x_min, y_min, z_min)
    p1.SetPoint(1, x_max, y_min, z_min)
    p1.SetPoint(2, x_min, y_max, z_min)
    p1.SetPoint(3, x_max, y_max, z_min)
    p1.SetPoint(4, x_min, y_min, z_max)
    p1.SetPoint(5, x_max, y_min, z_max)
    p1.SetPoint(6, x_min, y_max, z_max)
    p1.SetPoint(7, x_max, y_max, z_max)
    '''
    # Deformed points
    p2 = vtk.vtkPoints()
    # Start by copying all info from p1
    p2.DeepCopy(p1)

    # Displace the points in a random direction
    displacement_length = scale * 0.03  #change parameter around a bit
    for i in range(p2.GetNumberOfPoints()):
        p = list(p2.GetPoint(i))
        for j in range(3):
            p[j] = p[j] + (2.0 * random() - 1) * displacement_length
        p2.SetPoint(i, p)

    transform = vtk.vtkThinPlateSplineTransform()
    transform.SetSourceLandmarks(p1)
    transform.SetTargetLandmarks(p2)
    transform.SetBasisToR2LogR()
    transform.Update()

    transform_filter = vtk.vtkTransformPolyDataFilter()
    transform_filter.SetTransform(transform)
    transform_filter.SetInputData(pd)
    transform_filter.Update()

    vs = np.array(transform_filter.GetOutput().GetPoints().GetData())
    face_labels = np.array(
        transform_filter.GetOutput().GetCellData().GetScalars())
    poly = dsa.WrapDataObject(transform_filter.GetOutput()).Polygons
    faces = np.reshape(poly, (-1, 4))[:, 1:4]

    #vcolor = []
    print('writing aug mesh')
    with open(out_name, 'w+') as f:
        f.write(
            "# vtk DataFile Version 4.2 \nvtk output \nASCII \n \nDATASET POLYDATA \nPOINTS %d float \n"
            % len(vs))
        for vi, v in enumerate(vs):
            #vcol = ' %f %f %f' % (vcolor[vi, 0], vcolor[vi, 1], vcolor[vi, 2]) if vcolor is not None else ''
            f.write("%f %f %f\n" % (v[0], v[1], v[2]))
        f.write("POLYGONS %d %d \n" % (len(faces), 4 * len(faces)))
        for face_id in range(len(faces) - 1):
            f.write("3 %d %d %d\n" %
                    (faces[face_id][0], faces[face_id][1], faces[face_id][2]))
        f.write("3 %d %d %d" % (faces[-1][0], faces[-1][1], faces[-1][2]))
        f.write(
            "\n \nCELL_DATA %d \nSCALARS scalars double \nLOOKUP_TABLE default"
            % len(faces))
        for j, face in enumerate(faces):
            if j % 9 == 0:
                f.write("\n")
            f.write("%d " % face_labels[j])
    print('done writing')

    transform_filter_grid = vtk.vtkTransformPolyDataFilter()
    transform_filter_grid.SetTransform(transform)
    transform_filter_grid.SetInputData(grid_3d)
    transform_filter_grid.Update()

    #grid_points = np.array( transform_filter.GetOutput().GetPoints().GetData() )
    #grid_lines = np.array( transform_filter.GetOutput().GetLines().GetData() )
    #poly = dsa.WrapDataObject(transform_filter.GetOutput()).Polygons
    #faces = np.reshape(poly,(-1,4))[:,1:4]

    #print('writing warped grid')
    #with open(out_name, 'w+') as f:
    #f.write("# vtk DataFile Version 4.2 \nvtk output \nASCII \n \nDATASET POLYDATA \nPOINTS %d float \n" % len(grid_points))
    #for vi, v in enumerate(grid_points):
    #vcol = ' %f %f %f' % (vcolor[vi, 0], vcolor[vi, 1], vcolor[vi, 2]) if vcolor is not None else ''
    #f.write("%f %f %f\n" % (v[0], v[1], v[2]))
    #f.write("LINES %d %d \n" % (len(grid_lines),2*len(grid_lines)-1))
    #for lines_id in range(len(grid_lines) - 1):
    #f.write("3 %d %d %d\n" % (grid_lines[face_id][0] , faces[face_id][1], faces[face_id][2]))
    #f.write("3 %d %d %d" % (faces[-1][0], faces[-1][1], faces[-1][2]))
    #f.write("\n \nCELL_DATA %d \nSCALARS scalars double \nLOOKUP_TABLE default" % len(faces))
    #for j,face in enumerate(faces):
    #if j%9 == 0:
    #f.write("\n")
    #f.write("%d " % face_labels[j])
    #print('done writing')

    filt = vtk.vtkConnectivityFilter()

    filt.SetInputData(grid_3d)  # get the data from the MC alg.

    #filt.ColorRegionsOn()
    filt.Update()

    ren = vtk.vtkRenderer()
    renWin = vtk.vtkRenderWindow()
    renWin.AddRenderer(ren)
    WIDTH = 640
    HEIGHT = 480
    renWin.SetSize(WIDTH, HEIGHT)

    #create a renderwindowinteractor
    iren = vtk.vtkRenderWindowInteractor()
    iren.SetRenderWindow(renWin)

    # mapper
    dataMapper1 = vtk.vtkPolyDataMapper()
    dataMapper2 = vtk.vtkPolyDataMapper()
    #dataMapper1.AddInputConnection(pd_in.GetOutputPort())
    #dataMapper2.AddInputConnection(filt.GetOutputPort())
    dataMapper1.AddInputConnection(transform_filter.GetOutputPort())
    dataMapper2.AddInputConnection(transform_filter_grid.GetOutputPort())

    #vtkPolyDataMapper = dataMapper.SetInputConnection(0,transform_filter.GetOutputPort())
    #dataMapper.SetInputConnection(0,transform_filter.GetOutputPort())
    #dataMapper.SetInputConnection(1,transform_filter_grid.GetOutputPort())

    # actor
    dataActor1 = vtk.vtkActor()
    dataActor2 = vtk.vtkActor()
    dataActor1.SetMapper(dataMapper1)
    dataActor2.SetMapper(dataMapper2)

    # assign actor to the renderer
    ren.AddActor(dataActor1)
    ren.AddActor(dataActor2)

    # enable user interface interactor
    iren.Initialize()
    renWin.Render()
    iren.Start()
Example #24
0
def inv_curv(b_pointsU, b_pointsD, sPoints, diffeoX, diffeoY, rotPtX, rotPtY,
             interSkelX, interSkelY):
    invPtsU = b_pointsU.copy()
    invPtsD = b_pointsD.copy()
    skelPt = sPoints.copy()

    # looping through all the iterations of the curvature flow (we are doing the inverse of the flow)
    for j in range(0, len(diffeoX[0])):
        movingX = []
        movingY = []
        source_pts = vtk.vtkPoints()
        target_pts = vtk.vtkPoints()
        for i in range(0, len(rotPtX)):
            pt = []
            if j == 0:
                pt = [rotPtX[i], rotPtY[i], 0]
            else:
                pt = [diffeoX[i][-1 * j], diffeoY[i][-1 * j], 0]

            # source pts for TPS starts off as best fit ellipse
            # next iteration it will be the last diffeomorphism
            # keep going until it is the second diffeomorphism
            source_pts.InsertNextPoint(pt)

            pt = [diffeoX[i][-1 - j], diffeoY[i][-1 - j], 0]
            movingX.append(diffeoX[i][-1 - j])
            movingY.append(diffeoY[i][-1 - j])

            # target points is the diffeomorphism before the diffeomorphism of the source points
            # starts as last and goes to first
            target_pts.InsertNextPoint(pt)
        source_pts.Modified()
        target_pts.Modified()

        ### Interpolate deformation with thin-plate-spline
        tps = vtk.vtkThinPlateSplineTransform()
        tps.SetSourceLandmarks(source_pts)
        tps.SetTargetLandmarks(target_pts)
        tps.SetBasisToR()
        tps.Modified()
        sXs = []
        sYs = []

        # finding interpolated skel points
        for i in range(0, len(interSkelX)):
            intSkelPt = tps.TransformPoint([interSkelX[i], interSkelY[i], 0])
            interSkelX[i] = intSkelPt[0]
            interSkelY[i] = intSkelPt[1]

        for i in range(0, len(sPoints)):
            sp = [skelPt[i][0], skelPt[i][1], 0]
            up = [invPtsU[i][0], invPtsU[i][1], 0]
            if i != 0 and i != len(sPoints) - 1:
                down = [invPtsD[i - 1][0], invPtsD[i - 1][1], 0]

            # finding new skeletal points
            sk_pt = tps.TransformPoint(sp)
            skelPt[i][0] = sk_pt[0]
            skelPt[i][1] = sk_pt[1]
            sXs.append(sk_pt[0])
            sYs.append(sk_pt[1])

            # finding new boundary points for the up spokes
            newUp = tps.TransformPoint(up)
            invPtsU[i][0] = newUp[0]
            invPtsU[i][1] = newUp[1]

            # new boundary points of bottom spokes
            if i != 0 and i != len(sPoints) - 1:
                newDown = tps.TransformPoint(down)
                invPtsD[i - 1][0] = newDown[0]
                invPtsD[i - 1][1] = newDown[1]

            # plotting the final spokes
            if j == len(diffeoX[0]) - 1:
                xUp = [sk_pt[0], newUp[0]]
                yUp = [sk_pt[1], newUp[1]]
                # plt.plot(xUp, yUp,'k')
                if i != 0 and i != len(sPoints) - 1:
                    xDown = [sk_pt[0], newDown[0]]
                    yDown = [sk_pt[1], newDown[1]]
                    # plt.plot(xDown, yDown,'k')

    movingX.append(movingX[0])
    movingY.append(movingY[0])
    # plt.plot(interSkelX, interSkelY,'r')
    # plt.plot(movingX, movingY, 'b')
    # plt.show()
    return sXs, sYs, invPtsU, invPtsD
Example #25
0
def createMorph(selectedImages,selectedPMs):
  """
  Translates and rotate the bitmaps based on the shapedefining landmarks (selectedPMs)
  of the associated image to the target image (first image).
  Morphs the result so that the bitmap overlay on the first image is valid for the first image.  
  """
  
  #save the temporary results here later:
  os_temp_path = tempfile.gettempdir()
  
  #get the measurements for the first image (our targets)
  mainImage = OriginalImage.objects.all().get(id=selectedImages[0])
  potentialids = [] 
  #now get the associated measurements
  measures = Measurement.objects.all().filter(id__in=selectedPMs[0]).filter(mogelijkemeting__shapedefining=True)
  measures = [j for j in measures]
  measures.sort(key=lambda x: x.mogelijkemeting.name)
   
  coordsx = []
  coordsy = []
  for k, measurement in enumerate(measures):
    coordsx.append(float(measurement.x))
    coordsy.append(float(measurement.y))
    potentialids.append(measurement.mogelijkemeting.id)
  r1 = vtk.vtkJPEGReader()
  r1.SetFileName(settings.DATADIR + mainImage.id + ".jpg")
  r1.Update() 

  # flip y coord (VTK has opposite convention), create 3-d coords (z=0)
  ydim = r1.GetOutput().GetDimensions()[1]
  coords = [(x, ydim - y, 0) for (x,y) in zip(coordsx, coordsy)]
  
  # convert everything to vtkPoints
  lmt = vtk.vtkPoints()
  lmt.SetNumberOfPoints(len(coords))
  for i, coord in enumerate(coords):
    lmt.SetPoint(i,coord)
  
  #The target is clear, let's get to work, get the source images...
  images = []
  #we don't need the first image or its measures anymore, because they don't need to be transformed or morphed
  selectedImages.pop(0)
  selectedPMs.pop(0)
  for id in selectedImages:
    images.append(OriginalImage.objects.all().get(id=id))

  transformations = []
  morphtransformations = []
  
  #Create a new database object for the target image to associate the bitmaps with
  img = OriginalImage(project=mainImage.project, name='MorphedImage')
  img.save()
  imp = Image.open(settings.DATADIR + mainImage.id + '.jpg')
  imp.save(settings.DATADIR + img.id + '.jpg', 'JPEG')  
  orig_bitmaps = Bitmap.objects.all().filter(image=mainImage)
  
  for bm in orig_bitmaps:
    #store bitmaps of mainImage as sub of img
    bitmap = Bitmap(project=img.project, name='warpedbitmap', image=img, 
                      mogelijkemeting=bm.mogelijkemeting, imagewidth=bm.imagewidth, 
                      imageheight=bm.imageheight, minx=bm.minx, miny=bm.miny, maxx=bm.maxx, maxy=bm.maxy)
    bitmap.save()
      
    bitmap_image = Image.open(settings.DATADIR + bm.id + '.gif')
    bitmap_image = bitmap_image.convert("RGBA")
    bitmap_image.save(settings.DATADIR + bitmap.id + '.gif', transparency=0)
    
  #now get the other images and perform our transformations
  for i in range(len(images)):
    measures = Measurement.objects.all().filter(id__in=selectedPMs[i]).filter(mogelijkemeting__shapedefining=True)#get measurements
    measures = [j for j in measures]
    measures.sort(key=lambda x: x.mogelijkemeting.name)
    coordsx = []
    coordsy = []    
    for k, measurement in enumerate(measures):
      coordsx.append(float(measurement.x))
      coordsy.append(float(measurement.y))
      if potentialids[k] != measurement.mogelijkemeting.id: #the potentialmeasurements do not match up to the ones in the target image
        return img, 0
    r = vtk.vtkJPEGReader()
    r.SetFileName(settings.DATADIR + images[i].id + ".jpg")
    r.Update()

    ydim = r.GetOutput().GetDimensions()[1]
    coordso = [(x, ydim - y, 0) for (x,y) in zip(coordsx, coordsy)]
    lms = vtk.vtkPoints()
    lms.SetNumberOfPoints(len(coordso))
    for k, coord in enumerate(coordso):
      lms.SetPoint(k,coord)

    transformation = vtk.vtkLandmarkTransform()
    transformation.SetTargetLandmarks(lmt)  
    lmt.Modified()
    transformation.SetSourceLandmarks(lms)
    lms.Modified()
    #size matters, so set the mode to Rigid Body (also known as do not scale please)
    transformation.SetModeToRigidBody()
    transformation.Inverse()
    transformation.Update()
    out = vtk.vtkPoints()#this will be the source of our morph transform
    transformation.TransformPoints(lms,out)
    transformations.append(transformation)
    ir = vtk.vtkImageReslice()
    # we're not using linear, because we want to improve the quality of the bitmaps
    ir.SetInterpolationModeToNearestNeighbor()
    ir.SetResliceTransform(transformation)
    ir.SetInput(r.GetOutput())
    ir.SetInformationInput(r1.GetOutput())
    w = vtk.vtkJPEGWriter()
    w.SetFileName(os_temp_path+'/translated'+images[i].id+'.jpg')
    w.SetInput(ir.GetOutput())
    w.Write()
    r2 = vtk.vtkJPEGReader()
    r2.SetFileName(os_temp_path+'/translated'+images[i].id+'.jpg')
    r2.Update()  
 
    # the mighty morphing ThinPlateSplineTransform
    morphtransform = vtk.vtkThinPlateSplineTransform()
    morphtransform.SetBasisToR2LogR()
    morphtransform.SetSourceLandmarks(lms)
    lms.Modified()
    morphtransform.SetTargetLandmarks(lmt)
    lmt.Modified()
    morphtransform.Inverse()
    morphtransform.Update()
    morphtransformations.append(morphtransform)

    #ir.SetInput(r2.GetOutput())
    #ir.SetInformationInput(r1.GetOutput())
    
    bitmaps = Bitmap.objects.all().filter(image=images[i])
    
    #now perform the total transformation on all bitmaps
    for bm in bitmaps:
      location = settings.DATADIR + bm.id + ".gif"
      im = Image.open(location)
      im = im.convert("RGBA")
      im.save(settings.DATADIR + bm.id + ".png", "PNG")

      r3 = vtk.vtkPNGReader()
      r3.SetFileName(settings.DATADIR + bm.id + '.png')
      r3.Update()
      
      ir2 = vtk.vtkImageReslice()
      ir2.SetInterpolationModeToNearestNeighbor()
      ir2.SetResliceTransform(morphtransform)
      ir2.SetInput(r3.GetOutput())
      ir2.SetInformationInput(r2.GetOutput())
      
      w3 = vtk.vtkPNGWriter()
      w3.SetFileName(os_temp_path+'/morphed'+bm.id+'.png')
      w3.SetInput(ir2.GetOutput())
      w3.Write()
      
      bitmap = Bitmap(project=img.project, name='warpedbitmap', image=img, 
                      mogelijkemeting=bm.mogelijkemeting, imagewidth=bm.imagewidth, 
                      imageheight=bm.imageheight, minx=bm.minx, miny=bm.miny, maxx=bm.maxx, maxy=bm.maxy)
      bitmap.save()
      
      im = Image.open(os_temp_path+'/morphed'+bm.id+'.png')
      im = im.convert("RGBA")
      im.save(settings.DATADIR + bitmap.id + '.gif', transparency=0)
      

  return img, 1
 def register(self, fixedData, movingData, index = -1, discard = False, delta = 0, fov = 9999999.0,
         down_fix = 1, down_mov = 1, occ = 9999999.0, op = False, useMask = False, isTime = False, MaxRate = 0.2,
         aug = False, distance_fix = 0.3, distance_mov = 0.1, w_wrong = 1.5, truth_mov = None):
     time1 = time.time()
     if index == -1:
         index = self.gui.getDataIndex({'Contour': 0, 'Centerline': 1}, 'Select the object')
     if index is None:
         return None, None, None
     if index == 0:
         fixed_points = fixedData.getPointSet('Contour').copy()
         moving_points = movingData.getPointSet('Contour').copy()
     else:
         fixed_points = fixedData.getPointSet('Centerline').copy()
         moving_points = movingData.getPointSet('Centerline').copy()
     if truth_mov is None:
         truth_mov = moving_points.copy()
     
     fixed_bif = db.getBifurcation(fixed_points)
     moving_bif = db.getBifurcation(moving_points)
     
     if useMask:
         mask_points = movingData.getPointSet('Mask')
         for point in mask_points:
             moving_points = npy.delete(moving_points, npy.where((npy.abs(moving_points[:, 2] - point[2]) < 0.0001) & (npy.round(moving_points[:, -1]) == point[3])), axis = 0)
         
     fixed_res = fixedData.getResolution().tolist()
     moving_res = movingData.getResolution().tolist()
     fixed_points = fixed_points[npy.where(fixed_points[:, 0] >= 0)]
     moving_points = moving_points[npy.where(moving_points[:, 0] >= 0)]
     
     # Use the bifurcation as the initial position
     if (fixed_bif < 0) or (moving_bif < 0):
         fixed_min = 0
     
     # Augmentation of pointset
     fixed = fixed_points.copy()
     moving = moving_points.copy()
     
     if index == 1 and aug:
         fixed = util.augmentCenterline(fixed, 1, 10)
         moving = util.augmentCenterline(moving, 1, 10)
         fix_dis = util.getAxisSin(fixed, 3 / fixed_res[2]) * distance_fix
         mov_dis = util.getAxisSin(moving, 3 / moving_res[2]) * distance_mov
         fixed = util.resampleCenterline(fixed, fix_dis / fixed_res[2])
         moving = util.resampleCenterline(moving, mov_dis / moving_res[2])
     
     fixed = fixed[npy.cast[npy.int32](npy.abs(fixed[:, 2] - fixed_bif)) % down_fix == 0]
     moving = moving[npy.cast[npy.int32](npy.abs(moving[:, 2] - moving_bif)) % down_mov == 0]
     
     fixed[:, :3] *= fixed_res[:3]
     moving[:, :3] *= moving_res[:3]
     
     new_trans_points = truth_mov
     result_center_points = movingData.getPointSet('Centerline').copy()
     new_trans_points = new_trans_points[new_trans_points[:, 3] >= 0]
     result_center_points = result_center_points[result_center_points[:, 3] >= 0]
     new_trans_points[:, :3] *= moving_res[:3]
     result_center_points[:, :3] *= moving_res[:3]
     
     if (fixed_bif >= 0) and (moving_bif >= 0):
         fixed[:, 2] -= (fixed_bif * fixed_res[2] - moving_bif * moving_res[2] + delta)
     
     # Prepare for ICP
     
     MaxIterNum = 50
     #MaxNum = 600
     MaxNum = int(MaxRate * moving.shape[0] + 0.5)
     
     targetPoints = [vtk.vtkPoints(), vtk.vtkPoints(), vtk.vtkPoints()]
     targetVertices = [vtk.vtkCellArray(), vtk.vtkCellArray(), vtk.vtkCellArray()]
     target = [vtk.vtkPolyData(), vtk.vtkPolyData(), vtk.vtkPolyData()]
     Locator = [vtk.vtkCellLocator(), vtk.vtkCellLocator(), vtk.vtkCellLocator()]
     
     for i in range(3):
         for x in fixed[npy.round(fixed[:, 3]) == i]:
             id = targetPoints[i].InsertNextPoint(x[0], x[1], x[2])
             targetVertices[i].InsertNextCell(1)
             targetVertices[i].InsertCellPoint(id)
         target[i].SetPoints(targetPoints[i])
         target[i].SetVerts(targetVertices[i])
         
         Locator[i].SetDataSet(target[i])
         Locator[i].SetNumberOfCellsPerBucket(1)
         Locator[i].BuildLocator()
     
     step = 1
     if moving.shape[0] > MaxNum:
         ind = moving[:, 2].argsort()
         moving = moving[ind, :]
         step = moving.shape[0] / MaxNum
     nb_points = moving.shape[0] / step
     
     points1 = vtk.vtkPoints()
     points1.SetNumberOfPoints(nb_points)
     
     label = npy.zeros([MaxNum * 2], dtype = npy.int8)
     
     j = 0
     for i in range(nb_points):
         points1.SetPoint(i, moving[j][0], moving[j][1], moving[j][2])
         label[i] = moving[j][3]
         j += step
     
     closestp = vtk.vtkPoints()
     closestp.SetNumberOfPoints(nb_points)
     points2 = vtk.vtkPoints()
     points2.SetNumberOfPoints(nb_points)
     
     id1 = id2 = vtk.mutable(0)
     dist = vtk.mutable(0.0)
     outPoint = [0.0, 0.0, 0.0]
     p1 = [0.0, 0.0, 0.0]
     p2 = [0.0, 0.0, 0.0]
     iternum = 0
     a = points1
     b = points2
     if (op and index == 0) or (not op and index == 1):
         w_mat = [[1, w_wrong, w_wrong], [w_wrong, 1, 99999999], [w_wrong, 99999999, 1]]
     else:
         w_mat = [[1, 1, 1], [1, 1, 1], [1, 1, 1]]
     
     accumulate = vtk.vtkTransform()
     accumulate.PostMultiply()
     LandmarkTransform = vtk.vtkLandmarkTransform()
     LandmarkTransform.SetModeToRigidBody()
     
     while True:
         for i in range(nb_points):
             min_dist = 99999999
             min_outPoint = [0.0, 0.0, 0.0]
             for j in range(3):
                 Locator[j].FindClosestPoint(a.GetPoint(i), outPoint, id1, id2, dist)
                 dis = npy.sqrt(npy.sum((npy.array(outPoint) - a.GetPoint(i)) ** 2))
                 if dis * w_mat[label[i]][j] < min_dist:
                     min_dist = dis * w_mat[label[i]][j]
                     min_outPoint = copy.deepcopy(outPoint)
                 
             closestp.SetPoint(i, min_outPoint)
             
         LandmarkTransform.SetSourceLandmarks(a)
         LandmarkTransform.SetTargetLandmarks(closestp)
         LandmarkTransform.Update()
         accumulate.Concatenate(LandmarkTransform.GetMatrix())
             
         iternum += 1
         
         for i in range(nb_points):
             a.GetPoint(i, p1)
             LandmarkTransform.InternalTransformPoint(p1, p2)
             b.SetPoint(i, p2)
         b, a = a, b
         
         if iternum >= MaxIterNum:
             break
     
     matrix = accumulate.GetMatrix()
     
     T = ml.mat([matrix.GetElement(0, 3), matrix.GetElement(1, 3), matrix.GetElement(2, 3)]).T
     R = ml.mat([[matrix.GetElement(0, 0), matrix.GetElement(0, 1), matrix.GetElement(0, 2)], 
                 [matrix.GetElement(1, 0), matrix.GetElement(1, 1), matrix.GetElement(1, 2)], 
                 [matrix.GetElement(2, 0), matrix.GetElement(2, 1), matrix.GetElement(2, 2)]]).I
     result_center_points[:, :3] = util.applyTransformForPoints(result_center_points[:, :3], npy.array([1.0, 1, 1]), npy.array([1.0, 1, 1]), R, T, ml.zeros([3, 1], dtype = npy.float32))
     new_trans_points[:, :3] = util.applyTransformForPoints(new_trans_points[:, :3], npy.array([1.0, 1, 1]), npy.array([1.0, 1, 1]), R, T, ml.zeros([3, 1], dtype = npy.float32))
     
     LandmarkTransform = vtk.vtkThinPlateSplineTransform()
     LandmarkTransform.SetBasisToR()
     iternum = 0
     # Non-rigid
     while True:
         for i in range(nb_points):
             min_dist = 99999999
             min_outPoint = [0.0, 0.0, 0.0]
             for j in range(3):
                 Locator[j].FindClosestPoint(a.GetPoint(i), outPoint, id1, id2, dist)
                 dis = npy.sqrt(npy.sum((npy.array(outPoint) - a.GetPoint(i)) ** 2))
                 if dis * w_mat[label[i]][j] < min_dist:
                     min_dist = dis * w_mat[label[i]][j]
                     min_outPoint = copy.deepcopy(outPoint)
                 
             closestp.SetPoint(i, min_outPoint)
             
         LandmarkTransform.SetSourceLandmarks(a)
         LandmarkTransform.SetTargetLandmarks(closestp)
         LandmarkTransform.Update()
         
         '''
         for i in range(result_center_points.shape[0]):
             LandmarkTransform.InternalTransformPoint([result_center_points[i, 0], result_center_points[i, 1], result_center_points[i, 2]], p2)
             result_center_points[i, :3] = p2
         '''
         for i in range(new_trans_points.shape[0]):
             LandmarkTransform.InternalTransformPoint([new_trans_points[i, 0], new_trans_points[i, 1], new_trans_points[i, 2]], p2)
             new_trans_points[i, :3] = p2
             
         iternum += 1
         if iternum >= 1:
             break
         
         for i in range(nb_points):
             a.GetPoint(i, p1)
             LandmarkTransform.InternalTransformPoint(p1, p2)
             b.SetPoint(i, p2)
         b, a = a, b
     
     time2 = time.time()
     
     if (fixed_bif >= 0) and (moving_bif >= 0):
         new_trans_points[:, 2] += (fixed_bif * fixed_res[2] - moving_bif * moving_res[2] + delta)
         result_center_points[:, 2] += (fixed_bif * fixed_res[2] - moving_bif * moving_res[2] + delta)
     new_trans_points[:, :3] /= fixed_res[:3]
     result_center_points[:, :3] /= fixed_res[:3]
     resultImage = movingData.getData().copy()
     
     sa = SurfaceErrorAnalysis(None)
     dataset = db.BasicData(npy.array([[[0]]]), fixedData.getInfo(), {'Contour': new_trans_points, 'Centerline': result_center_points})
     mean_dis, mean_whole, max_dis, max_whole = sa.analysis(dataset, point_data_fix = fixedData.getPointSet('Contour').copy(), useResult = True)
     del dataset
     print mean_dis
     print mean_whole
     
     if isTime:
         return resultImage, {'Contour': new_trans_points, 'Centerline': result_center_points}, [mean_dis, mean_whole], time2 - time1
     return resultImage, {'Contour': new_trans_points, 'Centerline': result_center_points}, [mean_dis, mean_whole]
Example #27
0
  def performAffineAndThinPlateRegistration(self, state, landmarks):
    """Perform Affine registration first, use the transformed result as the input of the thin plate transform"""
    
    # if state.transformed:
     # if state.transformed.GetTransformNodeID() != state.transform.GetID():
        # state.transformed.SetAndObserveTransformNodeID(state.transform.GetID())


    volumeNodes = (state.fixed, state.moving)
    fiducialNodes = (state.fixedFiducials,state.movingFiducials)
    points = state.logic.vtkPointsForVolumes( volumeNodes, fiducialNodes )
 
    #yingli debug
    #print 'self.linearMode',self.linearMode

    if not self.landmarkTransform:
        self.landmarkTransform = vtk.vtkLandmarkTransform()

    if self.linearMode == 'Rigid':
      self.landmarkTransform.SetModeToRigidBody()
    if self.linearMode == 'Similarity':
      self.landmarkTransform.SetModeToSimilarity()
    if self.linearMode == 'Affine':
      self.landmarkTransform.SetModeToAffine()
    if state.fixedFiducials.GetNumberOfFiducials() < 3:
      self.landmarkTransform.SetModeToRigidBody()
   
    self.landmarkTransform.SetSourceLandmarks(points[state.moving])
    self.landmarkTransform.SetTargetLandmarks(points[state.fixed])
    self.landmarkTransform.Update()

    #transform moving landmarks
    affine_transformed_moving_points = vtk.vtkPoints()
    self.landmarkTransform.TransformPoints(points[state.moving],affine_transformed_moving_points)

    #yingli debug
    #print self.landmarkTransform.GetMatrix()
    #print 'old moving', points[state.moving].GetPoint(0)
    #print 'new moving', affine_transformed_moving_points.GetPoint(0)

    # do thin plate, use affine transformed result as the input
    # since this is a resample transform, source is the fixed (resampling target) space
    # and moving is the target space
    if not self.thinPlateTransform:
      self.thinPlateTransform = vtk.vtkThinPlateSplineTransform()
    self.thinPlateTransform.SetBasisToR() # for 3D transform
    self.thinPlateTransform.SetSourceLandmarks(affine_transformed_moving_points)
    self.thinPlateTransform.SetTargetLandmarks(points[state.fixed])
    self.thinPlateTransform.Update()

    if points[state.moving].GetNumberOfPoints() != points[state.fixed].GetNumberOfPoints():
      raise hell

    #add nesting transfrom: order matters!
    transformSelector = slicer.qMRMLNodeComboBox()
    transformSelector.nodeTypes = ( ("vtkMRMLTransformNode"), "" )
    transformSelector.selectNodeUponCreation = True
    transformSelector.addEnabled = True
    transformSelector.removeEnabled = True
    transformSelector.noneEnabled = True
    transformSelector.showHidden = False
    transformSelector.showChildNodeTypes = False
    transformSelector.setMRMLScene( slicer.mrmlScene )
    transformSelector.setToolTip( "The transform for linear registration" )
    transformSelector.enabled = False

    # concatenate transfroms: method 1: add nesting transfrom: order matters!
    # note: this method will keep each transform(not ideal)
    
    # landmarkTransformNode = slicer.util.getNode('Affine-Transform')
    # if not landmarkTransformNode:
        # landmarkTransformNode=transformSelector.addNode()
        # landmarkTransformNode.SetName('Affine-Transform')
        # state.transform.SetAndObserveTransformNodeID(landmarkTransformNode.GetID())

    # landmarkTransformNode.ApplyTransform(self.landmarkTransform)

    # thinPlateTransformNode = slicer.util.getNode('ThinPlate-Transform')
    # if not thinPlateTransformNode:
        # thinPlateTransformNode=transformSelector.addNode()
        # thinPlateTransformNode.SetName('ThinPlate-Transform')
        # landmarkTransformNode.SetAndObserveTransformNodeID(thinPlateTransformNode.GetID())

    # # thinPlateTransformNode.ApplyTransform(self.thinPlateTransform)
    
    #state.transform.SetAndObserveTransformToParent(self.landmarkTransform)
    # #state.transform.SetAndObserveTransformToParent(self.thinPlateTransform)
    # stateTransformNodeNode = slicer.util.getNode('Transform')
    # stateTransformNodeNode.SetAndObserveTransformToParent(self.thinPlateTransform)


    #test vtk concatenate
    #self.landmarkTransform.Concatenate(self.landmarkTransform)
    #state.transform.SetAndObserveTransformToParent(self.thinPlateTransform)

    #concatenate transfroms: method 2: use vtkGeneralTransform to concatenate transfroms.
    transform = vtk.vtkGeneralTransform()
    transform.Concatenate(self.thinPlateTransform)
    transform.Concatenate(self.landmarkTransform)
    state.transform.SetAndObserveTransformToParent(transform)
Example #28
0
    def applyPatch(self,
                   meshNode,
                   LMNode,
                   gridLandmarks,
                   sampleRate,
                   polydataNormalArray,
                   maximumProjectionDistance=.25):
        surfacePolydata = meshNode.GetPolyData()

        gridPoints = vtk.vtkPoints()

        gridPoints.InsertNextPoint(0, 0, 0)
        gridPoints.InsertNextPoint(0, sampleRate - 1, 0)
        gridPoints.InsertNextPoint(sampleRate - 1, 0, 0)
        for row in range(1, sampleRate - 1):
            for col in range(1, sampleRate - 1):
                if (row + col) < (sampleRate - 1):
                    gridPoints.InsertNextPoint(row, col, 0)

        gridPolydata = vtk.vtkPolyData()
        gridPolydata.SetPoints(gridPoints)

        sourcePoints = vtk.vtkPoints()
        targetPoints = vtk.vtkPoints()

        sourcePoints.InsertNextPoint(gridPoints.GetPoint(0))
        sourcePoints.InsertNextPoint(gridPoints.GetPoint(1))
        sourcePoints.InsertNextPoint(gridPoints.GetPoint(2))

        point = [0, 0, 0]
        for gridVertex in gridLandmarks:
            LMNode.GetMarkupPoint(0, int(gridVertex - 1), point)
            targetPoints.InsertNextPoint(point)

        #transform grid to triangle
        transform = vtk.vtkThinPlateSplineTransform()
        transform.SetSourceLandmarks(sourcePoints)
        transform.SetTargetLandmarks(targetPoints)
        transform.SetBasisToR()

        transformNode = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLTransformNode", "TPS")
        transformNode.SetAndObserveTransformToParent(transform)

        model = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLModelNode",
                                                   "mesh_resampled")
        model.SetAndObservePolyData(gridPolydata)
        model.SetAndObserveTransformNodeID(transformNode.GetID())
        slicer.vtkSlicerTransformLogic().hardenTransform(model)

        resampledPolydata = model.GetPolyData()

        pointLocator = vtk.vtkPointLocator()
        pointLocator.SetDataSet(surfacePolydata)
        pointLocator.BuildLocator()

        #get surface normal from each landmark point
        rayDirection = [0, 0, 0]

        for gridVertex in gridLandmarks:
            LMNode.GetMarkupPoint(0, int(gridVertex - 1), point)
            closestPointId = pointLocator.FindClosestPoint(point)
            tempNormal = polydataNormalArray.GetTuple(closestPointId)
            rayDirection[0] += tempNormal[0]
            rayDirection[1] += tempNormal[1]
            rayDirection[2] += tempNormal[2]

        #normalize
        vtk.vtkMath().Normalize(rayDirection)

        # # get normal at each grid point
        # gridNormals = np.zeros((3,3))
        # gridIndex=0
        # for gridVertex in gridLandmarks:
        # print(gridVertex)
        # LMNode.GetMarkupPoint(0,int(gridVertex-1),point)
        # closestPointId = pointLocator.FindClosestPoint(point)
        # tempNormal = polydataNormalArray.GetTuple(closestPointId)
        # print(tempNormal)
        # gridNormals[gridIndex] = tempNormal
        # gridIndex+=1
        # print(gridNormals)

        #set up locater for intersection with normal vector rays
        obbTree = vtk.vtkOBBTree()
        obbTree.SetDataSet(surfacePolydata)
        obbTree.BuildLocator()

        #define new landmark sets
        semilandmarkNodeName = "semiLM_" + str(gridLandmarks[0]) + "_" + str(
            gridLandmarks[1]) + "_" + str(gridLandmarks[2])
        semilandmarkPoints = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLMarkupsFiducialNode", semilandmarkNodeName)

        #get a sample distance for quality control
        m1 = model.GetPolyData().GetPoint(0)
        m2 = model.GetPolyData().GetPoint(1)
        m3 = model.GetPolyData().GetPoint(2)
        d1 = math.sqrt(vtk.vtkMath().Distance2BetweenPoints(m1, m2))
        d2 = math.sqrt(vtk.vtkMath().Distance2BetweenPoints(m2, m3))
        d3 = math.sqrt(vtk.vtkMath().Distance2BetweenPoints(m1, m3))
        sampleDistance = (d1 + d2 + d3)

        # set initial three grid points
        for index in range(0, 3):
            origLMPoint = resampledPolydata.GetPoint(index)
            #landmarkLabel = LMNode.GetNthFiducialLabel(gridLandmarks[index]-1)
            landmarkLabel = str(gridLandmarks[index])
            semilandmarkPoints.AddFiducialFromArray(origLMPoint, landmarkLabel)

        # calculate maximum projection distance
        projectionTolerance = maximumProjectionDistance / .25
        #boundingBox = vtk.vtkBoundingBox()
        #boundingBox.AddBounds(surfacePolydata.GetBounds())
        #diagonalDistance = boundingBox.GetDiagonalLength()
        #rayLength = math.sqrt(diagonalDistance) * projectionTolerance
        rayLength = sampleDistance * projectionTolerance

        # get normal projection intersections for remaining semi-landmarks
        for index in range(3, resampledPolydata.GetNumberOfPoints()):
            modelPoint = resampledPolydata.GetPoint(index)

            # ## get estimated normal vector
            # rayDirection = [0,0,0]
            # distance1=math.sqrt(vtk.vtkMath().Distance2BetweenPoints(modelPoint,resampledPolydata.GetPoint(0)))
            # distance2=math.sqrt(vtk.vtkMath().Distance2BetweenPoints(modelPoint,resampledPolydata.GetPoint(1)))
            # distance3=math.sqrt(vtk.vtkMath().Distance2BetweenPoints(modelPoint,resampledPolydata.GetPoint(2)))
            # distanceTotal = distance1 + distance2 + distance3
            # weights=[(distance3+distance2)/distanceTotal, (distance1+distance3)/distanceTotal,(distance1+distance2)/distanceTotal]

            # for gridIndex in range(0,3):
            # rayDirection+=(weights[gridIndex]*gridNormals[gridIndex])
            # vtk.vtkMath().Normalize(rayDirection)
            # ##

            rayEndPoint = [0, 0, 0]
            for dim in range(len(rayEndPoint)):
                rayEndPoint[
                    dim] = modelPoint[dim] + rayDirection[dim] * rayLength
            intersectionIds = vtk.vtkIdList()
            intersectionPoints = vtk.vtkPoints()
            obbTree.IntersectWithLine(modelPoint, rayEndPoint,
                                      intersectionPoints, intersectionIds)
            #if there are intersections, update the point to most external one.
            if intersectionPoints.GetNumberOfPoints() > 0:
                exteriorPoint = intersectionPoints.GetPoint(
                    intersectionPoints.GetNumberOfPoints() - 1)
                semilandmarkPoints.AddFiducialFromArray(exteriorPoint)
            #if there are no intersections, reverse the normal vector
            else:
                for dim in range(len(rayEndPoint)):
                    rayEndPoint[
                        dim] = modelPoint[dim] + rayDirection[dim] * -rayLength
                obbTree.IntersectWithLine(modelPoint, rayEndPoint,
                                          intersectionPoints, intersectionIds)
                if intersectionPoints.GetNumberOfPoints() > 0:
                    exteriorPoint = intersectionPoints.GetPoint(0)
                    semilandmarkPoints.AddFiducialFromArray(exteriorPoint)
                else:
                    print("No intersection, using closest point")
                    closestPointId = pointLocator.FindClosestPoint(modelPoint)
                    rayOrigin = surfacePolydata.GetPoint(closestPointId)
                    semilandmarkPoints.AddFiducialFromArray(rayOrigin)

        # update lock status and color
        semilandmarkPoints.SetLocked(True)
        semilandmarkPoints.GetDisplayNode().SetColor(random.random(),
                                                     random.random(),
                                                     random.random())
        semilandmarkPoints.GetDisplayNode().SetSelectedColor(
            random.random(), random.random(), random.random())
        semilandmarkPoints.GetDisplayNode().PointLabelsVisibilityOff()
        #clean up
        slicer.mrmlScene.RemoveNode(transformNode)
        slicer.mrmlScene.RemoveNode(model)
        print("Total points:", semilandmarkPoints.GetNumberOfFiducials())
        return semilandmarkPoints
Example #29
0
def write_transforms_to_itk_format(transform_list, outdir, subject_ids=None):
    """Write VTK affine or spline transforms to ITK 4 text file formats.

    Input transforms are in VTK RAS space and are forward transforms. Output
    transforms are in LPS space and are the corresponsing inverse
    transforms, according to the conventions for these file formats and for
    resampling images. The affine transform is straightforward. The spline
    transform file format is just a list of displacements that have to be in
    the same order as they are stored in ITK C code. This now outputs an ITK
    transform that works correctly to transform the tracts (or any volume in
    the same space) in Slicer. In the nonrigid case, we also output a vtk
    native spline transform file using MNI format.
    """

    idx = 0
    tx_fnames = list()
    for tx in transform_list:

        # save out the vtk transform to a text file as it is
        # The MNI transform reader/writer are available in vtk so use those:
        if tx.GetClassName() != 'vtkBSplineTransform':
            writer = vtk.vtkMNITransformWriter()
            writer.AddTransform(tx)
            if subject_ids is not None:
                fname = 'vtk_txform_' + str(subject_ids[idx]) + '.xfm'
            else:
                fname = 'vtk_txform_{0:05d}.xfm'.format(idx)
            writer.SetFileName(os.path.join(outdir, fname))
            writer.Write()

        # file name for itk transform written below
        if subject_ids is not None:
            fname = 'itk_txform_' + str(subject_ids[idx]) + '.tfm'
        else:
            fname = 'itk_txform_{0:05d}.tfm'.format(idx)
        fname = os.path.join(outdir, fname)
        tx_fnames.append(fname)

        # Save the itk transform as the inverse of this transform (resampling transform) and in LPS.
        # This will show the same transform in the slicer GUI as the vtk transform we internally computed
        # that is stored in the .xfm text file, above.
        # To apply our transform to resample a volume in LPS:
        # convert to RAS, use inverse of transform to resample, convert back to LPS
        if tx.GetClassName() == 'vtkThinPlateSplineTransform' or  tx.GetClassName() == 'vtkBSplineTransform':
            #print 'Saving nonrigid transform displacements in ITK format'

            # Deep copy to avoid modifying input transform that will be applied to polydata
            if tx.GetClassName() == 'vtkThinPlateSplineTransform':
                tps = vtk.vtkThinPlateSplineTransform()
            else:
                tps = vtk.vtkBSplineTransform()
            tps.DeepCopy(tx)

            #extent = tps.GetCoefficients().GetExtent()
            #origin = tps.GetCoefficients().GetOrigin()
            #spacing = tps.GetCoefficients().GetSpacing()
            #dims = tps.GetCoefficients().GetDimensions()
            #print "E:", extent
            #print "O:", origin
            #print "S:", spacing
            #print "D:", dims

            # invert to get the transform suitable for resampling an image
            tps.Inverse()

            # convert the inverse spline transform from RAS to LPS
            ras_2_lps = vtk.vtkTransform()
            ras_2_lps.Scale(-1, -1, 1)
            lps_2_ras = vtk.vtkTransform()
            lps_2_ras.Scale(-1, -1, 1)
            spline_inverse_lps = vtk.vtkGeneralTransform()
            spline_inverse_lps.Concatenate(lps_2_ras)
            spline_inverse_lps.Concatenate(tps)
            spline_inverse_lps.Concatenate(ras_2_lps)

            # Now, loop through LPS space. Find the effect of the
            # inverse transform on each point. This is essentially what
            # vtk.vtkTransformToGrid() does, but this puts things into
            # LPS.

            # This low-res grid produced small differences (order of 1-2mm) when transforming
            # polydatas inside Slicer vs. in this code. 
            #grid_size = [15, 15, 15]
            #grid_spacing = 10
            # This higher-res grid has fewer small numerical differences
            # grid_size = [50, 50, 50]
            # grid_spacing = 5
            # This higher-res grid has fewer small numerical differences, but files are larger
            #grid_size = [70, 70, 70]
            #grid_spacing = 3

            # This higher-res grid is sufficient to limit numerical
            # differences to under .1mm in tests.  However, files are
            # quite large (47M). As this is still much smaller than
            # the tractography files, and correctness is desired, we
            # will produce large transform files. A preferable
            # solution would be to store the forward transform we
            # compute at the grid points at which it is defined, but
            # there is no inverse flag available in the file
            # format. Therefore the inverse must be stored at high
            # resolution.
            grid_size = [105, 105, 105]
            grid_spacing = 2

            extent_0 = [-(grid_size[0] - 1)/2, -(grid_size[1] - 1)/2, -(grid_size[2] - 1)/2]
            extent_1 = [ (grid_size[0] - 1)/2,  (grid_size[1] - 1)/2,  (grid_size[2] - 1)/2]

            origin = -grid_spacing * (numpy.array(extent_1) - numpy.array(extent_0))/2.0

            grid_points_LPS = list()
            grid_points_RAS = list()

            # ordering of grid points must match itk-style array order for images
            for s in range(extent_0[0], extent_1[0]+1):
                for p in range(extent_0[1], extent_1[1]+1):
                    for l in range(extent_0[2], extent_1[2]+1):
                        grid_points_RAS.append([-l*grid_spacing, -p*grid_spacing, s*grid_spacing])
                        grid_points_LPS.append([l*grid_spacing, p*grid_spacing, s*grid_spacing])

            displacements_LPS = list()

            print "LPS grid for storing transform:", grid_points_LPS[0], grid_points_LPS[-1], grid_spacing

            lps_points = vtk.vtkPoints()
            lps_points2 = vtk.vtkPoints()
            for gp_lps in grid_points_LPS:
                lps_points.InsertNextPoint(gp_lps[0], gp_lps[1], gp_lps[2])

            spline_inverse_lps.TransformPoints(lps_points, lps_points2)
            pidx = 0
            for gp_lps in grid_points_LPS:
                pt = lps_points2.GetPoint(pidx)
                diff_lps = [pt[0] - gp_lps[0], pt[1] - gp_lps[1], pt[2] - gp_lps[2]]
                pidx += 1

                ## # this tested grid definition and origin were okay.
                ## diff_lps = [20,30,40]

                ## # this tested that the ordering of L,P,S is correct:
                ## diff_lps = [0, gp_lps[1], 0]
                ## diff_lps = [gp_lps[0], 0, 0]
                ## diff_lps = [0, 0, gp_lps[2]]

                ## # this tested that the ordering of grid points is correct
                ## # only the R>0, A>0, S<0 region shows a transform.
                ## if gp_lps[0] < 0 and gp_lps[1] < 0 and gp_lps[2] < 0:
                ##     diff_lps = [gp_lps[0]/2.0, 0, 0]
                ## else:
                ##     diff_lps = [0, 0, 0]

                displacements_LPS.append(diff_lps)

            # save the points and displacement vectors in ITK format.
            #print 'Saving in ITK transform format.'
            f = open(fname, 'w')
            f.write('#Insight Transform File V1.0\n')
            f.write('# Transform 0\n')
            # ITK version 3 that included an additive (!) affine transform
            #f.write('Transform: BSplineDeformableTransform_double_3_3\n')
            # ITK version 4 that does not include a second transform in the file
            f.write('Transform: BSplineTransform_double_3_3\n')
            f.write('Parameters: ')
            # "Here the data are: The bulk of the BSpline part are 3D
            # displacement vectors for each of the BSpline grid-nodes
            # in physical space, i.e. for each grid-node, there will
            # be three blocks of displacements defining dx,dy,dz for
            # all grid nodes."
            for block in [0, 1, 2]:
                for diff in displacements_LPS:
                    f.write('{0} '.format(diff[block]))

            #FixedParameters: size size size origin origin origin origin spacing spacing spacing (then direction cosines: 1 0 0 0 1 0 0 0 1)
            f.write('\nFixedParameters:')
            #f.write(' {0} {0} {0}'.format(2*sz+1))
            f.write(' {0}'.format(grid_size[0]))
            f.write(' {0}'.format(grid_size[1]))
            f.write(' {0}'.format(grid_size[2]))

            f.write(' {0}'.format(origin[0]))
            f.write(' {0}'.format(origin[1]))
            f.write(' {0}'.format(origin[2]))
            f.write(' {0} {0} {0}'.format(grid_spacing))
            f.write(' 1 0 0 0 1 0 0 0 1\n')

            f.close()
        else:
            tx_inverse = vtk.vtkTransform()
            tx_inverse.DeepCopy(tx)
            tx_inverse.Inverse()
            ras_2_lps = vtk.vtkTransform()
            ras_2_lps.Scale(-1, -1, 1)
            lps_2_ras = vtk.vtkTransform()
            lps_2_ras.Scale(-1, -1, 1)
            tx2 = vtk.vtkTransform()
            tx2.Concatenate(lps_2_ras)
            tx2.Concatenate(tx_inverse)
            tx2.Concatenate(ras_2_lps)

            three_by_three = list()
            translation = list()
            for i in range(0,3):
                for j in range(0,3):
                    three_by_three.append(tx2.GetMatrix().GetElement(i,j))
            translation.append(tx2.GetMatrix().GetElement(0,3))
            translation.append(tx2.GetMatrix().GetElement(1,3))
            translation.append(tx2.GetMatrix().GetElement(2,3))

            f = open(fname, 'w')
            f.write('#Insight Transform File V1.0\n')
            f.write('# Transform 0\n')
            f.write('Transform: AffineTransform_double_3_3\n')
            f.write('Parameters: ')
            for el in three_by_three:
                f.write('{0} '.format(el))
            for el in translation:
                f.write('{0} '.format(el))
            f.write('\nFixedParameters: 0 0 0\n')
            f.close()

        idx +=1
    return(tx_fnames)
    def cropWithCurve(self, modelNode, fidList, breastFlag, reverseNormal, setInsideOut, torsoFlag):
        # This method takes in a surface scan and list of fiducials as input and computes the breast volume
        # A curved posterior chest wall is constructed to create the closed breast

        modelsLogic = slicer.modules.models.logic()
        #Check which breast volume is being computed for
        if breastFlag == True:
            name = "ClosedLeftBreast"
        else:
            name = "ClosedRightBreast"

        # Define parameters

        InputModel = modelNode.GetPolyData()
        breastBoundPolyData = vtk.vtkPolyData()
        self.FiducialsToPolyData(fidList, breastBoundPolyData)

        # Create plane of best fit from input breast boundary fiducials
        plane = vtk.vtkPlane()
        self.LeastSquaresPlane(modelNode, breastBoundPolyData, plane)

        #creates loop from the breast boundary points
        breastBound = vtk.vtkImplicitSelectionLoop()
        breastBound.SetLoop(breastBoundPolyData.GetPoints())

        #creates the torso model when the torso flag is set
        if torsoFlag == True:
            self.createTorsoModel(InputModel,breastBound)

        # creates model for the plane of best fit
        planeModel = vtk.vtkReverseSense()
        planeModel = self.createPlaneModel(InputModel, plane, breastFlag)

        splineTransform = vtk.vtkThinPlateSplineTransform()
        splineTransform = self.thinPlateSplineTransform(breastBoundPolyData,plane, modelNode)

        #apply spline transform to the plane visualization
        planeWithSplineTransform = vtk.vtkTransformPolyDataFilter()
        planeWithSplineTransform.SetInputConnection(planeModel.GetOutputPort())
        planeWithSplineTransform.SetTransform(splineTransform)

        #create model of the transformed plane
        transformedPlaneModel = modelsLogic.AddModel(planeWithSplineTransform.GetOutputPort())
        transformedPlaneModel.GetDisplayNode().SetVisibility(False)
        transformedPlaneModel.SetName("transformedPlane")

        # Creates cropped breast model
        breastModel = self.createBreastModel(breastBound, InputModel, breastFlag, reverseNormal, setInsideOut, plane, planeWithSplineTransform)

        # Creates cropped-posterior wall
        posteriorWallModel = vtk.vtkPolyData()
        posteriorWallModel = self.createClippedPlane(breastBound,planeWithSplineTransform)

        # Creates closed breast model
        appendClosedBreast = vtk.vtkAppendPolyData()
        appendClosedBreast.AddInputData(breastModel) #Breasts
        appendClosedBreast.AddInputData(posteriorWallModel) #Chest Wall
        appendClosedBreast.Update()

        # Applies cleaning filter to closed breast model
        cleanClosedBreast = vtk.vtkCleanPolyData()
        cleanClosedBreast.SetInputData(appendClosedBreast.GetOutput())
        cleanClosedBreast.Update()

        # Added closed breast model to slicer models
        closedBreastModel = modelsLogic.AddModel(cleanClosedBreast.GetOutput())
        closedBreastModel.GetDisplayNode().SetVisibility(True)
        closedBreastModel.SetName(name)
        closedBreastModel.GetDisplayNode().BackfaceCullingOff()

        slicer.mrmlScene.RemoveNode(transformedPlaneModel)

        return closedBreastModel
Example #31
0
    def run(self, baseMeshNode, baseLMNode, semiLMNode, meshDirectory,
            lmDirectory, ouputDirectory, outputExtension, scaleProjection):
        SLLogic = CreateSemiLMPatches.CreateSemiLMPatchesLogic()
        targetPoints = vtk.vtkPoints()
        point = [0, 0, 0]
        # estimate a sample size usingn semi-landmark spacing
        sampleArray = np.zeros(shape=(25, 3))
        for i in range(25):
            semiLMNode.GetMarkupPoint(0, i, point)
            sampleArray[i, :] = point
        sampleDistances = self.distanceMatrix(sampleArray)
        minimumMeshSpacing = sampleDistances[sampleDistances.nonzero()].min(
            axis=0)
        rayLength = minimumMeshSpacing * (scaleProjection)

        for i in range(baseLMNode.GetNumberOfFiducials()):
            baseLMNode.GetMarkupPoint(0, i, point)
            targetPoints.InsertNextPoint(point)

        for meshFileName in os.listdir(meshDirectory):
            if (not meshFileName.startswith(".")):
                print(meshFileName)
                lmFileList = os.listdir(lmDirectory)
                meshFilePath = os.path.join(meshDirectory, meshFileName)
                regex = re.compile(r'\d+')
                subjectID = [int(x) for x in regex.findall(meshFileName)][0]
                for lmFileName in lmFileList:
                    if str(subjectID) in lmFileName:
                        # if mesh and lm file with same subject id exist, load into scene
                        currentMeshNode = slicer.util.loadModel(meshFilePath)
                        lmFilePath = os.path.join(lmDirectory, lmFileName)
                        success, currentLMNode = slicer.util.loadMarkupsFiducialList(
                            lmFilePath)

                        # set up transform between base lms and current lms
                        sourcePoints = vtk.vtkPoints()
                        for i in range(currentLMNode.GetNumberOfMarkups()):
                            currentLMNode.GetMarkupPoint(0, i, point)
                            sourcePoints.InsertNextPoint(point)

                        transform = vtk.vtkThinPlateSplineTransform()
                        transform.SetSourceLandmarks(sourcePoints)
                        transform.SetTargetLandmarks(targetPoints)
                        transform.SetBasisToR()  # for 3D transform

                        transformNode = slicer.mrmlScene.AddNewNodeByClass(
                            "vtkMRMLTransformNode", "TPS")
                        transformNode.SetAndObserveTransformToParent(transform)

                        # apply transform to the current surface mesh
                        currentMeshNode.SetAndObserveTransformNodeID(
                            transformNode.GetID())
                        slicer.vtkSlicerTransformLogic().hardenTransform(
                            currentMeshNode)

                        # project semi-landmarks
                        resampledLandmarkNode = slicer.mrmlScene.AddNewNodeByClass(
                            'vtkMRMLMarkupsFiducialNode',
                            meshFileName + '_SL_warped')
                        success = SLLogic.projectPoints(
                            baseMeshNode, currentMeshNode, semiLMNode,
                            resampledLandmarkNode, rayLength)

                        transformNode.Inverse()
                        resampledLandmarkNode.SetAndObserveTransformNodeID(
                            transformNode.GetID())
                        slicer.vtkSlicerTransformLogic().hardenTransform(
                            resampledLandmarkNode)

                        # transfer point data
                        for index in range(
                                semiLMNode.GetNumberOfControlPoints()):
                            fiducialLabel = semiLMNode.GetNthControlPointLabel(
                                index)
                            fiducialDescription = semiLMNode.GetNthControlPointDescription(
                                index)
                            resampledLandmarkNode.SetNthControlPointLabel(
                                index, fiducialLabel)
                            resampledLandmarkNode.SetNthControlPointDescription(
                                index, fiducialDescription)

                        # save output file
                        outputFileName = meshFileName + '_SL_warped' + outputExtension
                        outputFilePath = os.path.join(ouputDirectory,
                                                      outputFileName)
                        slicer.util.saveNode(resampledLandmarkNode,
                                             outputFilePath)

                        # clean up
                        slicer.mrmlScene.RemoveNode(resampledLandmarkNode)
                        slicer.mrmlScene.RemoveNode(currentLMNode)
                        slicer.mrmlScene.RemoveNode(currentMeshNode)
                        slicer.mrmlScene.RemoveNode(transformNode)
p2.InsertNextPoint(-100,-100,-50)
p1.InsertNextPoint(-100,-100,50)
p2.InsertNextPoint(-100,-100,50)
p1.InsertNextPoint(-100,100,-50)
p2.InsertNextPoint(-100,100,-50)
p1.InsertNextPoint(-100,100,50)
p2.InsertNextPoint(-100,100,50)
p1.InsertNextPoint(100,-100,-50)
p2.InsertNextPoint(100,-100,-50)
p1.InsertNextPoint(100,-100,50)
p2.InsertNextPoint(100,-100,50)
p1.InsertNextPoint(100,100,-50)
p2.InsertNextPoint(100,100,-50)
p1.InsertNextPoint(100,100,50)
p2.InsertNextPoint(100,100,50)
transform = vtk.vtkThinPlateSplineTransform()
transform.SetSourceLandmarks(p1)
transform.SetTargetLandmarks(p2)
transform.SetBasisToR()
gridThinPlate = vtk.vtkTransformToGrid()
gridThinPlate.SetInput(transform)
gridThinPlate.SetGridExtent(0,64,0,64,0,50)
gridThinPlate.SetGridSpacing(3.2,3.2,3.0)
gridThinPlate.SetGridOrigin(-102.4,-102.4,-75)
gridThinPlate.SetGridScalarTypeToUnsignedChar()
gridThinPlate.Update()
gridTransform = vtk.vtkGridTransform()
gridTransform.SetDisplacementGridData(gridThinPlate.GetOutput())
gridTransform.SetDisplacementShift(gridThinPlate.GetDisplacementShift())
gridTransform.SetDisplacementScale(gridThinPlate.GetDisplacementScale())
reslice = vtk.vtkImageReslice()
Example #33
0
def volumetric_spline_augmentation(file, save_name='', save_points=0):
    #file = '0212.vtk'
    file_name = 'C:/Users/lowes/OneDrive/Skrivebord/DTU/6_Semester/Bachelor/LAA_segmentation/' + file
    path = 'C:/Users/lowes/OneDrive/Skrivebord/DTU/6_Semester/Bachelor/Augmented_data/'
    out_name = path + file.split('.')[0] + 'aug' + save_name + '.vtk'

    pd_in = vtk.vtkPolyDataReader()
    pd_in.SetFileName(file_name)
    pd_in.Update()

    pd = pd_in.GetOutput()

    # Get bounding box
    bounds = pd.GetBounds()
    x_min = bounds[0]
    x_max = bounds[1]
    y_min = bounds[2]
    y_max = bounds[3]
    z_min = bounds[4]
    z_max = bounds[5]

    # get a measure of scale as the diagonal length
    scale = math.sqrt((x_max - x_min) * (x_max - x_min) + (y_max - y_min) *
                      (y_max - y_min) + (z_max - z_min) * (z_max - z_min))

    # Reference points
    # Here just corners of the bounding box
    # TODO: make more points
    n = 3
    i = 0
    p1 = vtk.vtkPoints()
    p1.SetNumberOfPoints(n * n * n)

    xlin = np.linspace(x_min, x_max, n)
    ylin = np.linspace(y_min, y_max, n)
    zlin = np.linspace(z_min, z_max, n)

    for x in xlin:
        for y in ylin:
            for z in zlin:
                p1.SetPoint(i, x, y, z)
                i += 1
    '''
    p1.SetPoint(0, x_min, y_min, z_min)
    p1.SetPoint(1, x_max, y_min, z_min)
    p1.SetPoint(2, x_min, y_max, z_min)
    p1.SetPoint(3, x_max, y_max, z_min)
    p1.SetPoint(4, x_min, y_min, z_max)
    p1.SetPoint(5, x_max, y_min, z_max)
    p1.SetPoint(6, x_min, y_max, z_max)
    p1.SetPoint(7, x_max, y_max, z_max)
    '''
    # Deformed points
    p2 = vtk.vtkPoints()
    # Start by copying all info from p1
    p2.DeepCopy(p1)

    # Displace the points in a random direction
    displacement_length = scale * 0.05  #change parameter around a bit
    for i in range(p2.GetNumberOfPoints()):
        p = list(p2.GetPoint(i))
        for j in range(3):
            p[j] = p[j] + (2.0 * random() - 1) * displacement_length
        p2.SetPoint(i, p)

    transform = vtk.vtkThinPlateSplineTransform()
    transform.SetSourceLandmarks(p1)
    transform.SetTargetLandmarks(p2)
    transform.SetBasisToR2LogR()
    transform.Update()

    transform_filter = vtk.vtkTransformPolyDataFilter()
    transform_filter.SetTransform(transform)
    transform_filter.SetInputData(pd)
    transform_filter.Update()

    vs = np.array(transform_filter.GetOutput().GetPoints().GetData())
    face_labels = np.array(
        transform_filter.GetOutput().GetCellData().GetScalars())
    poly = dsa.WrapDataObject(transform_filter.GetOutput()).Polygons
    faces = np.reshape(poly, (-1, 4))[:, 1:4]

    print('writing file')
    #vcolor = []
    with open(out_name, 'w+') as f:
        f.write(
            "# vtk DataFile Version 4.2 \nvtk output \nASCII \n \nDATASET POLYDATA \nPOINTS %d float \n"
            % len(vs))
        for vi, v in enumerate(vs):
            #vcol = ' %f %f %f' % (vcolor[vi, 0], vcolor[vi, 1], vcolor[vi, 2]) if vcolor is not None else ''
            f.write("%f %f %f\n" % (v[0], v[1], v[2]))
        f.write("POLYGONS %d %d \n" % (len(faces), 4 * len(faces)))
        for face_id in range(len(faces) - 1):
            f.write("3 %d %d %d\n" %
                    (faces[face_id][0], faces[face_id][1], faces[face_id][2]))
        f.write("3 %d %d %d" % (faces[-1][0], faces[-1][1], faces[-1][2]))
        f.write(
            "\n \nCELL_DATA %d \nSCALARS scalars double \nLOOKUP_TABLE default"
            % len(faces))
        for j, face in enumerate(faces):
            if j % 9 == 0:
                f.write("\n")
            f.write("%d " % face_labels[j])
    print('done writing')
    if save_points:
        fig = plt.figure()
        ax = fig.add_subplot(projection='3d')
        points = np.asarray(p1.GetData())
        ax.scatter(points[:, 0], points[:, 1], points[:, 2], linewidth=8)
        #plt.show()

        #fig = plt.figure()
        #ax = fig.add_subplot(projection='3d')
        points = np.asarray(p2.GetData())
        ax.scatter(points[:, 0],
                   points[:, 1],
                   points[:, 2],
                   linewidth=8,
                   marker='x')
        plt.show()

        vs1 = np.array(p1.GetData())
        out_p1 = path + file.split('.')[0] + '_p1.vtk'
        with open(out_p1, 'w+') as f:
            f.write(
                "# vtk DataFile Version 4.2 \nvtk output \nASCII \n \nDATASET POLYDATA \nPOINTS %d float \n"
                % len(vs1))
            for vi, v in enumerate(vs1):
                f.write("%f %f %f\n" % (v[0], v[1], v[2]))
                vs = np.array(p1.GetData())
        vs2 = np.array(p2.GetData())
        out_p2 = path + file.split('.')[0] + '_p2.vtk'
        with open(out_p2, 'w+') as f:
            f.write(
                "# vtk DataFile Version 4.2 \nvtk output \nASCII \n \nDATASET POLYDATA \nPOINTS %d float \n"
                % len(vs2))
            for vi, v in enumerate(vs2):
                f.write("%f %f %f\n" % (v[0], v[1], v[2]))
    '''
Example #34
0
def fit_srep(obj_mesh, standard_ellipsoid):
    eps = np.finfo(float).eps
    num_pts = obj_mesh.GetNumberOfPoints()
    coords_mat = np.zeros((num_pts, 3))
    for i in range(num_pts):
        pt = obj_mesh.GetPoint(i)
        coords_mat[i, :] = pt
    input_center = np.mean(coords_mat, axis=0)[np.newaxis, :]

    num_pts = standard_ellipsoid.GetNumberOfPoints()
    coords_mat = np.zeros((num_pts, 3))
    for i in range(num_pts):
        pt = standard_ellipsoid.GetPoint(i)
        coords_mat[i, :] = pt
    ell_center = np.mean(coords_mat, axis=0)[np.newaxis, :]

    transVec = input_center[0] - ell_center[0]

    for i in range(num_pts):
        ell_pt = standard_ellipsoid.GetPoint(i)
        pt = list(ell_pt)
        pt = [pt[0] + transVec[0], pt[1] + transVec[1], pt[2] + transVec[2]]
        pt = tuple(pt)
        standard_ellipsoid.GetPoints().SetPoint(i, pt)

    num_pts = standard_ellipsoid.GetNumberOfPoints()
    num_crest_points = 24

    coords_mat = np.zeros((num_pts, 3))
    # import matplotlib.pyplot as plt
    # from mpl_toolkits.mplot3d import Axes3D
    # fig = plt.figure()
    # ax = fig.add_subplot(111, projection='3d')

    for i in range(num_pts):
        pt = standard_ellipsoid.GetPoint(i)
        coords_mat[i, :] = pt
        # if i % 5 == 0:
        #     ax.scatter(pt[0], pt[1], pt[2])
    input_center = np.mean(coords_mat, axis=0)[np.newaxis, :]
    centered_coords = coords_mat - input_center

    covariance = np.cov(centered_coords.T) / num_pts
    _, s, vh = np.linalg.svd(covariance)
    rx, ry, rz = 2 * np.sqrt(s * num_pts).T
    #    plt.show()
    #     mass_filter = vtk.vtkMassProperties()
    #     mass_filter.SetInputData(standard_ellipsoid)
    #     mass_filter.Update()
    #     volume = mass_filter.GetVolume()

    #     rx, ry, rz = np.sqrt(s)

    #     ellipsoid_volume = 4 / 3.0 * np.pi * rx * ry * rz
    #     volume_factor = pow(volume/ ellipsoid_volume, 1.0 / 3.0)

    volume_factor = 0.8
    ### notations consistent with wenqi's presentation
    rx *= volume_factor
    ry *= volume_factor
    rz *= volume_factor

    mrx_o = (rx * rx - rz * rz) / rx
    mry_o = (ry * ry - rz * rz) / ry

    ELLIPSE_SCALE = 0.9
    mrb = mry_o * ELLIPSE_SCALE
    mra = mrx_o * ELLIPSE_SCALE

    delta_theta = 2 * np.pi / num_crest_points
    num_steps = 3
    skeletal_pts_x = np.zeros((num_crest_points, num_steps))
    skeletal_pts_y = np.zeros((num_crest_points, num_steps))
    skeletal_pts_z = np.zeros((num_crest_points, num_steps))
    bdry_up_x = np.zeros((num_crest_points, num_steps))
    bdry_up_y = np.zeros((num_crest_points, num_steps))
    bdry_up_z = np.zeros((num_crest_points, num_steps))

    bdry_down_x = np.zeros((num_crest_points, num_steps))
    bdry_down_y = np.zeros((num_crest_points, num_steps))
    bdry_down_z = np.zeros((num_crest_points, num_steps))

    crest_bdry_pts = np.zeros((num_crest_points, 3))
    crest_skeletal_pts = np.zeros((num_crest_points, 3))
    for i in range(num_crest_points):
        theta = np.pi - delta_theta * i
        x = mra * np.cos(theta)
        y = mrb * np.sin(theta)

        mx_ = (mra * mra - mrb * mrb) * np.cos(theta) / mra
        my_ = .0
        dx_ = x - mx_
        dy_ = y - my_

        step_size = 1.0 / float(num_steps - 1)

        for j in range(num_steps):
            sp_x = mx_ + step_size * j * dx_
            sp_y = my_ + step_size * j * dy_

            skeletal_pts_x[i, j] = sp_x
            skeletal_pts_y[i, j] = sp_y
            sin_spoke_angle = sp_y * mrx_o
            cos_spoke_angle = sp_x * mry_o

            # normalize to [-1, 1]
            l = np.sqrt(sin_spoke_angle**2 + cos_spoke_angle**2)
            if l > eps:
                sin_spoke_angle /= l
                cos_spoke_angle /= l
            cos_phi = l / (mrx_o * mry_o)
            sin_phi = np.sqrt(1 - cos_phi**2)
            bdry_x = rx * cos_phi * cos_spoke_angle
            bdry_y = ry * cos_phi * sin_spoke_angle
            bdry_z = rz * sin_phi
            bdry_up_x[i, j] = bdry_x
            bdry_up_y[i, j] = bdry_y
            bdry_up_z[i, j] = bdry_z

            bdry_down_x[i, j] = bdry_x
            bdry_down_y[i, j] = bdry_y
            bdry_down_z[i, j] = -bdry_z

            ## if at the boundary of the ellipse, add crest spokes
            if j == num_steps - 1:
                cx = rx * cos_spoke_angle - sp_x
                cy = ry * sin_spoke_angle - sp_y
                cz = 0
                vec_c = np.asarray([cx, cy, cz])
                norm_c = np.linalg.norm(vec_c)
                dir_c = np.asarray([bdry_x - sp_x, bdry_y - sp_y, 0.0])
                dir_c = dir_c / np.linalg.norm(vec_c)

                crest_spoke = norm_c * dir_c
                crest_bdry_x = crest_spoke[0] + sp_x
                crest_bdry_y = crest_spoke[1] + sp_y
                crest_bdry_z = 0.0

                crest_bdry_pts[i] = np.asarray(
                    [crest_bdry_x, crest_bdry_y, crest_bdry_z])
                crest_skeletal_pts[i] = np.asarray([sp_x, sp_y, 0.0])
    ### Rotate skeletal/implied boundary points as boundary points of the ellipsoid
    rot_obj = np.flipud(vh.T)
    ## make this rotation matrix same with c++ computation with Eigen3
    # rot_obj[0, :] *= -1
    # rot_obj[-1, :] *= -1

    concate_skeletal_pts = np.concatenate((skeletal_pts_x.flatten()[:, np.newaxis], \
                                        skeletal_pts_y.flatten()[:, np.newaxis], \
                                        skeletal_pts_z.flatten()[:, np.newaxis]), \
                                                axis=1)
    concate_bdry_up_pts = np.concatenate((bdry_up_x.flatten()[:, np.newaxis], \
                                    bdry_up_y.flatten()[:, np.newaxis], \
                                    bdry_up_z.flatten()[:, np.newaxis]), axis=1)
    concate_bdry_down_pts = np.concatenate((bdry_down_x.flatten()[:, np.newaxis], \
                                            bdry_down_y.flatten()[:, np.newaxis], \
                                            bdry_down_z.flatten()[:, np.newaxis]), axis=1)

    second_moment_srep = np.matmul(concate_skeletal_pts.T,
                                   concate_skeletal_pts)
    s_srep, v_srep = np.linalg.eig(second_moment_srep)

    rot_srep = v_srep

    rotation = np.matmul(rot_obj, rot_srep)
    rotation = np.flipud(rotation)

    transformed_concate_skeletal_pts = np.matmul(concate_skeletal_pts,
                                                 rotation) + input_center
    transformed_concate_bdry_up_pts = np.matmul(concate_bdry_up_pts,
                                                rotation) + input_center
    transformed_concate_bdry_down_pts = np.matmul(concate_bdry_down_pts,
                                                  rotation) + input_center
    transformed_crest_bdry_pts = np.matmul(crest_bdry_pts,
                                           rotation) + input_center
    transformed_crest_skeletal_pts = np.matmul(crest_skeletal_pts,
                                               rotation) + input_center

    ### Convert spokes to visualizable elements
    up_spokes_poly = vtk.vtkPolyData()
    up_spokes_pts = vtk.vtkPoints()
    up_spokes_cells = vtk.vtkCellArray()
    down_spokes_poly = vtk.vtkPolyData()
    down_spokes_pts = vtk.vtkPoints()
    down_spokes_cells = vtk.vtkCellArray()
    crest_spokes_poly = vtk.vtkPolyData()
    crest_spokes_pts = vtk.vtkPoints()
    crest_spokes_cells = vtk.vtkCellArray()

    for i in range(concate_skeletal_pts.shape[0]):
        id_s = up_spokes_pts.InsertNextPoint(
            transformed_concate_skeletal_pts[i, :])
        id_b = up_spokes_pts.InsertNextPoint(
            transformed_concate_bdry_up_pts[i, :])

        id_sdwn = down_spokes_pts.InsertNextPoint(
            transformed_concate_skeletal_pts[i, :])
        id_down = down_spokes_pts.InsertNextPoint(
            transformed_concate_bdry_down_pts[i, :])

        up_spoke = vtk.vtkLine()
        up_spoke.GetPointIds().SetId(0, id_s)
        up_spoke.GetPointIds().SetId(1, id_b)
        up_spokes_cells.InsertNextCell(up_spoke)

        down_spoke = vtk.vtkLine()
        down_spoke.GetPointIds().SetId(0, id_sdwn)
        down_spoke.GetPointIds().SetId(1, id_down)
        down_spokes_cells.InsertNextCell(down_spoke)

    up_spokes_poly.SetPoints(up_spokes_pts)
    up_spokes_poly.SetLines(up_spokes_cells)
    down_spokes_poly.SetPoints(down_spokes_pts)
    down_spokes_poly.SetLines(down_spokes_cells)

    for i in range(num_crest_points):
        id_crest_s = crest_spokes_pts.InsertNextPoint(
            transformed_crest_skeletal_pts[i, :])
        id_crest_b = crest_spokes_pts.InsertNextPoint(
            transformed_crest_bdry_pts[i, :])
        crest_spoke = vtk.vtkLine()
        crest_spoke.GetPointIds().SetId(0, id_crest_s)
        crest_spoke.GetPointIds().SetId(1, id_crest_b)
        crest_spokes_cells.InsertNextCell(crest_spoke)
    crest_spokes_poly.SetPoints(crest_spokes_pts)
    crest_spokes_poly.SetLines(crest_spokes_cells)

    append_filter = vtk.vtkAppendPolyData()
    append_filter.AddInputData(up_spokes_poly)
    append_filter.AddInputData(down_spokes_poly)
    append_filter.AddInputData(crest_spokes_poly)
    append_filter.Update()

    srep_poly = append_filter.GetOutput()
    input_mesh = standard_ellipsoid

    num_spokes = srep_poly.GetNumberOfCells()
    num_pts = srep_poly.GetNumberOfPoints()
    radii_array = np.zeros(num_spokes)
    dir_array = np.zeros((num_spokes, 3))
    base_array = np.zeros((num_spokes, 3))

    ### read the parameters from s-rep
    for i in range(num_spokes):
        id_base_pt = i * 2
        id_bdry_pt = id_base_pt + 1
        base_pt = np.array(srep_poly.GetPoint(id_base_pt))
        bdry_pt = np.array(srep_poly.GetPoint(id_bdry_pt))

        radius = np.linalg.norm(bdry_pt - base_pt)
        direction = (bdry_pt - base_pt) / radius

        radii_array[i] = radius
        dir_array[i, :] = direction
        base_array[i, :] = base_pt

    def obj_func(radii, grad=None):
        """
        Square of signed distance from tips
        of spokes to the input_mesh
        """
        implicit_distance = vtk.vtkImplicitPolyDataDistance()
        implicit_distance.SetInput(input_mesh)
        total_loss = 0
        for i, radius in enumerate(radii):
            direction = dir_array[i, :]
            base_pt = base_array[i, :]
            bdry_pt = base_pt + radius * direction

            dist = implicit_distance.FunctionValue(bdry_pt)
            total_loss += dist**2
        return total_loss

    # from scipy import optimize as opt
    # minimum = opt.fmin(obj_func, radii_array)

    # minimizer = minimum[0]

    ### optimize the variables (i.e., radii)
    import nlopt
    opt = nlopt.opt(nlopt.LN_NEWUOA, len(radii_array))
    opt.set_min_objective(obj_func)
    opt.set_maxeval(2000)
    minimizer = opt.optimize(radii_array)

    ## update radii of s-rep and return the updated
    num_diff_spokes = 0
    arr_length = vtk.vtkDoubleArray()
    arr_length.SetNumberOfComponents(1)
    arr_length.SetName("spokeLength")

    arr_dirs = vtk.vtkDoubleArray()
    arr_dirs.SetNumberOfComponents(3)
    arr_dirs.SetName("spokeDirection")

    for i in range(num_spokes):
        id_base_pt = i * 2
        id_bdry_pt = id_base_pt + 1
        base_pt = base_array[i, :]
        radius = minimizer[i]
        direction = dir_array[i, :]

        new_bdry_pt = base_pt + radius * direction
        arr_length.InsertNextValue(radius)
        arr_dirs.InsertNextTuple(direction)
        srep_poly.GetPoints().SetPoint(id_bdry_pt, new_bdry_pt)

        if np.abs(np.linalg.norm(new_bdry_pt - base_pt) -
                  radii_array[i]) > eps:
            num_diff_spokes += 1
    #        srep_poly.SetPoint

    srep_poly.GetPointData().AddArray(arr_length)
    srep_poly.GetPointData().AddArray(arr_dirs)
    srep_poly.Modified()
    ell_srep = srep_poly

    target_mesh = obj_mesh
    ell_mesh = standard_ellipsoid

    source_pts = vtk.vtkPoints()
    target_pts = vtk.vtkPoints()
    for i in range(num_pts):
        pt = [0] * 3
        ell_mesh.GetPoint(i, pt)
        source_pts.InsertNextPoint(pt)

        target_mesh.GetPoint(i, pt)
        target_pts.InsertNextPoint(pt)
    source_pts.Modified()
    target_pts.Modified()

    ### Interpolate deformation with thin-plate-spline
    tps = vtk.vtkThinPlateSplineTransform()
    tps.SetSourceLandmarks(source_pts)
    tps.SetTargetLandmarks(target_pts)
    tps.SetBasisToR()
    tps.Modified()

    ### Apply the deformation onto the spokes
    deformed_srep = vtk.vtkPolyData()
    deformed_spokes_ends = vtk.vtkPoints()
    deformed_spoke_lines = vtk.vtkCellArray()
    # refined_srep is a polydata that collects spokes

    for i in range(ell_srep.GetNumberOfCells()):
        base_pt_id = i * 2
        bdry_pt_id = i * 2 + 1
        s_pt = ell_srep.GetPoint(base_pt_id)
        b_pt = ell_srep.GetPoint(bdry_pt_id)

        new_s_pt = tps.TransformPoint(s_pt)
        new_b_pt = tps.TransformPoint(b_pt)

        id0 = deformed_spokes_ends.InsertNextPoint(new_s_pt)
        id1 = deformed_spokes_ends.InsertNextPoint(new_b_pt)

        spoke_line = vtk.vtkLine()
        spoke_line.GetPointIds().SetId(0, id0)
        spoke_line.GetPointIds().SetId(1, id1)
        deformed_spoke_lines.InsertNextCell(spoke_line)
    deformed_srep.SetPoints(deformed_spokes_ends)
    deformed_srep.SetLines(deformed_spoke_lines)
    deformed_srep.Modified()
    return deformed_srep
Example #35
0
    def run(self, landmarkDirectory, meshDirectory, gridLandmarks,
            outputDirectory):
        #read all landmarks
        #landmarks = self.getLandmarks(landmarkDirectory)
        #print("landmark file shape: ", landmarks.shape)
        #[landmarkNumber,dim,subjectNumber] = landmarks.shape
        #get grid points
        #newGridPoints = self.getGridPoints(landmarks, gridLandmarks)
        #reflect gridPoints onto each surface
        #meshList = self.getAllSubjectMeshes(meshDirectory)
        #for i in range(subjectNumber):
        #mesh = self.readMesh(meshList(i))
        #stickToSurface(newGridPoints(:,:,i), mesh)
        # save semi-landmarks
        #self.saveSemiLandmarks(newGridPoints, outputDirectory)

        #Read data
        S = slicer.util.getNode("gor_skull")
        L = slicer.util.getNode("Gorilla_template_LM1")
        surfacePolydata = S.GetPolyData()

        # Set up point locator for later
        pointLocator = vtk.vtkPointLocator()
        pointLocator.SetDataSet(surfacePolydata)
        pointLocator.BuildLocator()
        #set up locater for intersection with normal vector rays
        obbTree = vtk.vtkOBBTree()
        obbTree.SetDataSet(surfacePolydata)
        obbTree.BuildLocator()

        #Set up fiducial grid
        print("Set up grid")
        fiducialPoints = vtk.vtkPoints()
        point = [0, 0, 0]
        for pt in range(L.GetNumberOfControlPoints()):
            L.GetMarkupPoint(pt, 0, point)
            fiducialPoints.InsertNextPoint(point)

        fiducialPolydata = vtk.vtkPolyData()
        fiducialPolydata.SetPoints(fiducialPoints)
        delaunayFilter = vtk.vtkDelaunay2D()
        delaunayFilter.SetInputData(fiducialPolydata)
        delaunayFilter.Update()
        fiducialMesh = delaunayFilter.GetOutput()
        fiducialMeshModel = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLModelNode", "fiducialMesh")
        fiducialMeshModel.SetAndObservePolyData(fiducialMesh)

        #Set up triangle grid for projection
        gridPoints = vtk.vtkPoints()
        sampleRate = 3

        for row in range(sampleRate):
            for col in range(sampleRate):
                if (row + col) < sampleRate:
                    gridPoints.InsertNextPoint(row, col, 0)

        gridPolydata = vtk.vtkPolyData()
        gridPolydata.SetPoints(gridPoints)

        #Set up source and target for triangle transform
        sourcePoints = vtk.vtkPoints()
        targetPoints = vtk.vtkPoints()

        sourcePoints.InsertNextPoint(gridPoints.GetPoint(0))
        sourcePoints.InsertNextPoint(gridPoints.GetPoint(sampleRate - 1))
        sourcePoints.InsertNextPoint(
            gridPoints.GetPoint(gridPoints.GetNumberOfPoints() - 1))

        #set up transform
        transform = vtk.vtkThinPlateSplineTransform()
        transform.SetSourceLandmarks(sourcePoints)
        transform.SetBasisToR()
        transformNode = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLTransformNode", "TPS")
        transformNode.SetAndObserveTransformToParent(transform)

        #Iterate through each triangle in fiducial mesh and project sampled triangle
        idList = vtk.vtkIdList()
        triangleArray = fiducialMesh.GetPolys()
        triangleArray.InitTraversal()

        #define new landmark sets
        semilandmarkPoints = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLMarkupsFiducialNode", "semiLM")
        gridPoints = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLMarkupsFiducialNode", "grid")

        print("Iterate through cells")
        #iterate through each triangle cell in the landmark mesh
        for triangle in range(4):  #(triangleArray.GetNumberOfCells()):
            print("Semilandmark n: ",
                  semilandmarkPoints.GetNumberOfFiducials())
            print("Triangle: ", triangle)
            triangleArray.GetNextCell(idList)
            print(idList)
            targetPoints.Reset()
            for verticeIndex in range(3):
                verticeID = idList.GetId(verticeIndex)
                verticeLocation = fiducialMesh.GetPoint(verticeID)
                targetPoints.InsertNextPoint(verticeLocation)
                print("Adding target point: ", verticeLocation)

            transform.SetTargetLandmarks(targetPoints)
            model = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLModelNode",
                                                       "mesh_resampled")
            model.SetAndObservePolyData(gridPolydata)
            model.SetAndObserveTransformNodeID(transformNode.GetID())
            slicer.vtkSlicerTransformLogic().hardenTransform(model)
            transformedPolydata = model.GetPolyData()

            # #get surface normal from each landmark point
            rayDirection = [0, 0, 0]
            normalArray = surfacePolydata.GetPointData().GetArray("Normals")

            # #calculate average normal from cell landmarks
            for verticeIndex in range(3):
                verticeLocation = targetPoints.GetPoint(verticeIndex)
                closestPointId = pointLocator.FindClosestPoint(verticeLocation)
                tempNormal = normalArray.GetTuple(closestPointId)
                print("Normal: ", tempNormal)
                rayDirection[0] += tempNormal[0]
                rayDirection[1] += tempNormal[1]
                rayDirection[2] += tempNormal[2]

            for dim in range(len(rayDirection)):
                rayDirection[dim] = rayDirection[dim] / 3

            #get a sample distance for quality control
            m1 = model.GetPolyData().GetPoint(0)
            m2 = model.GetPolyData().GetPoint(1)
            #sampleDistance = 3*abs( (m1[0] - m2[0])+(m1[1] - m2[1])+ (m1[2] - m2[2]))
            sampleDistance = fiducialMesh.GetLength() / 10
            print("Sample distance: ", sampleDistance)

            # iterate through each point in the resampled triangle
            for index in range(model.GetPolyData().GetNumberOfPoints()):
                print("Point: ", index)
                modelPoint = model.GetPolyData().GetPoint(index)
                gridPoints.AddFiducialFromArray(modelPoint)
                rayEndPoint = [0, 0, 0]
                for dim in range(len(rayEndPoint)):
                    rayEndPoint[
                        dim] = modelPoint[dim] + rayDirection[dim] * 1000
                intersectionIds = vtk.vtkIdList()
                intersectionPoints = vtk.vtkPoints()
                obbTree.IntersectWithLine(modelPoint, rayEndPoint,
                                          intersectionPoints, intersectionIds)
                #print("Intersections: ", intersectionIds.GetNumberOfIds())
                #if there are intersections, update the point to most external one.
                if intersectionPoints.GetNumberOfPoints() > 0:
                    exteriorPoint = intersectionPoints.GetPoint(
                        intersectionPoints.GetNumberOfPoints() - 1)
                    projectionDistance = abs(
                        (exteriorPoint[0] - modelPoint[0]) +
                        (exteriorPoint[1] - modelPoint[1]) +
                        (exteriorPoint[2] - modelPoint[2]))
                    semilandmarkPoints.AddFiducialFromArray(exteriorPoint)
                #if there are no intersections, reverse the normal vector
                else:
                    for dim in range(len(rayEndPoint)):
                        rayEndPoint[
                            dim] = modelPoint[dim] + rayDirection[dim] * -1000
                    obbTree.IntersectWithLine(modelPoint, rayEndPoint,
                                              intersectionPoints,
                                              intersectionIds)
                    if intersectionPoints.GetNumberOfPoints() > 0:
                        exteriorPoint = intersectionPoints.GetPoint(0)
                        projectionDistance = abs(
                            (exteriorPoint[0] - modelPoint[0]) +
                            (exteriorPoint[1] - modelPoint[1]) +
                            (exteriorPoint[2] - modelPoint[2]))
                        if projectionDistance < sampleDistance:
                            semilandmarkPoints.AddFiducialFromArray(
                                exteriorPoint)
                        else:
                            print("projectionDistance distance: ",
                                  projectionDistance)
                            closestPointId = pointLocator.FindClosestPoint(
                                modelPoint)
                            rayOrigin = surfacePolydata.GetPoint(
                                closestPointId)
                            semilandmarkPoints.AddFiducialFromArray(rayOrigin)

                    #if none in reverse direction, use closest mesh point
                    else:
                        closestPointId = pointLocator.FindClosestPoint(
                            modelPoint)
                        rayOrigin = surfacePolydata.GetPoint(closestPointId)
                        semilandmarkPoints.AddFiducialFromArray(rayOrigin)
            #remove temporary model node
            #slicer.mrmlScene.RemoveNode(model)

        slicer.mrmlScene.RemoveNode(transformNode)
        return True
Example #36
0
p1.SetPoint(3, 255, 255, 0)
p1.SetPoint(4, 96, 96, 0)
p1.SetPoint(5, 96, 159, 0)
p1.SetPoint(6, 159, 159, 0)
p1.SetPoint(7, 159, 96, 0)
p2 = vtk.vtkPoints()
p2.SetNumberOfPoints(8)
p2.SetPoint(0, 0, 0, 0)
p2.SetPoint(1, 0, 255, 0)
p2.SetPoint(2, 255, 0, 0)
p2.SetPoint(3, 255, 255, 0)
p2.SetPoint(4, 96, 159, 0)
p2.SetPoint(5, 159, 159, 0)
p2.SetPoint(6, 159, 96, 0)
p2.SetPoint(7, 96, 96, 0)
thinPlate = vtk.vtkThinPlateSplineTransform()
thinPlate.SetSourceLandmarks(p2)
thinPlate.SetTargetLandmarks(p1)
thinPlate.SetBasisToR2LogR()
# convert the thin plate spline into a grid
transformToGrid = vtk.vtkTransformToGrid()
transformToGrid.SetInput(thinPlate)
transformToGrid.SetGridSpacing(16, 16, 1)
transformToGrid.SetGridOrigin(-0.5, -0.5, 0)
transformToGrid.SetGridExtent(0, 16, 0, 16, 0, 0)
transformToGrid.Update()
transform = vtk.vtkGridTransform()
transform.SetDisplacementGridConnection(transformToGrid.GetOutputPort())
transform.SetInterpolationModeToCubic()
# you must invert the transform before passing it to vtkImageReslice
transform.Inverse()
Example #37
0
def volumetric_spline_augmentation(pd):
    # Get bounding box
    bounds = pd.GetBounds()
    x_min = bounds[0]
    x_max = bounds[1]
    y_min = bounds[2]
    y_max = bounds[3]
    z_min = bounds[4]
    z_max = bounds[5]

    # get a measure of scale as the diagonal length
    scale = math.sqrt((x_max - x_min) * (x_max - x_min) + (y_max - y_min) *
                      (y_max - y_min) + (z_max - z_min) * (z_max - z_min))

    # Reference points
    # Here just corners of the bounding box
    n = 6
    i = 0
    p1 = vtk.vtkPoints()
    p1.SetNumberOfPoints(n * n * n)

    xlin = np.linspace(x_min, x_max, n)
    ylin = np.linspace(y_min, y_max, n)
    zlin = np.linspace(z_min, z_max, n)

    for x in xlin:
        for y in ylin:
            for z in zlin:
                p1.SetPoint(i, x, y, z)
                i += 1

    # Deformed points
    p2 = vtk.vtkPoints()
    # Start by copying all info from p1
    p2.DeepCopy(p1)

    # Displace the points in a random direction
    displacement_length = scale * 0.04  #change parameter around a bit
    for i in range(p2.GetNumberOfPoints()):
        p = list(p2.GetPoint(i))
        for j in range(3):
            p[j] = p[j] + (2.0 * random() - 1) * displacement_length
        p2.SetPoint(i, p)

    transform = vtk.vtkThinPlateSplineTransform()
    transform.SetSourceLandmarks(p1)
    transform.SetTargetLandmarks(p2)
    transform.SetBasisToR()
    transform.Update()

    transform_filter = vtk.vtkTransformPolyDataFilter()
    transform_filter.SetTransform(transform)
    transform_filter.SetInputData(pd)
    transform_filter.Update()

    points = np.array(transform_filter.GetOutput().GetPoints().GetData())
    face_labels = np.array(
        transform_filter.GetOutput().GetCellData().GetScalars())
    poly = dsa.WrapDataObject(transform_filter.GetOutput()).Polygons
    faces = np.reshape(poly, (-1, 4))[:, 1:4]
    return points, faces