3d surface plot with xyz coordinates 3d surface plot with xyz coordinates r r

3d surface plot with xyz coordinates


Here is an approach using kernel density estimation and the contour3d function from misc3d. I played around until I found a value for levels that worked decently. It's not perfectly precise, but you may be able to tweak things to get a better, more accurate surface. If you have more than 8GB of memory, then you may be able to increase n beyond what I did here.

library(rgl)library(misc3d)library(onion); data(bunny)# the larger the n, the longer it takes, the more RAM you needbunny.dens <- kde3d(bunny[,1],bunny[,2],bunny[,3], n=150,     lims=c(-.1,.2,-.1,.2,-.1,.2)) # I chose lim values manuallycontour3d(bunny.dens$d, level = 600,     color = "pink", color2 = "green", smooth=500)rgl.viewpoint(zoom=.75)

enter image description hereenter image description here

The image on the right is from the bottom, just to show another view.

You can use a larger value for n in kde3d but it will take longer, and you may run out of RAM if the array becomes too large. You could also try a different bandwidth (default used here). I took this approach from Computing and Displaying Isosurfaces in R - Feng & Tierney 2008.


Very similar isosurface approach using the Rvcg package:

library(Rvcg)library(rgl)library(misc3d)library(onion); data(bunny)bunny.dens <- kde3d(bunny[,1],bunny[,2],bunny[,3], n=150,     lims=c(-.1,.2,-.1,.2,-.1,.2)) # I chose lim values manuallybunny.mesh <- vcgIsosurface(bunny.dens$d, threshold=600)shade3d(vcgSmooth(bunny.mesh,"HC",iteration=3),col="pink") # do a little smoothing

enter image description here

Since it's a density estimation based approach, we can get a little more out of it by increasing the density of the bunny. I also use n=400 here. The cost is a significant increase in computation time, but the resulting surface is a hare better:

bunny.dens <- kde3d(rep(bunny[,1], 10), # increase density.                    rep(bunny[,2], 10),                    rep(bunny[,3], 10), n=400,                     lims=c(-.1,.2,-.1,.2,-.1,.2))bunny.mesh <- vcgIsosurface(bunny.dens$d, threshold=600)shade3d(vcgSmooth(bunny.mesh,"HC",iteration=1), col="pink")

enter image description here


Better, more efficient surface reconstruction methods exist (e.g. power crust, Poisson surface reconstruction, ball-pivot algorithm), but I don't know that any have been implemented in R, yet.

Here's a relevant Stack Overflow post with some great information and links to check out (including links to code): robust algorithm for surface reconstruction from 3D point cloud?.


I think have found one possible solution using the alphashape3d package. I had to play around a bit to get an acceptable value for alpha, which is related to the distances in the given data set (e.g. sd of bunny gave me some insight). I'm still trying to figure out how to better control the width of lines in vertices and edges so as not to dominate the plot, but this is probably related to settings in rgl.

Example:

library(onion)library(rgl)library(geometry)library(alphashape3d)data(bunny)apply(bunny,2,sd)alphabunny <- ashape3d(bunny, alpha = 0.003)bg3d(1)plot.ashape3d(alphabunny, col=c(5,5,5), lwd=0.001, size=0, transparency=rep(0.5,3), indexAlpha = "all")

enter image description here

Edit:

Only by adjusting the plot.ashape3d function, was I able to remove the edges and vertices:

plot.ashape3d.2 <- function (x, clear = TRUE, col = c(2, 2, 2), byComponents = FALSE,                              indexAlpha = 1, transparency = 1, walpha = FALSE, ...) {  as3d <- x  triangles <- as3d$triang  edges <- as3d$edge  vertex <- as3d$vertex  x <- as3d$x  if (class(indexAlpha) == "character")     if (indexAlpha == "ALL" | indexAlpha == "all")       indexAlpha = 1:length(as3d$alpha)  if (any(indexAlpha > length(as3d$alpha)) | any(indexAlpha <=                                                    0)) {    if (max(indexAlpha) > length(as3d$alpha))       error = max(indexAlpha)    else error = min(indexAlpha)    stop(paste("indexAlpha out of bound : valid range = 1:",                length(as3d$alpha), ", problematic value = ", error,                sep = ""), call. = TRUE)  }  if (clear) {    rgl.clear()  }  if (byComponents) {    components = components_ashape3d(as3d, indexAlpha)    if (length(indexAlpha) == 1)       components = list(components)    indexComponents = 0    for (iAlpha in indexAlpha) {      if (iAlpha != indexAlpha[1])         rgl.open()      if (walpha)         title3d(main = paste("alpha =", as3d$alpha[iAlpha]))      cat("Device ", rgl.cur(), " : alpha = ", as3d$alpha[iAlpha],           "\n")      indexComponents = indexComponents + 1      components[[indexComponents]][components[[indexComponents]] ==                                       -1] = 0      colors = c("#000000", sample(rainbow(max(components[[indexComponents]]))))      tr <- t(triangles[triangles[, 8 + iAlpha] == 2 |                           triangles[, 8 + iAlpha] == 3, c("tr1", "tr2",                                                           "tr3")])      if (length(tr) != 0)         rgl.triangles(x[tr, 1], x[tr, 2], x[tr, 3], col = colors[1 +                                                                    components[[indexComponents]][tr]], alpha = transparency,                       ...)    }  }  else {    for (iAlpha in indexAlpha) {      if (iAlpha != indexAlpha[1])         rgl.open()      if (walpha)         title3d(main = paste("alpha =", as3d$alpha[iAlpha]))      cat("Device ", rgl.cur(), " : alpha = ", as3d$alpha[iAlpha],           "\n")      tr <- t(triangles[triangles[, 8 + iAlpha] == 2 |                           triangles[, 8 + iAlpha] == 3, c("tr1", "tr2",                                                           "tr3")])      if (length(tr) != 0)         rgl.triangles(x[tr, 1], x[tr, 2], x[tr, 3], col = col[1],                       , alpha = transparency, ...)    }  }}alphabunny <- ashape3d(bunny, alpha = c(0.003))plot.ashape3d.2(alphabunny, col=5, indexAlpha = "all", transparency=1)bg3d(1)

enter image description here


The package Rvcg updated to version 0.14 in July 2016, and ball pivoting surface reconstruction was added. The function is vcgBallPivoting:

library(Rvcg) # needs to be >= version 0.14library(rgl)library(onion); data(bunny)# default parametersbunnybp <- vcgBallPivoting(bunny, radius = 0.0022, clustering = 0.2, angle = pi/2)shade3d(bunnybp, col = rainbow(1000), specular = "black")shade3d(bunnybp, col = "pink", specular = "black") # easier to see problem areas.

enter image description hereenter image description here

The ball pivoting and the default parameter settings are not perfect for the Stanford bunny (as noted by cuttlefish44 in the comments radius = 0.0022 does better than the default radius = 0), and you are left with some gaps in the surface. The actual bunny has 2 holes in the base and some scanning limitations contribute to a few other holes (as mentioned here: https://graphics.stanford.edu/software/scanview/models/bunny.html). You may be able to find better parameters, and it's quite fast to use vcgBallPivoting (~0.5 seconds on my machine), but additional effort / methods may be required to close the gaps.