提问人:vscv 提问时间:2/3/2023 最后编辑:vscv 更新时间:3/23/2023 访问量:307
将 3D 对象切片/栅格化到图像堆栈时,如何标记轮廓的内/外?
How to label inner/outer of contour when slice/rasterize 3D objects to image stack?
问:
对于 3D 打印,我们将数字对象切成图像堆栈,以便使用 3D 打印机逐层堆叠它们。切片完成后,如何标记内/外以设置实心部分?
- STL 模型:
- 切片:
- 一个图像堆栈的示例(切片):
但需要保留或标记轮廓的内/外轮廓,比如说内部是黑色的,这样 3D 打印机就会打印出来并跳过白色的外部。目标填充在轮廓内部,如下图所示:
尝试 1
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
但似乎不太合适。需要构建一个非常精细的网格来恢复边界。voxelize sliced
尝试 2 个 VTK 示例
显示 STL:
只需添加 STL 读取器和映射器:
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
切片结果:
尝试 2 几乎完成了工作,但无法弄清楚 SetExtent/SetOrigin 效果。输出图像都适合轮廓的尺寸,因此每个输出图像 WXH 都不相同。
尝试 3 个 3D Silcer 示例
仅更改某些代码,如下所示:
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
结果似乎是可以接受的,但需要将来修改一些代码以匹配分辨率、位置、间距等。那么,有没有一种更精简、更高效的方法来自动化类似的工作呢?
答:
1赞
mmusy
2/4/2023
#1
您可能想尝试 和 的组合,例如:vtkFeatureEdges
vtkStripper
vtkTriangleFilter
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
评论
0赞
vscv
2/6/2023
Thanks, @mmusy. It did the job. But it has the same issue as Try-2 VTK, "The output image all fit to the contours' dimensions, so each output image WXH is not identical." is it possible manually control the space padding for each plane to fit the output image size?
0赞
mmusy
2/6/2023
You don't need padding, the contour coordinates are absolute, they are not shifted wrt the original shape. The "padding" is trivially given by the difference of the bounds.
0赞
vscv
3/21/2023
can you get the output of the sliced image, just for example?
0赞
mmusy
3/22/2023
yes - you can write it to disk with eg. .cap.write("capmesh.stl")
0赞
vscv
3/23/2023
Thanks, @mmusy, I mean the "image" output as the original question. It would be great if you could provide the workable code.
评论