Skip to content

Commit

Permalink
ENH: Remove use of segmentation nodes in VRG pipeline
Browse files Browse the repository at this point in the history
  • Loading branch information
NicerNewerCar authored and jcfr committed Dec 4, 2023
1 parent b4fd1ec commit 66f93a6
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 @@ -428,7 +428,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 @@ -438,7 +437,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 @@ -457,10 +455,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 @@ -473,7 +469,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 @@ -636,7 +632,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 @@ -647,7 +642,6 @@ def onManualVRGGen(self):
if not self.logic.validateInputs(
markupsNode=markupsNode,
volumeNode=volumeNode,
segmentationNode=segmentationNode,
mainOutputDir=mainOutputDir,
viewAngle=viewAngle,
clippingRange=clippingRange,
Expand All @@ -666,13 +660,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 @@ -682,7 +672,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 @@ -697,12 +687,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 @@ -1036,7 +1025,7 @@ def extractSubVolumeForVRG(
def generateVRGForCameras(
self,
cameras: list[RadiographGeneration.Camera],
volumeImageData: vtk.vtkImageData,
volumeNode: slicer.vtkMRMLVolumeNode,
outputDir: str,
width: int,
height: int,
Expand All @@ -1047,8 +1036,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 @@ -1069,9 +1058,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 @@ -1154,3 +1154,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 66f93a6

Please sign in to comment.