enthought / mayavi

3D visualization of scientific data in Python
http://docs.enthought.com/mayavi/mayavi/
Other
1.3k stars 284 forks source link

incorrect obj file with savefig #259

Open eendebakpt opened 8 years ago

eendebakpt commented 8 years ago

After writing a mesh to .obj format the color is discarded. An example script is included below. The generated .obj file starts with

# wavefront obj file written by the visualization toolkit

mtllib /home/eendebakpt/tmp/dummy3.mtl

v 0.880769 0 0.2
v 0.880769 0 0.2

but this should be

# wavefront obj file written by the visualization toolkit

mtllib /home/eendebakpt/tmp/dummy3.mtl
usemtl mtl1
v 0.880769 0 0.2
v 0.880769 0 0.2

An example script to generate the .obj:

from mayavi import mlab
import numpy as np
from scipy.special import sph_harm

# Create a sphere
r = 0.2
pi = np.pi
cos = np.cos
sin = np.sin
phi, theta = np.mgrid[0:pi:17j, 0:2 * pi:17j]

x = r * sin(phi) * cos(theta)
y = r * sin(phi) * sin(theta)
z = r * cos(phi)

x += np.random.rand()
mlab.figure(1, bgcolor=(1, 1, 1), fgcolor=(0, 0, 0), size=(400, 300))
mlab.clf()
# Represent spherical harmonics on the surface of the sphere
n=1; m=1
s = sph_harm(m, n, theta, phi).real

mm=mlab.mesh(x, y, z, color=(1.,1.,0.) , colormap='jet')

mlab.view(90, 70, 6.2, (-1.3, -2.9, 0.25))

mlab.savefig('/home/eendebakpt/tmp/dummy3.obj')

mlab.show()
stefanoborini commented 8 years ago

Verified in current versions. Investigating.

stefanoborini commented 8 years ago

The resulting file is correct as is. The usemtl statement is only applicable to polygonals. The v entry specifies vertices, which do not take a material.

see http://www.martinreddy.net/gfx/3d/OBJ.spec

If you look later in the file, where the faces are specified, you can see

g grp1
usemtl mtl1
f 1//1 18//18 19//19 
f 2//2 19//19 20//20 
f 3//3 20//20 21//21 
f 4//4 21//21 22//22 
f 5//5 22//22 23//23 
f 6//6 23//23 24//24 
Jorgetr88 commented 8 years ago

Hello. I understand that .obj works with only the geometry of the object that can be plotted on python with mlab, for example. Then, when i use mlab.savefig it generates also a .mtl that contains textures and other attributes. The question is, in an example similar to the posted before, to generate spherical harmonics:

from mayavi import mlab
import numpy as np
from scipy.special import sph_harm

# Create a sphere
r = .3
pi = np.pi
cos = np.cos
sin = np.sin
phi, theta = np.mgrid[0:pi:101j, 0:2 * pi:101j]

x = r * sin(phi) * cos(theta)
y = r * sin(phi) * sin(theta)
z = r * cos(phi)

mlab.figure(1, bgcolor=(1, 1, 1), fgcolor=(0, 0, 0), size=(400, 300))
mlab.clf()
# Represent spherical harmonics on the surface of the sphere
for n in range(1, 6):
    for m in range(n):
        s = sph_harm(m, n, theta, phi).real

        mlab.mesh(x - m, y - n, z, scalars=s, colormap='jet')

        s[s < 0] *= 0.97

        s /= s.max()
        mlab.mesh(s * x - m, s * y - n, s * z + 1.3,
                  scalars=s, colormap='Spectral')

mlab.view(90, 70, 6.2, (-1.3, -2.9, 0.25))
mlab.savefig('spherical_harm.obj')
mlab.show()

How can i keep the atributes of the colormap='spectral', so that i can export the .obj file to another program and display the geometry with also the color on it? The program where i am trying to export is Blender, and i am using python 2.7. Thanks.

stefanoborini commented 8 years ago

Reopening for support.

mtamburrano commented 6 years ago

bump, I cannot export the .obj with the right color info in the respective .mtl.

prabhuramachandran commented 6 years ago

@mtamburrano -- this looks like a bug in VTK, as Mayavi is merely asking VTK to do the export. So the OBJ exporter is not doing a proper job of exporting the materials. However, all is not lost, the X3D exporter does a fantastic job. I just tested with Mayavi master, VTK 8.1.0, and blender 2.78c. Just change your savefig to mlab.savefig('spherical_harm.x3d') and import that. It works beautifully for me. Of course you will need to view the object with the viewport shading in "rendered" mode in blender. For now I am closing this here as there isn't much I can do at the Mayavi level.

mtamburrano commented 6 years ago

hi @prabhuramachandran, thank you but that doesn't work for me.

I use this method to assign a specific color on specific voxels:

def create_8bit_rgb_lut():
    xl = np.mgrid[0:256, 0:256, 0:256]
    lut = np.vstack((xl[0].reshape(1, 256**3),
                        xl[1].reshape(1, 256**3),
                        xl[2].reshape(1, 256**3),
                        255 * np.ones((1, 256**3)))).T
    return lut.astype('int32')

def rgb_2_scalar_idx(rgb):
    return 256**2 *rgb[0] + 256 * rgb[1] + rgb[2]

rgb_lut = create_8bit_rgb_lut()
#assign the right color to each voxel
scalars = global_df['label'].apply(lambda x: colors[int(x)]).apply(rgb_2_scalar_idx).values

plot = mlab.points3d(self.voxel_coordinates[0], self.voxel_coordinates[1], self.voxel_coordinates[2], scalars, mode='cube', scale_mode="none", scale_factor=1)
plot.module_manager.scalar_lut_manager.lut._vtk_obj.SetTableRange(0, self.rgb_lut.shape[0])
plot.module_manager.scalar_lut_manager.lut.number_of_colors = self.rgb_lut.shape[0]
plot.module_manager.scalar_lut_manager.lut.table = self.rgb_lut

When I visualize the plot, the colors are correct, but when I try to export the plot in any format (.obj, x3d, etc..) the colors change instantaneously. I tried to swap the channels of the rgb table, but the issue seems not to be a different convention (e.g. BGR vs RGB) because even the gray (r=g=b) turns into a light green when I try to export the figure.

prabhuramachandran commented 6 years ago

@mtamburrano -- Can you please give me a complete minimal example that I can run, otherwise it is a bit too much work to figure out what it is exactly that you are doing.

mtamburrano commented 6 years ago

sure, here you are:

import numpy as np
from mayavi import mlab

'''
colors =([[127, 127, 127],
  [ 255, 0,  0],
  [0,  255,  0],
  [127,  127,  255],
  [0,  0,  0],
  [255, 255,  255]])

'''
colors =([[127, 127, 127],
  [ 255, 0,  0],
  [0,  255,  0],
  [127,  127,  255],
  [0,  0,  0],
  [127, 127,  255]])

#create direct grid as 256**3 x 4 array 
def create_8bit_rgb_lut():
    xl = np.mgrid[0:256, 0:256, 0:256]
    lut = np.vstack((xl[0].reshape(1, 256**3),
                        xl[1].reshape(1, 256**3),
                        xl[2].reshape(1, 256**3),
                        255 * np.ones((1, 256**3)))).T
    return lut.astype('int32')

# indexing function to above grid
def rgb_2_scalar_idx(rgb):
    return 256**2 *rgb[0] + 256 * rgb[1] + rgb[2]

if __name__ == "__main__":

  #coords = (np.random.randint(5, size=(size)),np.random.randint(5, size=(size)),np.random.randint(5, size=(size)))
  coords = (np.array([0, 1, 3, 4, 5, 6]), np.array([1, 1, 1, 1, 1, 1]), np.array([1, 1, 1, 1, 1, 1]))
  size = coords[0].shape[0]

  rgb_lut = create_8bit_rgb_lut()
  scalars = [rgb_2_scalar_idx(colors[rgb]) for rgb in range(0, size)]
  print(scalars)

  plot = mlab.points3d(coords[0], coords[1], coords[2], scalars, mode='cube', scale_mode="none", scale_factor=1)

  plot.module_manager.scalar_lut_manager.lut._vtk_obj.SetTableRange(0, rgb_lut.shape[0])
  plot.module_manager.scalar_lut_manager.lut.number_of_colors = rgb_lut.shape[0]
  plot.module_manager.scalar_lut_manager.lut.table = rgb_lut

  mlab.show()
  #mlab.savefig("try.x3d")

I noticed that this issue doesn't occur with every set of colors, so I included two different sets. Using the uncommented colors array, on mlab.show() you'll see the correct colors, but if you save the figure using the save button in the qt window or if you run the code uncommenting the mlab.savefig(...) line, you'll end with a .x3d file with different colors. Instead if you use the commented set of colors, the colors are right both in the qt window than in the exported file. I'm not sure what is happening here

atta007 commented 1 year ago

Hi, this is my code https://github.com/xaviersantos/OpenPCDet/blob/dev/data_augmentation.ipynb. While creating obj files its missing face(f) values. I have followed all the ways which are mentioned in the above comment but even then I can not visualize.[Open3D INFO] Skipping non-triangle primitive geometry of type: 1 [Open3D INFO] Skipping non-triangle primitive geometry of type: 8 [Open3D INFO] Skipping non-triangle primitive geometry of type: 2 [Open3D INFO] Skipping non-triangle primitive geometry of type: 2 [Open3D INFO] Skipping non-triangle primitive geometry of type: 2 [Open3D INFO] Skipping non-triangle primitive geometry of type: 2 [Open3D INFO] Skipping non-triangle primitive geometry of type: 2 [Open3D INFO] Skipping non-triangle primitive geometry of type: 2 [Open3D INFO] Skipping non-triangle primitive geometry of type: 2 [Open3D INFO] Skipping non-triangle primitive geometry of type: 2 [Open3D INFO] Skipping non-triangle primitive geometry of type: 2 [Open3D INFO] Skipping non-triangle primitive geometry of type: 2 [Open3D INFO] Skipping non-triangle primitive geometry of type: 2 [Open3D INFO] Skipping non-triangle primitive geometry of type: 2 [Open3D INFO] Skipping non-triangle primitive geometry of type: 2 [Open3D INFO] Skipping non-triangle primitive geometry of type: 2 TriangleMesh with 6 points and 36 triangles. Please guide me on how can I visualize. Thank you