I want to crop a volume with a fixed size, let’s say 400x400. As far as I know, there is no way to set the dimension of the AnnotationROI in Crop Volume module. (I can do it manually but it’s quite frustrating).
Yes, you can do this using python code. Can you describe in more detail what you want to achieve and I may be able to write you some code for you to do what you need.
What I’m trying to do is cropping a volume with a desired size:
I open my dcm volume that is 512(H)x512(W)x256(depth)
I want to crop it so I have a volume of (for example) 400x400x200 → I want to choose the size in advance, so I don’t need to struggle with the mouse to obtain exactly 400 pixels.
It would be nice if I can place the center of the square (annotation ROI with desired size) whenever I want and then crop the volume.
If you could recommend me any type of tutorial for writing python code for slicer I would appreciate it.
First drop an ROI around the heart like you have shown in the picture above. Make sure the ROI is called ‘R’ (this is usually what it is called by default when you drop and ROI in) if it is called something else rename it ‘R’ in the data module. Then open the python interactor (the little blue and yellow symbol on the far right on the top toolbar). Copy and paste this code into the interactor:
# this gets the ROI node and assigns it to a variable
roiNode = slicer.util.getNode('R')
# Set the sizes you want the ROI here. Change the numbers to suit your application
radius = [400,400,200]
# This sets the ROI size to the dimensions specified above
roiNode.SetRadiusXYZ(radius)
This will quickly size the ROI to the exact sizes specified in the ‘radius’ list. You can also automate the cropping etc. Let me know if there is anything you would like to add to the code to make life easier.
In terms of learning to code in slicer (I’m still pretty noob but can do basic things). I would recommend learning some basic python to get the hang of the structure. The code is quite specific to slicer but there are heaps of examples which will give you a good start in the script repository to get the hang of the slicer commands.
Actually, I just realised that the ‘radius’ is specified in millimeters (RAS coordinates) and not pixels (IJK coordinates). It may need a conversion between RAS and IJK coordinates. This just picks up the first volume in the scene. Also, I forgot that the radius measurement needs to be halved to make the size of the ROI correct. This may not be the most elegant way of doing this but this worked for me in a quick test:
# specify desired dimensions in voxels
radiusIJK = [400, 400, 200]
# assign the first volume node in the data module to a variable
volumeNode = slicer.util.getNode('vtkMRMLScalarVolumeNode1')
# assign roi node to a variable
roiNode = slicer.util.getNode('R')
# get the size of the volume voxels
spacing = volumeNode.GetSpacing()
# convert the number of pixels to measurements in mm
radiusRAS = [(radiusIJK[0]*spacing[0])/2, (radiusIJK[1]*spacing[1])/2, (radiusIJK[2]*spacing[2])/2]
# change the size of the ROI
roiNode.SetRadiusXYZ(radiusRAS)
Great, this should work as long as the DICOM images are true axial images, that is they are in the same plane as the CT gantry plane. If you look in the volume information area of the Volumes module, the IJK to RAS direction matrix should have only 1s and 0s in it. This means the volume is aligned with the primary axes in Slicer. Sometimes the CT operator makes reformatted reconstructions that are not quite true axial images if, for example, the patient is not sitting straight in the CT machine. If you encounter volumes generated from reformatted images that are not quite aligned with the primary axes in Slicer then we will have to make some additions to the code. Perhaps align the ROI to the volume prior to resizing it or something.