I have a matrix of landmarks that denotes a nose. I wish to convert this matrix to mesh3d so that I could use shade3d
function to visualize the surface.
Here is the dput of my data. I have to deposit it in GitHub because it is too large to be directly put here.
The three columns are x, y, and z coordinates. I would like to ask how can I convert this matrix to mesh3d. I tried as.mesh3d
, however, I was returned error because the number of vertices is not a multiple of 3 or 4.
mesh.d <- as.mesh3d(deformed, triangles = T)
Error in as.mesh3d.default(deformed, triangles = T) : length(x)%%3 == 0 is not TRUE
I also tried to remove the last two rows so that my data has 621 rows, which is a multiple of 3. I then used shade3d
to plot. However, the resultant plot does not give surface mesh of a nose. The function mesh3d
requires input of not just vertices, but also indices which I do not have. I therefore ask if it is possible to convert my coordinate matrix to an object of mesh3d in R?
The indices describe the triangles formed from triplets of vertices. If you don't have them given to you, you will need to construct them somehow.
There are a few options. You can use the alphashape3d::ashape3d
function to approximate the outline of the points. You need to choose the alpha
parameter; for example, with alpha = 20
I get
ash <- ashape3d(as.matrix(nose), alpha=20)
shade3d(as.mesh3d(ash))
This would work even if the points were randomly rearranged, but in fact, if you plot
plot3d(nose, type = "l")
you can see that the points are very regularly organized:
If you can work out how they are organized, you might be able to rearrange the x, y and z coordinates into matrices and use surface3d()
to plot them. For example, this plots all but the first 23 points:
m1x <- matrix(nose[24:323,1], nrow=20)
m1y <- matrix(nose[24:323,2], nrow=20)
m1z <- matrix(nose[24:323,3], nrow=20)
m2x <- matrix(nose[324:623,1], nrow=20)
m2y <- matrix(nose[324:623,2], nrow=20)
m2z <- matrix(nose[324:623,3], nrow=20)
mx <- cbind(m1x[,15:1], m2x)
my <- cbind(m1y[,15:1], m2y)
mz <- cbind(m1z[,15:1], m2z)
library(rgl)
open3d()
surface3d(mx, my, mz, col = "gray")
You can see that the alpha3d
plot fills out the side of the nose too much. However, this one ignores 23 points; I can't really see how they should be incorporated.