For 3D printing, we slice the digital objects into image stacks in order to stack them layer by layer using a 3D printer. And when the slice is done, how to label the inner/outer to set the solid parts?
but the need is to keep or label the inner/outer of contours, say the inner is black so the 3D printer will print it and skip the white outer. The goal is filled inner of contours as the following image:
import pyvista as pv
mesh = pv.read('./haus.stl')
slices = mesh.slice_along_axis(n=20, axis='z', progress_bar=True)
# show single slice with camera setting
slices[15].plot(cpos=[0, 1, 1], line_width=5, parallel_projection=True,)
# save slices (outcome is as step.3 image stack)
for i in range(20):
p = pv.Plotter(off_screen=True)
p.add_mesh(slices[i])
p.camera_position = 'zy'
p.enable_parallel_projection()
im_name = "im_slice_" + str(i) + ".jpg"
p.screenshot(im_name)
# Try voxelize (as ans from https://stackoverflow.com/questions/75300529)
voxels = pv.voxelize(mesh, density=mesh.length / 100)
# Try pv.Plane() (not test yet)
plane=pv.Plane()
plane.compute_implicit_distance(mesh, inplace=True)
np.sign(plane.point_data['implicit_distance'])
#i_resolution=?, j_resolution=?
# Try vtk (not test yet)
# https://stackoverflow.com/questions/68191368
but voxelize sliced
doesn't seem very suitable. A very fine mesh needs to be built to restore the boundaries.
show STL:
Just add STL reader and Mapper:
filename = './haus.stl'
reader = vtkSTLReader()
reader.SetFileName(filename)
reader.Update()
stlMapper = vtk.vtkPolyDataMapper()
stlMapper.SetInputConnection(reader.GetOutputPort())
polydata = stlMapper
print("Get GetOrigin", polydata.GetCenter())
sphereSource = reader
slice result:
Try 2 is almost done with the job, but can not figure out the SetExtent/SetOrigin effect. The output image all fit to the contours' dimensions so each output image WXH is not identical.
Only change some code as following:
inputModelFile = "./data/haus.stl"
outputDir = "./outputs/"
...
for i in range(80,140, 10):
imageio.imwrite(f"{outputDir}/image_{i:03}.jpg", 255 - outputLabelmapVolumeArray[i]) # Inverting Colors
The result seems acceptable, but need future to revise some code to match the resolution, position, spacing, etc. So, is there a more lean and more efficient way to automate similar work?
You may want to try out the combination of vtkFeatureEdges
, vtkStripper
and vtkTriangleFilter
, eg:
from vedo import *
msh = Mesh('https://vedo.embl.es/examples/data/cow.vtk')
slices = []
for z in np.arange(-.50, .50, .15):
line = msh.clone().cut_with_plane(origin=(0,0,z), normal='z')
cap = line.cap(True)
slices.append(cap)
show(slices, msh.alpha(0.1), axes=1)
In case you want to create a set of images or a tiff stack (instead of a polygonal mesh), you can do it with:
from vedo import *
surf = Mesh("https://vedo.embl.es/examples/data/cow.vtk")
surf.compute_normals()
# write a tiff stack
vol = surf.binarize(spacing=(0.02, 0.02, 0.02))
vol.alpha([0,0.6]).c('blue5')
vol.write("image.tif")
# write a numpy array and/or a set of png files
arr = vol.tonumpy()
pic = Picture(arr[:,:,55])
pic.write("slice55.png")
show(vol, pic, N=2, sharecam=False, axes=1)
Finally you can inspect the tiff file from command line:
vedo --slicer3d image.tif