【问题标题】:Decimate 3D surface mesh evenly and preserving bilaterally symmetry均匀抽取 3D 表面网格并保持双边对称
【发布时间】:2021-11-16 04:46:16
【问题描述】:

这是一个 3D 面部表面网格示例。从下面的图 1 可以看出,地标是双边对称的。我希望减少地标的数量。

这里face是顶点的坐标,triang是三角剖分文件,landPairs是一个包含顶点配对信息的两列文件。 landPairs 不用于稍后的绘图,但在需要时提供。所有数据均来自here

这是在抽取之前绘制原始顶点的代码:

library(rgl)
library(Rvcg)

# Customized function to convert vb and it information to 3D mesh
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)
}
# Load `face` and `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)

# Plot the undecimated mesh
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)

这是下图1(顶点间距均匀,绝对双边对称):

# Plot the decimated mesh
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)

这是下面的图 2(顶点不是均匀分布的,也不再是对称的):

可以看出,在抽取的面中,顶点的间距不像抽取之前那样均匀,原本对称的顶点变得不再对称。 我的问题是,是否有一种方法可以减少顶点数量,同时确保减少的顶点尽可能均匀分布并保持顶点的双边对称性?

【问题讨论】:

  • 我不知道现有的方法来做你想做的事,但如果我想这样做,我会使用 rgl::clipMesh3d() 沿着对称线切割网格,抽取结果,然后在对称线上复制结果。一切都很简单,除了在最后加入两半,您需要为此编写一些代码。

标签: r 3d visualization mesh rgl


【解决方案1】:

这是一种方法。从您的代码开始,然后添加:

# Get the positive part of the face
posface <- clipMesh3d(facemesh, fn="y")

# Decimate it, keeping the boundary
posdeci <- vcgQEdecim(posface, percent=0.1, bound = TRUE)

# Duplicate it in a reflection
negdeci <- posdeci
negdeci$vb[2,] <- -negdeci$vb[2,]

# Join them together
fulldeci <- merge(posdeci, negdeci)

# Plot it
open3d()
shade3d(fulldeci, col="steelblue", specular = "#202020", alpha = 0.7)
plot3d(t(fulldeci$vb[-4, ]), type = "s", col = "red", xlab = "x", ylab = "y", zlab = "z", 
   size = 0.4, aspect = FALSE, alpha = 0.8, add=T)

这在中线有太多的点,但除此之外就是你想要的。

编辑添加:

让分数更统一有点棘手。如果您在对vcgQEdecim() 的调用中不使用bound = TRUE,它将在脸部中间留下一个空隙。要填充它,您需要添加连接边缘两侧的四边形,但要确定哪些顶点形成边缘需要一个新函数:

getBorder <- function(mesh) {
  border <- which(vcgBorder(mesh)$bordervb)
  inorder <- NULL
  repeat{
    i <- 1
    inorder <- c(inorder, border[i])
    repeat{
      found <- FALSE
      tris <- which(apply(mesh$it, 2, function(col) border[i] %in% col))
      for (j in tris) {
        tri <- mesh$it[,j]
        i0 <- which(tri == border[i])
        i1 <- i0 %% 3 + 1
        # keep tri[i1] if the edge from tri[i0] to tri[i1] is external
        tris1 <- which(apply(mesh$it[,tris,drop=FALSE], 2, function(col) all(tri[c(i0, i1)] %in% col)))
        if (length(tris1) == 1) {
          if (tri[i1] %in% inorder)
            break
          inorder <- c(inorder, tri[i1])
          i <- which(border == tri[i1])
          found <- TRUE
          break
        }
      }
      if (!found) break
    }
    border <- setdiff(border, inorder)
    if (!length(border)) break
    inorder <- c(inorder, NA)
  }
  inorder
}

使用该函数,以下代码可以完成合理的工作:

# Try joining halves using quads

posdeci2 <- vcgQEdecim(posface,percent=0.1, bound = FALSE)
negdeci2 <- posdeci2
negdeci2$vb[2,] <- -negdeci2$vb[2,]

# This one has the gap
fulldeci2 <- merge(posdeci2, negdeci2)

# Fill in the gap with quads
# Keep the ones in the middle, but not the outside edge
border <- getBorder(posdeci2)
border <- border[posdeci2$vb[2, border] < 0.005]

borderverts <- posdeci2$vb[, border]
negverts <- negdeci2$vb[, border]

# The quads have both sets of vertices
quadverts <- cbind(borderverts, negverts)
n <- ncol(borderverts)

# We'll assume n > 1
indices <- rbind(1:(n-1), 2:n, n + 2:n, n + 1:(n-1))
quads <- mesh3d(vertices = quadverts, quads = indices)
fulldeci3 <- merge(fulldeci2, quads)

# plot it
open3d()
shade3d(fulldeci3, col="steelblue", specular = "#202020", alpha = 0.7)
plot3d(t(fulldeci3$vb[-4, ]), type = "s", col = "red", xlab = "x", ylab = "y", zlab = "z", 
       size = 0.4, aspect = FALSE, alpha = 0.8, add=T)

【讨论】:

  • 非常有帮助!只需以下 Q。设置bound=T 是一个不错的选择。但是否有可能在一定程度上减少沿边界的地标数量?如果可能的话,我还希望在简化边界顶点后得到新的三角剖分文件。一些自定义代码将不胜感激。
  • 我认为要做到这一点,您需要按顺序获取边界顶点,然后修改网格以仅保留 percent 。也许Rvcg 或其他一些包有帮助解决这个问题的功能。
  • 这不是三角剖分,但我添加了一些代码将两半与四边形连接起来。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-30
  • 1970-01-01
  • 2013-12-03
  • 1970-01-01
相关资源
最近更新 更多