mayavi icon indicating copy to clipboard operation
mayavi copied to clipboard

incorrect obj file with savefig

Open eendebakpt opened this issue 10 years ago • 10 comments

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()

eendebakpt avatar Oct 21 '15 13:10 eendebakpt

Verified in current versions. Investigating.

stefanoborini avatar Apr 01 '16 10:04 stefanoborini

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 

stefanoborini avatar Apr 01 '16 12:04 stefanoborini

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.

Jorgetr88 avatar May 07 '16 21:05 Jorgetr88

Reopening for support.

stefanoborini avatar May 09 '16 08:05 stefanoborini

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

mtamburrano avatar Jan 25 '18 16:01 mtamburrano

@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.

prabhuramachandran avatar Feb 10 '18 07:02 prabhuramachandran

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.

mtamburrano avatar Feb 12 '18 11:02 mtamburrano

@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.

prabhuramachandran avatar Feb 12 '18 11:02 prabhuramachandran

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

mtamburrano avatar Feb 12 '18 14:02 mtamburrano

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

atta007 avatar Dec 27 '22 21:12 atta007