How to get proper views of point cloud data in numpy-stl?

1.6k Views Asked by At

I am trying to get front, back, left, right, top, bottom after projecting the point clouds of 3D data. But the results are not good. Is there any better way to get the required views? I have done up to this using numpy-stl documentation and some research for projection.

import numpy as np
import pandas as pd
import os
import time
import scipy
import math
from scipy import ndimage
from stl import mesh
from matplotlib import pyplot as plt
from mpl_toolkits import mplot3d
from matplotlib import cm
%matplotlib inline

# Load an existing stl file:
my_mesh = mesh.Mesh.from_file('Bolt.stl')

# Create a new plot
figure = pyplot.figure()
axes = mplot3d.Axes3D(figure)

# Load the STL files and add the vectors to the plot
axes.add_collection3d(mplot3d.art3d.Poly3DCollection(my_mesh.vectors))

# Auto scale to the mesh size
scale = my_mesh.points.flatten()
axes.auto_scale_xyz(scale, scale, scale)

# Show the plot to the screen
pyplot.show()

3D view of the input bolt.stl file

I have download that bolt.stl from grabcad.com.

After that, I have tried to project it's different views like:

points = my_mesh.vectors
x = points[:,0].flatten()
y = points[:,1].flatten()
z = points[:,2].flatten()

fig= plt.figure()
ax= fig.add_subplot(111, projection= '3d')
ax.scatter(x,y,z)

ax.plot(x, z, 'r+', zdir='y', zs=100)
ax.plot(y, z, 'g+', zdir='x', zs=-100)
ax.plot(x, y, 'k+', zdir='z', zs=-100)

ax.set_xlabel('X')
ax.set_xlim([-100, 100])
ax.set_ylabel('Y')
ax.set_ylim([-100, 100])
ax.set_zlabel('Z')
ax.set_zlim([-100, 100])

plt.show()

Using matplotlib to get projected views

Result is so bad, I cannot even know, where goes the bolt 3D.

I have also tried:

X = points[:,0]
Y = points[:,1]
Z = points[:,2]

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, Z, rstride=8, cstride=8, alpha=0.3)
cset = ax.contourf(X, Y, Z, zdir='z', offset=-100, cmap="gray")
cset = ax.contourf(X, Y, Z, zdir='x', offset=-100, cmap="gray")
cset = ax.contourf(X, Y, Z, zdir='y', offset=100, cmap="gray")

ax.set_xlabel('X')
ax.set_xlim(-100, 100)
ax.set_ylabel('Y')
ax.set_ylim(-100, 100)
ax.set_zlabel('Z')
ax.set_zlim(-100, 100)

plt.show()

Using contourf

I have also tried with this code to, which I have found from "MVCNN for 3D shape recognition "

def point_cloud_to_volume(points, size=32):
    vol = np.zeros((size,size,size))
    locations = np.copy(points)
    locations[:] *= (size-1)
    locations = locations.astype(int)
    locations[locations >= size] = 0.0
    locations[locations < 0] = 0.0
    vol[locations[:,0],locations[:,1],locations[:,2]] = 1.0
    return vol

def vol2depthmap(volume_array, bg_val=32):
    vol = volume_array.argmax(2)
    vol[vol == 0] = bg_val
    return vol
v = point_cloud_to_volume(points)
%matplotlib inline
from matplotlib import pyplot as plt
plt.imshow(vol2depthmap(v), interpolation='nearest', cmap='Greys')
plt.colorbar()

Matplotlib plot after convertion from point cloud to volume

Finally, I have tried:

front_proj = points[:, :, :].sum(axis=1)
plt.plot(front_proj)
plt.show()

Front View

side_proj = points[:, :, :].sum(axis=0)
plt.plot(side_proj)
plt.show()

Side View

top_proj = points[:, :, :].sum(axis=2)
plt.plot(top_proj)
plt.show()

Top View

I have tried using slicing, but as you have already guessed what will be the result.

front   = points[:,:,0] 
back   = points[:,:,-1] 
top    = points[0,:,:]  
bottom = points[-1,:,:] 
r_side = points[:,-1,:] 
l_side = points[:,0,:]

front view

back view

top view

bottom view

right view

left view

How to get the proper views of .stl file like below. Please ignore drafting and dimensions.

Sample views

Or any other cad format will do. I tried it in .stl file as there is no python-library I found so far, to load other cad formats than stl.

2

There are 2 best solutions below

0
Dirk On

Have you tried this?

figure = plt.figure()
axes = mplot3d.Axes3D(figure)

axes.add_collection3d(mplot3d.art3d.Poly3DCollection(mymesh.vectors))
axes.view_init(90,270) # top view
scale = mymesh.points.flatten('F') #C, F, A, or K
axes.auto_scale_xyz(scale, scale, scale)

plt.show()

Play with the view_init combinations of 0,90,180,270 to get the other projections.

0
Zachary Chiodini On

Here's something you can do:

vertices = my_mesh.vectors.reshape(3*len(my_mesh.vectors), 3)
vertices = np.unique(vertices, axis=0)
x, y, z = zip(*vertices)

figure = plt.figure()
axes = mplot3d.Axes3D(figure)
axes.scatter3D(x, y, z)
plt.show()