先打开一个曲面
import open3d as o3d
mesh = o3d.io.read_triangle_mesh('knot.ply')
mesh.compute_vertex_normals()
o3d.visualization.draw_geometries([mesh])
效果如下
knot.ply
显然是点云文件,如果用io.read_point_cloud
读取,那么draw
出来的就是一片点云。将每三个点组成一个三角形,那么点云也就变成了三角面。
Open3D提供了4种滤波方法,分别是均值滤波、拉普拉斯滤波、taubin滤波以及锐化滤波。
所谓均值滤波,就是取最邻近的点做个均值,例如,顶点 v i v_i vi的值变化为
v i = ∑ n ∈ N v n ∣ N ∣ v_i=\frac{\sum_{n\in N} v_n}{|N|} vi=∣N∣∑n∈Nvn
N N N为距离 v i v_i vi最近的点集(包括 v i v_i vi), ∣ N ∣ |N| ∣N∣为点的个数
import numpy as np
vertices = np.asarray(mesh.vertices)
noise = 5
# 添加噪声
vertices += np.random.uniform(0, noise, size=vertices.shape)
mesh.vertices = o3d.utility.Vector3dVector(vertices)
mesh.compute_vertex_normals()
# 平滑去噪 迭代次数设为1
mesh_simple1 = mesh.filter_smooth_simple(1)
mesh_simple1.compute_vertex_normals()
mesh_simple5 = mesh.filter_smooth_simple(5)
mesh_simple5.compute_vertex_normals()
o3d.visualization.draw_geometries([mesh,
mesh_simple1.translate([200,0,0]),
mesh_simple5.translate([400,0,0]),])
对比如下
Laplace滤波相当于是对临近点做加权平均,其权重取决于到目标点的距离,其表达式如下
v i = v i ⋅ λ ∑ n ∈ N w n v n − v i v_i=v_i\cdot\lambda\sum_{n\in N}w_nv_n-v_i vi=vi⋅λn∈N∑wnvn−vi
其中,lambda
默认为0.5。
laplaces = []
for i,s in [[1,0.5],[10,0.5],[10,1],[50,0.5]]:
laplaces.append(mesh.filter_smooth_laplacian(i,s))
laplaces[-1].compute_vertex_normals()
laplaces[-1].translate([200*len(laplaces),0,0])
o3d.visualization.draw_geometries(laplaces+[mesh])
效果为
随着迭代次数和lambda
取值的不断增大,可以发现这个图形变得越来越细,为了解决这个问题,需要用到Taubin滤波。
Taubin滤波在Laplace滤波的基础上又加了一个负的 μ \mu μ参数,且要求 0 < λ < − μ 0<\lambda<-\mu 0<λ<−μ。
记第 i i i个点的坐标为 ( x i , y i , z i ) (x_i, y_i, z_i) (xi,yi,zi),则所有点的坐标可以组成一个 N × 3 N\times 3 N×3的矩阵,记作 X X X。令
X ′ = ( I − λ K ) X X ′ ′ = ( I − μ K ) X X'=(I-\lambda K)X\\ X''=(I-\mu K)X\\ X′=(I−λK)XX′′=(I−μK)X
其中, I I I是单位矩阵, K = I − W K=I-W K=I−W,W为 N × N N\times N N×N的加权矩阵,其元素 W i j W_{ij} Wij表示第 i , j i,j i,j的两个点是否相邻,如果不相邻则置零。
则经过 M M M次迭代之后,得到
X M = ( ( I − λ K ) ( I − λ K ) ) M X X^M=((I-\lambda K)(I-\lambda K))^MX XM=((I−λK)(I−λK))MX
taibin = []
for i in [1, 10, 50]:
taibin.append(mesh.filter_smooth_taubin(i))
taibin[-1].compute_vertex_normals()
taibin[-1].translate([200*len(taibin),0,0])
o3d.visualization.draw_geometries(taibin+[mesh])
效果为
可见,就算迭代次数达到了50次,也没有出现变细的情况。
前三种滤波方法相当于把噪声抹平,锐化滤波与之相反,是凸显出不光滑 的部分,故而其算法与均值滤波相似,但要用当前值减去其相邻点的平均值。
由于加上噪声再做锐化,得到的图实在是没眼看,所以这回采用原始数据进行锐化
import open3d as o3d
mesh = o3d.io.read_triangle_mesh('knot.ply')
mesh.compute_vertex_normals()
sharpens = []
for i in [2, 4]:
sharpens.append(mesh.filter_sharpen(i))
sharpens[-1].compute_vertex_normals()
sharpens[-1].translate([400*len(sharpens),0,0])
o3d.visualization.draw_geometries(sharpens+[mesh])
效果如下