I’m trying to do the following:
(1) oversample a labelmap
(2) modify it in the higher resolution voxel space
(3) update the segmentation node with the modified labelmap
I figured out (1) and (2), but I couldn’t find info on (3).
Any help would be greatly appreciated.
Below is a demo of what I mean:
def apply_oversampling_on_segmentationNode(segmentationNode, inputVolumeNode, oversampling_factor):
segmentationGeometryLogic = slicer.vtkSlicerSegmentationGeometryLogic()
if segmentationGeometryLogic.GetOversamplingFactor() != oversampling_factor:
segmentationGeometryLogic.SetInputSegmentationNode(segmentationNode)
segmentationGeometryLogic.SetSourceGeometryNode(inputVolumeNode)
segmentationGeometryLogic.SetOversamplingFactor(oversampling_factor)
segmentationGeometryLogic.CalculateOutputGeometry()
geometryImageData = segmentationGeometryLogic.GetOutputGeometryImageData()
geometryString = slicer.vtkSegmentationConverter.SerializeImageGeometry(geometryImageData)
segmentationNode.GetSegmentation().SetConversionParameter(slicer.vtkSegmentationConverter.GetReferenceImageGeometryParameterName(), geometryString)
segmentationGeometryLogic.ResampleLabelmapsInSegmentationNode()
else:
geometryImageData = segmentationGeometryLogic.GetOutputGeometryImageData()
return geometryImageData
def get_dims_spacing_origin_from_vtkImageData(geometryImageData):
dims = geometryImageData.GetDimensions()
spacing = geometryImageData.GetSpacing()
origin = geometryImageData.GetOrigin()
return dims, spacing, origin
def modifySegment(segmentArray):
# some random modification
return np.clip(segmentArray + np.random.rand(*segmentArray.shape), 0, 1)
# (1) works
geometryImageData = apply_oversampling_on_segmentationNode(segmentationNode, inputVolumeNode, oversampling_factor=3)
dims, spacing, origin = get_dims_spacing_origin_from_vtkImageData(geometryImageData) # I can use this to get the correct closed surface representation
# (2) works
segmentId = segmentationNode.GetSegmentation().GetSegmentIdBySegmentName(segment_name)
segmentArray = slicer.util.arrayFromSegmentInternalBinaryLabelmap(segmentationNode, segmentId)
newSegmentArray = modifySegment(segmentArray.copy())
# (3) how do I do this properly??
slicer.util.updateSegmentBinaryLabelmapFromArray(newSegmentArray, segmentationNode, segmentId, referenceVolumeNode=inputVolumeNode)
Once the segmentation has the resolution that you need, I would recommend to import the new segments from a labelmap node and delete the old segment (or use Logical operators effect’s Copy method).
You could use slicer.vtkOrientedImageDataResample.ModifyImage to manipulate an existing segment, but it is very hard to do it correctly due to multiple segments sharing a labelmap and further complicated by masking settings.
I am able to get the correct resolution using segGeomLogic.ResampleLabelmapsInSegmentationNode(), but when I try to edit the segment with the new resolution (brush, erase, etc.), it seems to return to the original resolution.
Make sure the master (source) representation is binary labelmap. If it is then give us more information so that we can reproduce what your see and can tell if it is the expected behaviour or something is wrong.
If you are referring to the master representation setting as shown below, I believe I do have binary labelmap as my master representation.
I’m trying to do the following:
Resample label maps programmatically using the code below
Edit the resulting segments with segment editor (brush, erase, etc.)
Expected behavior: Labelmap geometry stays as resampled
Observed behavior: Labelmap geometry converts back to the original geometry before resampling
Test: Specifying Geometry using this button () results in the expected behavior
I successfully created a new segment using slicer.modules.segmentations.logic().ImportLabelmapToSegmentationNode(labelmap_vtkImageData, segmentationNode, segmentName).
But the stored labelmap is clipped to the effective extent. What’s the best way to retrieve the full extent numpy array from the original vtkImageData?
I tried to directly work with vtkImageData without creating a new volume node, but everything worked much better if I just create a volume node for the reference geometry.
Thanks for sharing your experience. Indeed, it makes things simpler if the reference image geometry that is set in the segmentation is the same as the current segmentation geometry.