How to programmatically use zoom in and zoom out to properly adjust the volume size of the 3D view?

Dear all,
Here is the thing I want to do, thank you in advance for any possible help!

With Slicer 4.11,I am using capture screenshot module to record my volume slice along the P-A orientation.
By default, I take a 3D only screenshot like this:


image

When I load this Screenshot.png file into MATLAB or Python, I checked this dimension which is 617x1015x4.There are four channels R,G,B,A so the last dimension is 4 but what I care is the 617x1015,this seems like to be the default display window size.
Under this window size, my slice size is not quite right.
image
The red line rectangle is different from the particular 300x400 dimension in the volume information module as follows:

When I adjust the volume size manually by zooming in or zooming out,for example:


I can get the smaller size but it is too small than 300x400.So in this situation I have to adjust again and again until I load this png file into Python and find the dimesion is 300x400.
Manual adjustment is quite time-comsuming and inefficient.So I am wondering if there is a way to let the volume zoom-in or zoom-out to become an exact size with python code.
I think there maybe a node in the scene.mrml file that controls the size of the volume.
Thank you for your attention and I will be grateful if you can give me some advice!

You can get the camera as described here and then compute the camera parameters as discussed here.

1 Like

Thanks Andras, thank you very much for helping me solve this problem.

While I have never touched the VTK but I remembered you once gave me a VTKTextBook.I looked up this book especailly about the section 3.6 Cameras


I probably knew the basics after reading several times.I think I am close to the solution if you can help me again!
So I first get the camera according to the Script repository as follows:

layoutManager = slicer.app.layoutManager()
for threeDViewIndex in range(layoutManager.threeDViewCount) :
  view = layoutManager.threeDWidget(threeDViewIndex).threeDView()
  threeDViewNode = view.mrmlViewNode()
  cameraNode = slicer.modules.cameras.logic().GetViewActiveCameraNode(threeDViewNode)

Since I just have one ViewNode,

camera = cameraNode.GetCamera()

I have sucessfully got the camera


According to the VTKbook,I think in general, there are two ways to adjust the camera,one is modifying the camera’s postion while keeping the focal point fixed and another way is to do the opposite.
And I found there are many attributes can be operated but particularly this Zoom method, which changes the camera’s view angle, so that more or less of the scene falls within the view frustum.

I prefer to use the default settings but just resize the volume to a desired dimension.So I just use the Zoom() method and observed the results.
When I first loaded the scene.mrml file into Slicer,


In this situation I need to zoom-out to adjust the dimension and I assume the zoom-out operation is exacly same with sliding the middle mouse button,so then I run this single line code:

camera.Zoom(0.5)

it produced the result below:

Sadly, I have no idea how to fine-tune the volume size to the desired dimension like 300x400.
I have also seen this post.But I am confused with the solution there especially I know very little about VTK.

ParallelScale = 2*(Distance*tan(0.5*ViewAngle))

Does Slicer use the orthographic projection (or parallel projection) as default?
How to caculate between the distance and viewAngle in order to get the desired dimension(300x400 in my case)
I would really appreciate it if you could give me some concrete code to illustrate the problem.
Thank you in advance!

I think what you miss is the volume’s size and location. You can get that information from the volume bounds (specified in the renderer coordinate system):

bounds=[0,0,0,0,0,0]
getNode('MRHead').GetRASBounds(bounds)
print(bounds)

Thanks Andras,
I am not trying to switch between perspective and parallel projection that keeps an object the same size within the view but just want to calculate the exact voxel dimension of the volume.

You are right,I can get the volume bounds which is associated with the ROI range.
image
Also,I have these parameters:

camera = renderer.GetActiveCamera()
angle = math.radians(camera.GetViewAngle())
point = camera.GetFocalPoint()
direction = camera.GetDirectionOfProjection()
scale = camera.GetParallelScale()
distance = scale / math.sin(.5 * angle)

However,I have no idea how to put all these together to get what I need.
I noticed that I am using the RAS coordinate but what I need is the 2D slice shape(300x400 pixel in my case), in other words,the IJK coordinate .
Is there a simple way just to transfer the RAS to IJK and produce the dimension I need?
I found the related matrix


Is it possible to zoom-in or zoom-out in order to change the image dimensions to the below:

Thank you for your continued attention!