Skip to content

Commit

Permalink
ENH: Remove use of segmentation nodes in VRG pipline
Browse files Browse the repository at this point in the history
  • Loading branch information
NicerNewerCar committed Nov 27, 2023
1 parent f67192b commit da8e480
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 176 deletions.
79 changes: 55 additions & 24 deletions AutoscoperM/AutoscoperM.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,6 @@ def onGenerateVRG(self):
# Set up and validate inputs
volumeNode = self.ui.volumeSelector.currentNode()
mainOutputDir = self.ui.mainOutputSelector.currentPath
segmentationNode = self.ui.vrg_SegNodeComboBox.currentNode()
width = self.ui.vrgRes_width.value
height = self.ui.vrgRes_height.value
nPossibleCameras = self.ui.posCamSpin.value
Expand All @@ -435,7 +434,6 @@ def onGenerateVRG(self):
vrgSubDir = self.ui.vrgSubDir.text
if not self.logic.validateInputs(
volumeNode=volumeNode,
segmentationNode=segmentationNode,
mainOutputDir=mainOutputDir,
width=width,
height=height,
Expand All @@ -454,10 +452,8 @@ def onGenerateVRG(self):
logging.error("Failed to generate VRG: more optimized cameras than possible cameras")
return

# Extract the subvolume for the radiographs
volumeImageData, bounds = self.logic.extractSubVolumeForVRG(
volumeNode, segmentationNode, cameraDebugMode=self.ui.camDebugCheckbox.isChecked()
)
bounds = [0] * 6
volumeNode.GetBounds(bounds)

# Generate all possible camera positions
camOffset = self.ui.camOffSetSpin.value
Expand All @@ -470,7 +466,7 @@ def onGenerateVRG(self):
# Generate initial VRG for each camera
self.logic.generateVRGForCameras(
cameras,
volumeImageData,
volumeNode,
os.path.join(mainOutputDir, tmpDir),
width,
height,
Expand Down Expand Up @@ -633,7 +629,6 @@ def onLoadPV(self):
def onManualVRGGen(self):
markupsNode = self.ui.mVRG_markupSelector.currentNode()
volumeNode = self.ui.volumeSelector.currentNode()
segmentationNode = self.ui.mVRG_segmentationSelector.currentNode()
mainOutputDir = self.ui.mainOutputSelector.currentPath
viewAngle = self.ui.mVRG_viewAngleSpin.value
clippingRange = (self.ui.mVRG_ClippingRangeSlider.minimumValue, self.ui.mVRG_ClippingRangeSlider.maximumValue)
Expand All @@ -644,7 +639,6 @@ def onManualVRGGen(self):
if not self.logic.validateInputs(
markupsNode=markupsNode,
volumeNode=volumeNode,
segmentationNode=segmentationNode,
mainOutputDir=mainOutputDir,
viewAngle=viewAngle,
clippingRange=clippingRange,
Expand All @@ -663,13 +657,9 @@ def onManualVRGGen(self):
if self.logic.vrgManualCameras is None:
self.onMarkupNodeChanged(markupsNode) # create the cameras

volumeImageData, _ = self.logic.extractSubVolumeForVRG(
volumeNode, segmentationNode, cameraDebugMode=self.ui.camDebugCheckbox.isChecked()
)

self.logic.generateVRGForCameras(
self.logic.vrgManualCameras,
volumeImageData,
volumeNode,
os.path.join(mainOutputDir, vrgDir),
width,
height,
Expand All @@ -679,7 +669,7 @@ def onManualVRGGen(self):
self.updateProgressBar(100)

for cam in self.logic.vrgManualCameras:
IO.generateCameraCalibrationFile(cam, os.path.join(mainOutputDir, cameraDir, f"cam{cam.id}.yaml"))
IO.generateCameraCalibrationFile(cam, os.path.join(mainOutputDir, cameraDir, f"cam{cam.id}.json"))

def onMarkupNodeChanged(self, node):
if node is None:
Expand All @@ -694,12 +684,11 @@ def onMarkupNodeChanged(self, node):
for cam in self.logic.vrgManualCameras:
slicer.mrmlScene.RemoveNode(cam.FrustumModel)
self.logic.vrgManualCameras = None
# get the volume and segmentation nodes
segmentationNode = self.ui.mVRG_segmentationSelector.currentNode()
if not self.logic.validateInputs(segmentationNode=segmentationNode):
return
# get the volume nodes
volumeNode = self.ui.volumeSelector.currentNode()
self.logic.validateInputs(volumeNode=volumeNode)
bounds = [0] * 6
segmentationNode.GetBounds(bounds)
volumeNode.GetBounds(bounds)
self.logic.vrgManualCameras = RadiographGeneration.generateCamerasFromMarkups(
node,
bounds,
Expand Down Expand Up @@ -1033,7 +1022,7 @@ def extractSubVolumeForVRG(
def generateVRGForCameras(
self,
cameras: list[RadiographGeneration.Camera],
volumeImageData: vtk.vtkImageData,
volumeNode: slicer.vtkMRMLVolumeNode,
outputDir: str,
width: int,
height: int,
Expand All @@ -1044,8 +1033,8 @@ def generateVRGForCameras(
:param cameras: list of cameras
:type cameras: list[RadiographGeneration.Camera]
:param volumeImageData: volume image data
:type volumeImageData: vtk.vtkImageData
:param volumeNode: volume node
:type volumeNode: slicer.vtkMRMLVolumeNode
:param outputDir: output directory
:type outputDir: str
:param width: width of the radiographs
Expand All @@ -1066,9 +1055,20 @@ def generateVRGForCameras(
def progressCallback(x):
return x

# Apply a thresh of 0 to the volume to remove air from the volume
thresholdScalarVolume = slicer.modules.thresholdscalarvolume
parameters = {
"InputVolume": volumeNode.GetID(),
"OutputVolume": volumeNode.GetID(),
"ThresholdValue": 0,
"ThresholdType": "Below",
"Lower": 0,
}
slicer.cli.runSync(thresholdScalarVolume, None, parameters)

# write a temporary volume to disk
volumeFName = "AutoscoperM_VRG_GEN_TEMP.mhd"
IO.writeTemporyFile(volumeFName, volumeImageData)
IO.writeTemporyFile(volumeFName, self.convertNodeToData(volumeNode))

# Execute CLI for each camera
cliModule = slicer.modules.virtualradiographgeneration
Expand Down Expand Up @@ -1151,3 +1151,34 @@ def progressCallback(x):

progress = ((idx + 1) / len(bestCameras)) * 10 + 90
progressCallback(progress)

def convertNodeToData(self, volumeNode: slicer.vtkMRMLVolumeNode) -> vtk.vtkImageData:
"""
Converts a volume node to a vtkImageData object
"""
imageData = vtk.vtkImageData()
imageData.DeepCopy(volumeNode.GetImageData())
imageData.SetSpacing(volumeNode.GetSpacing())
origin = list(volumeNode.GetOrigin())
imageData.SetOrigin(origin)

mat = vtk.vtkMatrix4x4()
volumeNode.GetIJKToRASMatrix(mat)
if mat.GetElement(0, 0) < 0 and mat.GetElement(1, 1) < 0:
origin[0:2] = [x * -1 for x in origin[0:2]]
imageData.SetOrigin(origin)

# Ensure we are in the correct orientation (RAS vs LPS)
imageReslice = vtk.vtkImageReslice()
imageReslice.SetInputData(imageData)

axes = vtk.vtkMatrix4x4()
axes.Identity()
axes.SetElement(0, 0, -1)
axes.SetElement(1, 1, -1)

imageReslice.SetResliceAxes(axes)
imageReslice.Update()
imageData = imageReslice.GetOutput()

return imageData
Loading

0 comments on commit da8e480

Please sign in to comment.