vtkInterface.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import vtk, qt, ctk, slicer
  2. import numpy as np
  3. import SimpleITK as sitk
  4. #set of routines to transform images from one form to another, most notably
  5. #numpy to vtk to itk and all possible combinations inbetween. Keep track of
  6. #orientation, origin and spacing between transforms
  7. class vtkInterface:
  8. def __init__(self, parent):
  9. #parent.title = "vtk Interface"
  10. #parent.categories = ["LabKey"]
  11. parent.dependencies = []
  12. parent.title ="vtkInterface"
  13. parent.contributors = ["Andrej Studen (FMF/JSI)"] # replace with "Firstname Lastname (Org)"
  14. parent.helpText = """
  15. Convert native numpy data structures to vtk
  16. """
  17. parent.acknowledgementText = """
  18. This module was developed within the frame of the ARRS sponsored medical
  19. physics research programe to investigate quantitative measurements of cardiac
  20. function using sestamibi-like tracers
  21. """ # replace with organization, grant and thanks.
  22. self.parent = parent
  23. def numpyToVTK(numpy_array, shape, data_type=vtk.VTK_FLOAT):
  24. v=vtk.vtkImageData()
  25. v.GetPointData().SetScalars(
  26. vtk.util.numpy_support.numpy_to_vtk(
  27. np.ravel(numpy_array,order='F'),deep=True, array_type=data_type))
  28. v.SetOrigin(0,0,0)
  29. v.SetSpacing(1,1,1)
  30. v.SetDimensions(shape)
  31. return v
  32. def completeOrientation(orientation):
  33. o=orientation
  34. o.append(o[1]*o[5]-o[2]*o[4])#0,3
  35. o.append(o[2]*o[3]-o[0]*o[5])#1,4
  36. o.append(o[0]*o[4]-o[1]*o[3])#2,5
  37. return o
  38. def ITK2VTK(img):
  39. #convert itk to vtk format.
  40. #get the array
  41. data=sitk.GetArrayFromImage(img)
  42. #reverse the shape (don't ask, look at vtk manual if really curios)
  43. shape=list(reversed(data.shape))
  44. return numpyToVTK(data.ravel(),shape)
  45. def VTK2ITK(v):
  46. #convert vtk image to sitk image
  47. #convert to numpy first and then go to sitk
  48. scalars=v.GetPointData().GetScalars()
  49. shape=v.GetDimensions()
  50. data=vtk.util.numpy_support.vtk_to_numpy(scalars)
  51. #now convert to sitk (notice the little reversal of the shape)
  52. return sitk.GetImageFromArray(np.reshape(data,list(reversed(shape))))
  53. def ITKfromNode(nodeName):
  54. #use node as data source and generate an itk image
  55. node=slicer.mrmlScene.GetFirstNodeByName(nodeName)
  56. if node==None:
  57. print("Node {0} not available".format(nodeName))
  58. return
  59. img=VTK2ITK(node.GetImageData())
  60. img.SetOrigin(node.GetOrigin())
  61. img.SetSpacing(node.GetSpacing())
  62. m=vtk.vtkMatrix4x4()
  63. node.GetIJKToRASDirectionMatrix(m)
  64. orientation=[0]*9
  65. for i in range(0,3):
  66. for j in range (0,3):
  67. orientation[3*j+i]=m.GetElement(i,j)
  68. img.SetDirection(orientation)
  69. return img
  70. def ITKtoNode(img,nodeName):
  71. #display itk image and assign it a volume node
  72. #useful for displaying outcomes of itk calculations
  73. node=slicer.mrmlScene.GetFirstNodeByName(nodeName)
  74. if node==None:
  75. node=slicer.vtkMRMLScalarVolumeNode()
  76. node.SetName(nodeName)
  77. slicer.mrmlScene.AddNode(node)
  78. node.SetAndObserveImageData(ITK2VTK(img))
  79. #hairy - keep orientation, spacing and origin from node and pass it to itk
  80. #for future reference
  81. spacing=img.GetSpacing()
  82. orientation=img.GetDirection()
  83. origin=img.GetOrigin()
  84. #we should get orientation, spacing and origin from somewhere
  85. ijkToRAS = vtk.vtkMatrix4x4()
  86. for i in range(0,3):
  87. for j in range(0,3):
  88. ijkToRAS.SetElement(i,j,spacing[i]*orientation[3*j+i])
  89. ijkToRAS.SetElement(i,3,origin[i])
  90. node.SetIJKToRASMatrix(ijkToRAS)