Cube Segments / Conversion of ROIs into Segments

Dear Slicers,

I have a project where I want to place a number of 2x2x2cm voxels on brain scans to imitate MR Spectroscopy voxel placement. It seems that using ROIs to generate these is the best approach, however, I couldn’t find an efficient way to convert these CUBIC ROIs into Segments/Label maps.

Is there a solution for this?

Thank you!

1 Like

Well, figured it out. You create a template Segment using thresholding 0-to-max (i.e. to select all voxels). Convert the segment to a labelmap. Use this labelmap with Crop Volume module and use the ROI for cropping, and there you go. A labelmap with shaped exactly as the ROI.

1 Like

Flood fill effect in aegment editor extra effects extension takes an ROi.

That may save you a couple steps.

1 Like

Neat! Thank you!

I tested it (see below). It seems like the Flood Fill provides an approximation of the ROI, while Crop will make it match the ROI’s exact dimensions.

Probably the scalable solution will be a python script for Batch Cropping. I’ll share once I made it.

Thank you again!

To me, they align quite well. The extra space outside of the ROI is due your spacing. Segmentation has to follow the voxel boundaries.

If you want to ROI boundary and the segmentation to align more precisely, you can increase the resolution of the segmentation (but of course that will also increase the memory consumption).

(purple is output of flood will, red box is the ROI).

What is doesn’t work well with the rotated ROIs though.

@lassoan is it possible to add this feature?

You may have a look at a custom module, Markups to surface, that can handle a rotated ROI. It could probably fit this requirement.

But then It would still have to be converted to a segment or label map. So it’s 1 step less to just have a hi-resolution template file to Crop to the dimensions of the ROI.

OK, created a script (using chat GPT).

It uses the Template volume (“TEMPLATE_for_CROPPING”), and then the ROIs are named V1…10. And then the script iterates on the ROIs and generates Cropped_V1…Cropped_V10 scalar volumes. Simple but useful. My project is expected to have few hundreds of. Voxels, so this can save substantial amounts of time.

Initialize CropVolume logic

cropVolumeLogic = slicer.modules.cropvolume.logic()

Get the volume node for the template

templateVolumeNode = slicer.util.getNode(‘TEMPLATE_for_CROPPING’)

Loop through ROI nodes V1 to V10

for i in range(1, 11): # Adjust the range based on your actual ROI names
roiName = f"V{i}"
roiNode = slicer.util.getNode(roiName)

if roiNode:  # Only proceed if the ROI node actually exists
    # Create a new CropVolumeParameters Node for each iteration
    cropVolumeNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLCropVolumeParametersNode')
    
    # Set the input volume and ROI for cropping
    cropVolumeNode.SetInputVolumeNodeID(templateVolumeNode.GetID())
    cropVolumeNode.SetROINodeID(roiNode.GetID())
    
    # Apply cropping
    cropVolumeLogic.Apply(cropVolumeNode)
    
    # Get the output volume node
    outputVolumeNode = slicer.mrmlScene.GetNodeByID(cropVolumeNode.GetOutputVolumeNodeID())
    
    # Rename the output volume node to match the ROI with 'Cropped_' prefix
    outputVolumeNode.SetName(f"Cropped_{roiName}")

    # Optionally, save the cropped volume to disk
    # outputPath = f"C:/path/to/save/Cropped_{roiName}.nrrd"
    # slicer.util.saveNode(outputVolumeNode, outputPath)

    # Remove the cropVolumeNode to avoid potential conflicts in the next iteration
    slicer.mrmlScene.RemoveNode(cropVolumeNode)
1 Like