如何均匀简化3D人脸表面网格且保留顶点双侧对称性
3D人脸网格简化时保留双侧对称性与顶点均匀分布的方案咨询
以下是3D人脸表面网格的示例,从下图1可见,特征点具备双侧对称性,我希望减少特征点的数量。
其中face为顶点坐标,triang为三角剖分文件,landPairs为包含顶点配对信息的两列文件,landPairs后续不会用于绘图,但若需要可直接使用。所有数据可从对应仓库获取。
原始网格绘制代码
library(rgl) library(Rvcg) # 自定义函数:将vb和it信息转换为3D网格 lm2mesh <- function(vb, it) { vb <- t(vb) vb <- rbind(vb, 1) rownames(vb) <- c("xpts", "ypts", "zpts", "") it_mat <- t(as.matrix(it)) rownames(it_mat) <- NULL vertices <- c(vb) indices <- c(it_mat) tmesh3d(vertices = vertices, indices = indices, homogeneous = TRUE, material = NULL, normals = NULL, texcoords = NULL) } # 加载`face`和`triang`文件 face <- as.matrix(read.csv("<PATH>\\SampleFace.csv", header=F)) triang <- as.matrix(read.csv("<PATH>\\triangulation.csv", header=F)) facemesh <- lm2mesh(face,triang) # 绘制未简化的网格 shade3d(facemesh, col="steelblue", specular = "#202020", alpha = 0.7) plot3d(face, type = "s", col = "red", xlab = "x", ylab = "y", zlab = "z", size = 0.2, aspect = FALSE, alpha = 0.8, add=T)
原始网格输出结果

顶点分布均匀且完全具备双侧对称性。
现有简化方案代码
# 绘制简化后的网格 open3d() facemeshdecim <- vcgQEdecim(facemesh,percent=0.1) shade3d(facemeshdecim, col="steelblue", specular = "#202020", alpha = 0.7) plot3d(t(facemeshdecim$vb[-4, ]), type = "s", col = "red", xlab = "x", ylab = "y", zlab = "z", size = 0.4, aspect = FALSE, alpha = 0.8, add=T)
简化后网格输出结果

顶点分布不再均匀,且双侧对称性消失。
可行解决方案
有两种成熟的实现思路,都可以同时满足顶点分布均匀、保留双侧对称性的需求:
方案1:半侧镜像简化法(实现成本最低,适合当前数据集)
利用手头已有的landPairs对称配对信息,操作步骤如下:
- 先对原始网格做坐标对齐,确保人脸对称轴与X=0平面完全重合(若数据集已经对齐可跳过这一步)
- 提取X≥0的半侧人脸网格,单独对这半侧网格做简化,调整
vcgQEdecim的参数开启均匀分布约束:# 半侧简化示例代码片段 facemesh_half <- vcgClip(facemesh, "x", 0) # 截取x≥0的半侧网格 # 开启preserveboundary参数保留边界,boundweight调大避免对称轴处被过度简化 facemesh_half_decim <- vcgQEdecim(facemesh_half, percent=0.1, preserveboundary = T, boundweight = 10) - 将简化后的半侧网格沿X轴做镜像翻转,把对称的顶点、三角面拼接回完整网格,直接用
landPairs做顶点匹配即可 - 最后对拼接后的网格做一次简单的平滑处理消除接缝,即可得到完全对称、顶点分布均匀的简化网格
方案2:约束二次误差测度简化法(效果更可控,适合批量处理)
修改vcgQEdecim的误差计算逻辑,把对称约束加入到边折叠的代价计算中:
- 每次计算边折叠代价时,同时计算其对称边的折叠代价,取两者的平均值作为最终代价
- 只要触发任意一条边的折叠操作,就同时对其对称边执行完全相同的折叠操作
- 额外添加顶点密度约束项,避免局部区域顶点过度稀疏/密集,即可同时满足两个需求
第一种方案不需要修改现有的简化工具底层逻辑,直接用现有数据和R包就能实现,推荐优先尝试。
内容的提问来源于stack exchange,提问作者Patrick
相关产品推荐
相关产品推荐

