K3D-tools / K3D-jupyter

K3D lets you create 3D plots backed by WebGL with high-level API (surfaces, isosurfaces, voxels, mesh, cloud points, vtk objects, volume renderer, colormaps, etc). The primary aim of K3D-jupyter is to be easy for use as stand alone package like matplotlib, but also to allow interoperation with existing libraries as VTK.
MIT License
953 stars 121 forks source link

Dataset scaling, correct scale bars #417

Closed habi closed 10 months ago

habi commented 1 year ago

Description

I'm trying to visualize a tomographic dataset of fish heads for a publication. For this, I'd like to have 'correct' scale bars in the figure, not going from -0.5..0.5

I think that I can achieve this with setting the bounds and the scaling correctly, but don't succeed.

What I Did

The data is rather big, so I subsample it.

Reconstructions[whichfish].shape
(3688, 1700, 3060)
whichfish = 0
subsample = 10
fish = k3d.volume((Reconstructions[whichfish][::subsample, ::subsample, ::subsample]).astype(numpy.float16))
plot = k3d.plot()
plot += fish
plot.display()

This leads to a skewed display of the fish, as seen in the screenshot below. Clipboard01 The fish head is more flat, as seen in the calculated MIPs 230229 TestScan_007um rec MIPs

When setting the bounds deliberately, the fish is not skewed anymore, but only shown in one quadrant of the visualization. I have the voxel size (in um) and can scale the display with this, then the size seem correct.

fish = k3d.volume((Reconstructions[whichfish][::subsample, ::subsample, ::subsample]).astype(numpy.float16),
                  bounds=[0, Reconstructions[whichfish][::subsample, ::subsample, ::subsample].shape[0],
                          0, Reconstructions[whichfish][::subsample, ::subsample, ::subsample].shape[1],
                          0, Reconstructions[whichfish][::subsample, ::subsample, ::subsample].shape[2]],
                  scaling=[Data.Voxelsize[whichfish]*subsample/1000,
                           Data.Voxelsize[whichfish]*subsample/1000,
                           Data.Voxelsize[whichfish]*subsample/1000]
                 )
plot = k3d.plot()
plot += fish
plot.display()

Clipboard02

How can I 'fill' the whole visualization with the fish head?

habi commented 1 year ago

This here is a test dataset, the issue actually came up with another Jupyter notebook, which saves a standalone HTML page towards the end which we use in a manuscript on the data wrangling of tomographic data.

artur-trzesiok commented 1 year ago

Hi @habi !

bounds and scaling are rendundant in that case. By default k3d.volume will display voxel data in box -0.5, 0.5. By defining bounds you can define that physical region on scene. So in fact bounds are in scene unit. So you should contain both resolution information and voxel spacing information in bounds.

Popular case:

bounds = [
0, res_x * spacing_x,
0, res_y * spacing_y,
0, res_z * spacing_z
]

I'm not sure what do you mean by "fill whole visualization - I will use a camera to zoom in into fish and make good frame :). You can read after that position of camera by:

plot.camera

And you can copy output directly to code:

plot.camera = [1.9019489217942718,
 -2.6507589132089504,
 1.7105498878433167,
 0.0007290108532804158,
 0.0005253581588631243,
 4.012680384320523e-06,
 -0.24568722693443604,
 0.33397619879211266,
 0.9099987281099015]

So you will have always the same good view

habi commented 1 year ago

Thanks for the input, this helps a lot. I've updated the code (and the output of the manuscript) with your suggestion!