Ejemplo n.º 1
0
def emptyGridTransform(transformSize=[193, 229, 193],
                       transformOrigin=[-96.0, -132.0, -78.0],
                       transformSpacing=[1.0, 1.0, 1.0],
                       transformNode=None):

    if not transformNode:
        transformNode = slicer.mrmlScene.AddNewNodeByClass(
            'vtkMRMLGridTransformNode')

    voxelType = vtk.VTK_FLOAT
    fillVoxelValue = 0
    # Create an empty image volume, filled with fillVoxelValue
    imageData = vtk.vtkImageData()
    imageData.SetDimensions(transformSize)
    imageData.AllocateScalars(voxelType, 3)
    imageData.GetPointData().GetScalars().Fill(fillVoxelValue)
    # Create transform
    transform = slicer.vtkOrientedGridTransform()
    transform.SetInterpolationModeToCubic()
    transform.SetDisplacementGridData(imageData)
    # Create transform node
    transformNode.SetAndObserveTransformFromParent(transform)
    transformNode.GetTransformFromParent().GetDisplacementGrid().SetOrigin(
        transformOrigin)
    transformNode.GetTransformFromParent().GetDisplacementGrid().SetSpacing(
        transformSpacing)

    return transformNode
Ejemplo n.º 2
0
        def gridTransformFromCorners(self, volumeNode, sourceCorners,
                                     targetCorners):
            """Create a grid transform that maps between the current and the desired corners.
      """
            # sanity check
            columns, rows, slices = volumeNode.GetImageData().GetDimensions()
            cornerShape = (slices, 2, 2, 3)
            if not (sourceCorners.shape == cornerShape
                    and targetCorners.shape == cornerShape):
                raise Exception(
                    "Corner shapes do not match volume dimensions %s, %s, %s" %
                    (sourceCorners.shape, targetCorners.shape, cornerShape))

            # create the grid transform node
            gridTransform = slicer.vtkMRMLGridTransformNode()
            gridTransform.SetName(
                slicer.mrmlScene.GenerateUniqueName(volumeNode.GetName() +
                                                    ' acquisition transform'))
            slicer.mrmlScene.AddNode(gridTransform)

            # place grid transform in the same subject hierarchy folder as the volume node
            shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(
                slicer.mrmlScene)
            volumeParentItemId = shNode.GetItemParent(
                shNode.GetItemByDataNode(volumeNode))
            shNode.SetItemParent(shNode.GetItemByDataNode(gridTransform),
                                 volumeParentItemId)

            # create a grid transform with one vector at the corner of each slice
            # the transform is in the same space and orientation as the volume node
            gridImage = vtk.vtkImageData()
            gridImage.SetOrigin(*volumeNode.GetOrigin())
            gridImage.SetDimensions(2, 2, slices)
            sourceSpacing = volumeNode.GetSpacing()
            gridImage.SetSpacing(sourceSpacing[0] * columns,
                                 sourceSpacing[1] * rows, sourceSpacing[2])
            gridImage.AllocateScalars(vtk.VTK_DOUBLE, 3)
            transform = slicer.vtkOrientedGridTransform()
            directionMatrix = vtk.vtkMatrix4x4()
            volumeNode.GetIJKToRASDirectionMatrix(directionMatrix)
            transform.SetGridDirectionMatrix(directionMatrix)
            transform.SetDisplacementGridData(gridImage)
            gridTransform.SetAndObserveTransformToParent(transform)
            volumeNode.SetAndObserveTransformNodeID(gridTransform.GetID())

            # populate the grid so that each corner of each slice
            # is mapped from the source corner to the target corner
            displacements = slicer.util.arrayFromGridTransform(gridTransform)
            for sliceIndex in range(slices):
                for row in range(2):
                    for column in range(2):
                        displacements[sliceIndex][row][column] = targetCorners[
                            sliceIndex][row][column] - sourceCorners[
                                sliceIndex][row][column]
    def onExportGrid(self):
        """Converts the current thin plate transform to a grid"""
        self.hotUpdateButton = None
        state = self.registrationState()

        # since the transform is ras-to-ras, we find the extreme points
        # in ras space of the fixed (target) volume and fix the unoriented
        # box around it.  Sample the grid transform at the resolution of
        # the fixed volume, which may be a bit overkill but it should aways
        # work without too much loss.
        rasBounds = [
            0,
        ] * 6
        state.fixed.GetRASBounds(rasBounds)
        from math import floor, ceil
        origin = list(map(int, map(floor, rasBounds[::2])))
        maxes = list(map(int, map(ceil, rasBounds[1::2])))
        boundSize = [m - o for m, o in zip(maxes, origin)]
        spacing = state.fixed.GetSpacing()
        samples = [ceil(int(b / s)) for b, s in zip(boundSize, spacing)]
        extent = [
            0,
        ] * 6
        extent[::2] = [
            0,
        ] * 3
        extent[1::2] = samples
        extent = list(map(int, extent))

        toGrid = vtk.vtkTransformToGrid()
        toGrid.SetGridOrigin(origin)
        toGrid.SetGridSpacing(state.fixed.GetSpacing())
        toGrid.SetGridExtent(extent)
        toGrid.SetInput(
            state.transform.GetTransformFromParent())  # same in VTKv 5 & 6
        toGrid.Update()

        gridTransform = slicer.vtkOrientedGridTransform()
        if vtk.VTK_MAJOR_VERSION < 6:
            gridTransform.SetDisplacementGrid(
                toGrid.GetOutput())  # different in VTKv 5 & 6
        else:
            gridTransform.SetDisplacementGridData(toGrid.GetOutput())
        gridNode = slicer.vtkMRMLGridTransformNode()
        gridNode.SetAndObserveTransformFromParent(gridTransform)
        gridNode.SetName(state.transform.GetName() + "-grid")
        slicer.mrmlScene.AddNode(gridNode)
Ejemplo n.º 4
0
    def gridTransformFromCorners(self,volumeNode,sourceCorners,targetCorners):
      """Create a grid transform that maps between the current and the desired corners.
      """
      # sanity check
      columns, rows, slices = volumeNode.GetImageData().GetDimensions()
      cornerShape = (slices, 2, 2, 3)
      if not (sourceCorners.shape == cornerShape and targetCorners.shape == cornerShape):
        raise Exception("Corner shapes do not match volume dimensions %s, %s, %s" %
                          (sourceCorners.shape, targetCorners.shape, cornerShape))

      # create the grid transform node
      gridTransform = slicer.vtkMRMLGridTransformNode()
      gridTransform.SetName(slicer.mrmlScene.GenerateUniqueName(volumeNode.GetName()+' acquisition transform'))
      slicer.mrmlScene.AddNode(gridTransform)

      # place grid transform in the same subject hierarchy folder as the volume node
      shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene)
      volumeParentItemId = shNode.GetItemParent(shNode.GetItemByDataNode(volumeNode))
      shNode.SetItemParent(shNode.GetItemByDataNode(gridTransform), volumeParentItemId)

      # create a grid transform with one vector at the corner of each slice
      # the transform is in the same space and orientation as the volume node
      gridImage = vtk.vtkImageData()
      gridImage.SetOrigin(*volumeNode.GetOrigin())
      gridImage.SetDimensions(2, 2, slices)
      sourceSpacing = volumeNode.GetSpacing()
      gridImage.SetSpacing(sourceSpacing[0] * columns, sourceSpacing[1] * rows, sourceSpacing[2])
      gridImage.AllocateScalars(vtk.VTK_DOUBLE, 3)
      transform = slicer.vtkOrientedGridTransform()
      directionMatrix = vtk.vtkMatrix4x4()
      volumeNode.GetIJKToRASDirectionMatrix(directionMatrix)
      transform.SetGridDirectionMatrix(directionMatrix)
      transform.SetDisplacementGridData(gridImage)
      gridTransform.SetAndObserveTransformToParent(transform)
      volumeNode.SetAndObserveTransformNodeID(gridTransform.GetID())

      # populate the grid so that each corner of each slice
      # is mapped from the source corner to the target corner
      displacements = slicer.util.arrayFromGridTransform(gridTransform)
      for sliceIndex in range(slices):
        for row in range(2):
          for column in range(2):
            displacements[sliceIndex][row][column] = targetCorners[sliceIndex][row][column] - sourceCorners[sliceIndex][row][column]
Ejemplo n.º 5
0
    def createAcquisitionTransform(self, volumeNode, metadata):

        # Creates transform that applies scan conversion transform
        probeRadius = metadata['CurvatureRadiusProbe']
        trackRadius = metadata['CurvatureRadiusTrack']
        if trackRadius != 0.0:
            raise ValueError(f"Curvature Radius (Track) is {trackRadius}. Currently, only volume with zero radius can be imported.")

        # Create a sampling grid for the transform
        import numpy as np
        spacing = np.array(volumeNode.GetSpacing())
        averageSpacing = (spacing[0] + spacing[1] + spacing[2]) / 3.0
        voxelsPerTransformControlPoint = 20  # the transform is changing smoothly, so we don't need to add too many control points
        gridSpacingMm = averageSpacing * voxelsPerTransformControlPoint
        gridSpacingVoxel = np.floor(gridSpacingMm / spacing).astype(int)
        gridAxesIJK = []
        imageData = volumeNode.GetImageData()
        extent = imageData.GetExtent()
        for axis in range(3):
            gridAxesIJK.append(list(range(extent[axis * 2], extent[axis * 2 + 1] + gridSpacingVoxel[axis], gridSpacingVoxel[axis])))
        samplingPoints_shape = [len(gridAxesIJK[0]), len(gridAxesIJK[1]), len(gridAxesIJK[2]), 3]

        # create a grid transform with one vector at the corner of each slice
        # the transform is in the same space and orientation as the volume node
        import vtk
        gridImage = vtk.vtkImageData()
        gridImage.SetOrigin(*volumeNode.GetOrigin())
        gridImage.SetDimensions(samplingPoints_shape[:3])
        gridImage.SetSpacing(gridSpacingVoxel[0] * spacing[0], gridSpacingVoxel[1] * spacing[1], gridSpacingVoxel[2] * spacing[2])
        gridImage.AllocateScalars(vtk.VTK_DOUBLE, 3)
        transform = slicer.vtkOrientedGridTransform()
        directionMatrix = vtk.vtkMatrix4x4()
        volumeNode.GetIJKToRASDirectionMatrix(directionMatrix)
        transform.SetGridDirectionMatrix(directionMatrix)
        transform.SetDisplacementGridData(gridImage)

        # create the grid transform node
        gridTransform = slicer.vtkMRMLGridTransformNode()
        gridTransform.SetName(slicer.mrmlScene.GenerateUniqueName(volumeNode.GetName() + ' acquisition transform'))
        slicer.mrmlScene.AddNode(gridTransform)
        gridTransform.SetAndObserveTransformToParent(transform)

        # populate the grid so that each corner of each slice
        # is mapped from the source corner to the target corner

        nshape = tuple(reversed(gridImage.GetDimensions()))
        nshape = nshape + (3,)
        displacements = vtk.util.numpy_support.vtk_to_numpy(gridImage.GetPointData().GetScalars()).reshape(nshape)

        # Get displacements
        from math import sin, cos
        ijkToRas = vtk.vtkMatrix4x4()
        volumeNode.GetIJKToRASMatrix(ijkToRas)
        spacing = volumeNode.GetSpacing()
        center_IJK = [(extent[0] + extent[1]) / 2.0, extent[2], (extent[4] + extent[5]) / 2.0]
        sourcePoints_RAS = numpy.zeros(shape=samplingPoints_shape)
        targetPoints_RAS = numpy.zeros(shape=samplingPoints_shape)
        for k in range(samplingPoints_shape[2]):
            for j in range(samplingPoints_shape[1]):
                for i in range(samplingPoints_shape[0]):
                    samplingPoint_IJK = [gridAxesIJK[0][i], gridAxesIJK[1][j], gridAxesIJK[2][k], 1]
                    sourcePoint_RAS = np.array(ijkToRas.MultiplyPoint(samplingPoint_IJK)[:3])
                    radius = probeRadius - (samplingPoint_IJK[1] - center_IJK[1]) * spacing[1]
                    angleRad = (samplingPoint_IJK[0] - center_IJK[0]) * spacing[0] / probeRadius
                    targetPoint_RAS = np.array([
                        -radius * sin(angleRad),
                        radius * cos(angleRad) - probeRadius,
                        spacing[2] * (samplingPoint_IJK[2] - center_IJK[2])])
                    displacements[k][j][i] = targetPoint_RAS - sourcePoint_RAS

        return gridTransform
Ejemplo n.º 6
0
    def computeStraighteningTransform(self, transformToStraightenedNode,
                                      curveNode, sliceSizeMm, outputSpacingMm):
        """
    Compute straightened volume (useful for example for visualization of curved vessels)
    resamplingCurveSpacingFactor: 
    """

        # Create a temporary resampled curve
        resamplingCurveSpacing = outputSpacingMm * self.transformSpacingFactor
        originalCurvePoints = curveNode.GetCurvePointsWorld()
        sampledPoints = vtk.vtkPoints()
        if not slicer.vtkMRMLMarkupsCurveNode.ResamplePoints(
                originalCurvePoints, sampledPoints, resamplingCurveSpacing,
                False):
            raise ValueError("Resampling curve failed")
        resampledCurveNode = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLMarkupsCurveNode",
            "CurvedPlanarReformat_resampled_curve_temp")
        resampledCurveNode.SetNumberOfPointsPerInterpolatingSegment(1)
        resampledCurveNode.SetCurveTypeToLinear()
        resampledCurveNode.SetControlPointPositionsWorld(sampledPoints)
        numberOfSlices = resampledCurveNode.GetNumberOfControlPoints()

        # Z axis (from first curve point to last, this will be the straightened curve long axis)
        curveStartPoint = np.zeros(3)
        curveEndPoint = np.zeros(3)
        resampledCurveNode.GetNthControlPointPositionWorld(0, curveStartPoint)
        resampledCurveNode.GetNthControlPointPositionWorld(
            resampledCurveNode.GetNumberOfControlPoints() - 1, curveEndPoint)
        transformGridAxisZ = (
            curveEndPoint - curveStartPoint) / np.linalg.norm(curveEndPoint -
                                                              curveStartPoint)

        # X axis = average X axis of curve, to minimize torsion (and so have a simple displacement field, which can be robustly inverted)
        sumCurveAxisX_RAS = np.zeros(3)
        for gridK in range(numberOfSlices):
            curvePointToWorld = vtk.vtkMatrix4x4()
            resampledCurveNode.GetCurvePointToWorldTransformAtPointIndex(
                resampledCurveNode.GetCurvePointIndexFromControlPointIndex(
                    gridK), curvePointToWorld)
            curvePointToWorldArray = slicer.util.arrayFromVTKMatrix(
                curvePointToWorld)
            curveAxisX_RAS = curvePointToWorldArray[0:3, 0]
            sumCurveAxisX_RAS += curveAxisX_RAS
        meanCurveAxisX_RAS = sumCurveAxisX_RAS / np.linalg.norm(
            sumCurveAxisX_RAS)
        transformGridAxisX = meanCurveAxisX_RAS

        # Y axis
        transformGridAxisY = np.cross(transformGridAxisZ, transformGridAxisX)
        transformGridAxisY = transformGridAxisY / np.linalg.norm(
            transformGridAxisY)

        # Make sure that X axis is orthogonal to Y and Z
        transformGridAxisX = np.cross(transformGridAxisY, transformGridAxisZ)
        transformGridAxisX = transformGridAxisX / np.linalg.norm(
            transformGridAxisX)

        # Origin (makes the grid centered at the curve)
        curveLength = resampledCurveNode.GetCurveLengthWorld()
        curveNodePlane = vtk.vtkPlane()
        slicer.modules.markups.logic().GetBestFitPlane(resampledCurveNode,
                                                       curveNodePlane)
        transformGridOrigin = np.array(curveNodePlane.GetOrigin())
        transformGridOrigin -= transformGridAxisX * sliceSizeMm[0] / 2.0
        transformGridOrigin -= transformGridAxisY * sliceSizeMm[1] / 2.0
        transformGridOrigin -= transformGridAxisZ * curveLength / 2.0

        # Create grid transform
        # Each corner of each slice is mapped from the original volume's reformatted slice
        # to the straightened volume slice.
        # The grid transform contains one vector at the corner of each slice.
        # The transform is in the same space and orientation as the straightened volume.

        gridDimensions = [2, 2, numberOfSlices]
        gridSpacing = [sliceSizeMm[0], sliceSizeMm[1], resamplingCurveSpacing]
        gridDirectionMatrixArray = np.eye(4)
        gridDirectionMatrixArray[0:3, 0] = transformGridAxisX
        gridDirectionMatrixArray[0:3, 1] = transformGridAxisY
        gridDirectionMatrixArray[0:3, 2] = transformGridAxisZ
        gridDirectionMatrix = slicer.util.vtkMatrixFromArray(
            gridDirectionMatrixArray)

        gridImage = vtk.vtkImageData()
        gridImage.SetOrigin(transformGridOrigin)
        gridImage.SetDimensions(gridDimensions)
        gridImage.SetSpacing(gridSpacing)
        gridImage.AllocateScalars(vtk.VTK_DOUBLE, 3)
        transform = slicer.vtkOrientedGridTransform()
        transform.SetDisplacementGridData(gridImage)
        transform.SetGridDirectionMatrix(gridDirectionMatrix)
        transformToStraightenedNode.SetAndObserveTransformFromParent(transform)

        # Compute displacements
        transformDisplacements_RAS = slicer.util.arrayFromGridTransform(
            transformToStraightenedNode)
        for gridK in range(gridDimensions[2]):
            curvePointToWorld = vtk.vtkMatrix4x4()
            resampledCurveNode.GetCurvePointToWorldTransformAtPointIndex(
                resampledCurveNode.GetCurvePointIndexFromControlPointIndex(
                    gridK), curvePointToWorld)
            curvePointToWorldArray = slicer.util.arrayFromVTKMatrix(
                curvePointToWorld)
            curveAxisX_RAS = curvePointToWorldArray[0:3, 0]
            curveAxisY_RAS = curvePointToWorldArray[0:3, 1]
            curvePoint_RAS = curvePointToWorldArray[0:3, 3]
            for gridJ in range(gridDimensions[1]):
                for gridI in range(gridDimensions[0]):
                    straightenedVolume_RAS = (
                        transformGridOrigin +
                        gridI * gridSpacing[0] * transformGridAxisX +
                        gridJ * gridSpacing[1] * transformGridAxisY +
                        gridK * gridSpacing[2] * transformGridAxisZ)
                    inputVolume_RAS = (
                        curvePoint_RAS +
                        (gridI - 0.5) * sliceSizeMm[0] * curveAxisX_RAS +
                        (gridJ - 0.5) * sliceSizeMm[1] * curveAxisY_RAS)
                    transformDisplacements_RAS[gridK][gridJ][
                        gridI] = inputVolume_RAS - straightenedVolume_RAS
        slicer.util.arrayFromGridTransformModified(transformToStraightenedNode)

        slicer.mrmlScene.RemoveNode(
            resampledCurveNode)  # delete temporary curve