resample.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import slicer
  2. import vtk
  3. import os
  4. from slicer.ScriptedLoadableModule import *
  5. class resample(ScriptedLoadableModule):
  6. """Uses ScriptedLoadableModule base class, available at:
  7. https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
  8. """
  9. def __init__(self, parent):
  10. ScriptedLoadableModule.__init__(self, parent)
  11. parent.title = "Resample"
  12. parent.categories = ["Examples"]
  13. parent.dependencies = []
  14. parent.contributors = ["Andrej Studen (FMF/JSI)"] # replace with "Firstname Lastname (Org)"
  15. parent.helpText = """
  16. Resample to different shapes
  17. """
  18. parent.acknowledgementText = """
  19. This module was developed within the frame of the ARRS sponsored medical
  20. physics research programe to investigate quantitative measurements of cardiac
  21. function using sestamibi-like tracers
  22. """ # replace with organization, grant and thanks.
  23. self.parent.helpText += self.getDefaultModuleDocumentationLink()
  24. self.parent = parent
  25. #
  26. # resampleWidget
  27. #
  28. class resampleWidget(ScriptedLoadableModuleWidget):
  29. """Uses ScriptedLoadableModuleWidget base class, available at:
  30. https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
  31. """
  32. def setup(self):
  33. ScriptedLoadableModuleWidget.setup(self)
  34. self.logic=resampleLogic(self)
  35. class resampleLogic(ScriptedLoadableModuleLogic):
  36. """This class should implement all the actual
  37. computation done by your module. The interface
  38. should be such that other python code can import
  39. this class and make use of the functionality without
  40. requiring an instance of the Widget.
  41. Uses ScriptedLoadableModuleLogic base class, available at:
  42. https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
  43. """
  44. def __init__(self,parent):
  45. ScriptedLoadableModuleLogic.__init__(self, parent)
  46. def printMe(self):
  47. print("resampleLogic ready")
  48. def rebinNode(self,node,refNode):
  49. #refNodeName="2SBMIRVolume19"
  50. #nodeName="2SMobrVolume19"
  51. #node=slicer.util.getFirstNodeByName(nodeName)
  52. #refNode=slicer.util.getFirstNodeByName(refNodeName)
  53. #transformNodeName="2SMobr_DF"
  54. #transformNode=slicer.util.getFirstNodeByName(transformNodeName)
  55. #node.SetAndObserveTransformNodeID(transformNode.GetID())
  56. print("rebinNode: {} {}").format(node,refNode)
  57. refImage=refNode.GetImageData()
  58. n=refImage.GetNumberOfPoints()
  59. refIJKtoRAS=vtk.vtkMatrix4x4()
  60. refNode.GetIJKToRASMatrix(refIJKtoRAS)
  61. nodeRAStoIJK=vtk.vtkMatrix4x4()
  62. node.GetRASToIJKMatrix(nodeRAStoIJK)
  63. nodeName=node.GetName()
  64. coeff=vtk.vtkImageBSplineCoefficients()
  65. coeff.SetInputData(node.GetImageData())
  66. coeff.SetBorderMode(vtk.VTK_IMAGE_BORDER_CLAMP)
  67. #between 3 and 5
  68. coeff.SetSplineDegree(5)
  69. coeff.Update()
  70. #interpolation ready to use
  71. #this is tought. COpy only links (ie. shallow copy)
  72. newImage=vtk.vtkImageData()
  73. newImage.DeepCopy(refNode.GetImageData())
  74. newScalars=newImage.GetPointData().GetScalars()
  75. #doesn't set the scalars
  76. for i in range(0,n):
  77. refIJK=refImage.GetPoint(i)
  78. refIJK=list(refIJK)
  79. refIJK.append(1)
  80. #shift to world coordinates to match global points
  81. refPos=refIJKtoRAS.MultiplyPoint(refIJK)
  82. refPos=refPos[0:3]
  83. fWorld=[0,0,0]
  84. #apply potential transformations
  85. refNode.TransformPointToWorld(refPos,fWorld)
  86. #now do the opposite on the target node; reuse fPos
  87. nodePos=[0,0,0]
  88. node.TransformPointFromWorld(fWorld,nodePos)
  89. nodePos.append(1)
  90. nodeIJK=nodeRAStoIJK.MultiplyPoint(nodePos)
  91. #here we should apply some sort of interpolation
  92. nodeIJK=nodeIJK[0:3]
  93. v=coeff.Evaluate(nodeIJK)
  94. v0=newScalars.GetTuple1(i)
  95. newScalars.SetTuple1(i,v)
  96. #print("[{}]: {}->{}").format(i,v0,v)
  97. node.SetName(nodeName+"_BU")
  98. newNode=slicer.vtkMRMLScalarVolumeNode()
  99. newNode.SetName(nodeName)
  100. newNode.SetOrigin(refNode.GetOrigin())
  101. newNode.SetSpacing(refNode.GetSpacing())
  102. newNode.SetIJKToRASMatrix(refIJKtoRAS)
  103. newNode.SetAndObserveImageData(newImage)
  104. slicer.mrmlScene.AddNode(newNode)
  105. class resampleTest(ScriptedLoadableModuleTest):
  106. """
  107. This is the test case for your scripted module.
  108. Uses ScriptedLoadableModuleTest base class, available at:
  109. https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
  110. """
  111. def setUp(self):
  112. """ Do whatever is needed to reset the state - typically a scene clear will be enough.
  113. """
  114. slicer.mrmlScene.Clear(0)
  115. refNodeName="2SBMIRVolume19"
  116. nodeName="2SMobrVolume19"
  117. transformNodeName="2SMobr_DF"
  118. path="c:\\Users\\studen\\labkeyCache\\dinamic_spect\\Patients\\@files"
  119. refPath=os.path.join(path,"2SBMIR")
  120. refPath=os.path.join(refPath,refNodeName+".nrrd")
  121. slicer.util.loadNodeFromFile(refPath,'VolumeFile')
  122. transformPath=os.path.join(path,"2SMobr")
  123. transformPath=os.path.join(transformPath,transformNodeName+".h5")
  124. slicer.util.loadNodeFromFile(transformPath,'TransformFile')
  125. nodePath=os.path.join(path,"2SMobr")
  126. nodePath=os.path.join(nodePath,nodeName+".nrrd")
  127. slicer.util.loadNodeFromFile(nodePath,'VolumeFile')
  128. self.node=slicer.util.getFirstNodeByName(nodeName)
  129. self.refNode=slicer.util.getFirstNodeByName(refNodeName)
  130. self.transformNode=slicer.util.getFirstNodeByName(transformNodeName)
  131. self.node.SetAndObserveTransformNodeID(self.transformNode.GetID())
  132. self.resampler=resampleLogic(None)
  133. def runTest(self):
  134. """Run as few or as many tests as needed here.
  135. """
  136. self.setUp()
  137. self.test_resample()
  138. def test_resample(self):
  139. """ Ideally you should have several levels of tests. At the lowest level
  140. tests should exercise the functionality of the logic with different inputs
  141. (both valid and invalid). At higher levels your tests should emulate the
  142. way the user would interact with your code and confirm that it still works
  143. the way you intended.
  144. One of the most important features of the tests is that it should alert other
  145. developers when their changes will have an impact on the behavior of your
  146. module. For example, if a developer removes a feature that you depend on,
  147. your test should break so they know that the feature is needed.
  148. """
  149. self.delayDisplay("Starting the test")
  150. #
  151. # first, get some data
  152. #
  153. self.resampler.rebinNode(self.node,self.refNode)
  154. self.delayDisplay('Test passed!')