marcomusy / vedo

A python module for scientific analysis of 3D data based on VTK and Numpy
https://vedo.embl.es
MIT License
2.03k stars 265 forks source link

[BUG] Screenshot function and camera argument not working anymore #985

Closed ccechatelier closed 10 months ago

ccechatelier commented 10 months ago

Dear Marco, dear vedo community,

I am encountering some issues with the newest version of vedo.

The screenshot function used after showing a Plotter is not working anymore. No error whatsoever, no file generated, nothing. I had to go around and use the plotter.show as an Image, and save it raw. Doing so the camera position does not matter anymore, and the same view is showed everytime. Only the light are properly changing.

Here is the script associated to that issue :

datasets = [130]

scan = {130: 12}
co2 = {130: 5}
iso = {130: 0.65}

path_exp = f''
path_results = f''
phaselim = np.pi/10

print('Dataset', dataset, 'Scan', scan[dataset])
fn_vti = f'cdiutils_D{dataset}_S{scan[dataset]}_structural_properties.vti'
vol = Volume(f'{path_exp}{path_results}{fn_vti}')
printc('Arrays in Volume are:\n', vol.pointdata.keys(), invert=True)
vol.pointdata.select("amplitude")  # select the first data array as the active one

## Some parameters of interest
cx, cy, cz = vol.center() # center of the cell
nx, ny, nz = vol.dimensions() # number of voxels
dx, dy, dz = vol.spacing()
sx, sy, sz = nx*dx, ny*dy, nz*dz # size of the cell

print('Center   :', cx, cy, cz)
print('Vox #    :', nx, ny, nz)
print('Vox size :', dx, dy, dz)
print('Size box :', sx, sy, sz)

## Phase or Strain
data, value = 'Phase', 'phase'
vmin, vmax, cmap = -phaselim, phaselim, 'turbo'

isosurface = vol.isosurface(iso[dataset]).cmap(cmap, value, vmin = vmin, vmax = vmax)

## Specular parameters
ambient, diffuse, specular = 0.7, 0.3, 0.4 # simulation
specularPower, specularColor= 20, 'white'
isosurface.lighting('metallic', ambient, diffuse, specular, specularPower, specularColor)

## Plotters
angle = 0
print('####################')
print('[INFO] Angle', angle)
s = np.sin(np.deg2rad(angle))
c = np.cos(np.deg2rad(angle))

cam_rot = {'pos': (cx+s*sx, cy+0.425*sy, cz+c*sz),
            'viewup': (0, 1, 0),
            'focalPoint': (cx, cy, cz)}

print(cam_rot)
## Lights
p1 = Point([cx+s*sx, cy+0.425*sy, cz+c*sz], c='red')
p2 = Point([cx+c*sx, cy+0.425*sy, cz-s*sz], c='blue')
p3 = Point([cx-s*sx, cy+0.425*sy, cz-c*sz], c='blue')
l1 = Light(p1, c='white', intensity=1)
l2 = Light(p2, c='white', intensity=0.2)
l3 = Light(p3, c='white', intensity=0.2)

vp = Plotter(N=1, offscreen=True, sharecam=False)
img = vp.show((isosurface, f""), l1, l2, l3, viewup = 'y', camera=cam_rot, at=0, axes=0)
# screenshot(f'D{dataset}_S{scan[dataset]}_NP_Ni_{data}_cam_{angle}.png', scale=1)
img.save(f'D{dataset}_S{scan[dataset]}_NP_Ni_{data}_cam_{angle}.png')
vp.close()

## Plotters
angle = 180
print('####################')
print('[INFO] Angle', angle)
s = np.sin(np.deg2rad(angle))
c = np.cos(np.deg2rad(angle))

cam_rot = {'pos': (cx+s*sx, cy+0.425*sy, cz+c*sz),
            'viewup': (0, 1, 0),
            'focalPoint': (cx, cy, cz)}

print(cam_rot)
## Lights
p1 = Point([cx+s*sx, cy+0.425*sy, cz+c*sz], c='red')
p2 = Point([cx+c*sx, cy+0.425*sy, cz-s*sz], c='blue')
p3 = Point([cx-s*sx, cy+0.425*sy, cz-c*sz], c='blue')
l1 = Light(p1, c='white', intensity=1)
l2 = Light(p2, c='white', intensity=0.2)
l3 = Light(p3, c='white', intensity=0.2)

vp = Plotter(N=1, offscreen=True, sharecam=False)
img = vp.show((isosurface, f""), l1, l2, l3, viewup = 'y', camera=cam_rot, at=0, axes=0)
# screenshot(f'D{dataset}_S{scan[dataset]}_NP_Ni_{data}_cam_{angle}.png', scale=1)
img.save(f'D{dataset}_S{scan[dataset]}_NP_Ni_{data}_cam_{angle}.png')
vp.close()

Does anybody have an idea on the underlying problem that I might be facing ?

System: Ubuntu 20.04 Using VSCode, and Jupyter notebook

Thanks a lot in advance for any insights! Cheers, Coco

marcomusy commented 10 months ago

Hi Coco, in fact what you are doing is already the correct thing, because you set (or the jupyter env is automatically detected) settings.default_backend = "2d" then vp.show() will return a PIL image in your jupyter notebook.

An alternative is to set: settings.default_backend = "vtk" then vp.show(..., screenshot="myimage.png") will return a Plottter your jupyter notebook.

Also you don't need N=1, offscreen=True, sharecam=False in vp = Plotter().

I will try update screenshot() so that it will do automatically that.

ccechatelier commented 10 months ago

Hi Marco, thanks this solves the issue on the screenshot function, that's very nice :) Yet, I still have the issue that camera positions are not taken into account. It seems that there is a default position given that can't be updated.

ccechatelier commented 10 months ago

My bad, I just noticed that the viewup argument supersedes the camera argument ... Removing it allows for taking into account the given positions :) Thanks a lot for your help !!!