I want to generate a binary mask that has ones for all voxels inside and zeros for all voxels outside a volume. The volume is defined by the convex hull around a set of 3D coordinates (<100; some of the coordinates are inside the volume).
I can get the convex hull using CONVHULLN, but how do I convert that into a binary mask?
In case there is no good way to go via the convex hull, do you have any other idea how I could create the binary mask?
You can solve this problem using the DelaunayTri class and the pointLocation method. Here's an example:
pointMatrix = rand(20,3); %# A set of 20 random 3-D points
dt = DelaunayTri(pointMatrix); %# Create a Delaunay triangulation
[X,Y,Z] = meshgrid(0:0.01:1); %# Create a mesh of coordinates for your volume
simplexIndex = pointLocation(dt,X(:),Y(:),Z(:)); %# Find index of simplex that
%# each point is inside
mask = ~isnan(simplexIndex); %# Points outside the convex hull have a
%# simplex index of NaN
mask = reshape(mask,size(X)); %# Reshape the mask to 101-by-101-by-101
The above example creates a logical mask for a 101-by-101-by-101 mesh spanning the unit volume (0 to 1 in each dimension), with a 1 (true) for the mesh points inside the convex hull of the 3-D point set.
It's late here, so only a very sketchy suggestion:
With the points from your convex hull construct a Delaunay tessellation.
Using the pointLocation method of the DelaunayTri class test every point in your array of pixels.
I expect that this will be very slow, and that there are better solutions, if one comes in my dreams I'll post again tomorrow.
This is a scan conversion problem. Check out section 8 of 3D Scan-Conversion Algorithms for Voxel-Based Graphics.
The algorithm you want is the solid one, and is slightly simpler since you are voxelizing a convex polyhedron whose faces are triangles - each "voxel" run is bounded by two triangles.
Related
I have a dataset of 3D points, which are arranged in clusters resembling a (semi-)ellipsoidal shape. When I try standard ellipsoid fitting as, e.g. implemented in the MATLAB function http://www.mathworks.com/matlabcentral/fileexchange/24693-ellipsoid-fit , I get imaginary radii, no matter if I apply the fitting to all points within the ellipsoidic volume or only to points sitting on its convex hull.
I wonder whether the fact that the cluster shape is more semi-ellipsoidal than resembling a full ellipsoid leads to these instabilities? Is there any more robust method that could solve my problem?
UPDATE:
This is an example for one such cluster of 3D points. The blue circles indicated points located on the convex hull of the cluster.
The minimal working example for the convex hull case would be as follows:
k = convhull(x, y, z);
ind = unique(k(:));
[center,radii,evecs,~] = ellipsoid_fit([x(ind),y(ind),z(ind)], 1);
Given a point set (i.e a 3XN array of vertices), how can I triangulate it using matlab?
Assuming the point set does represent some surface of an object, and does not contain any noise.
EDIT:
The chosen answer gives a way to create the tetrahedrons of a mesh. I was looking for triangulation; for my specific case of a convex shape, the convex hull (using convhulln as suggested in the answer's comments) was enough.
To create a Delaunay triangulation, you can use the class DELAUNAYTRI:
You create a triangulation object by calling
DT = DelaunayTri(coordinates);
where coordinates is a N-by-3 (or 2) array of vertex coordinates.
To access the triangulation, call
tri = DT.triangulation;
To plot, call e.g.
patch('Vertices',DT.X,'Faces',DT.triangulation)
use delaunay3 and convert the tetrahedral mesh into a triangular one
http://www.mathworks.com/matlabcentral/fileexchange/5355-toolbox-graph/content/toolbox_graph/tet2tri.m
I have a large (~60,000) set of triplet data points representing x,y, and z coordinates, which are scattered throughout a Cartesian volume.
I'm looking for a way to use Matlab to visualize the non-convex shape/volume described by the maximum extent of the points.
I can of course visualize the individual points using scatter3, but given the large number of points the details of the shape are obscured by the noise of the dots.
As an analogy, imagine that you filled a hour glass with spheres of random sizes such as BBs, ping pong balls, and kix and then were given the coordinates of the center of each of each object. How would you take those coordinates and visualize the shape of the hour glass containing them?
My example uses different sized objects because the spacing between data points is non-uniform and effectively random; it uses an hourglass because the shape is non-convex.
If your surface enclosing the points can be described as a convex polyhedron (i.e. like the surface of a cube or a dodecahedron, without concave pits or jagged pointy parts), then I would start by creating a 3-D Delaunay triangulation of the points. This will fill the volume around the points with a series of tetrahedral elements with the points as their vertices, and you can then find the set of triangular faces that form the outer shell of the volume using the convexHull method of the DelaunayTri class.
Here's an example that generates 200 random points uniformly distributed within the unit cube, creates a tetrahedral mesh for these points, then finds the 3-D convex hull for the volume:
interiorPoints = rand(200,3); %# Generate 200 3-D points
DT = DelaunayTri(interiorPoints); %# Create the tetrahedral mesh
hullFacets = convexHull(DT); %# Find the facets of the convex hull
%# Plot the scattered points:
subplot(2,2,1);
scatter3(interiorPoints(:,1),interiorPoints(:,2),interiorPoints(:,3),'.');
axis equal;
title('Interior points');
%# Plot the tetrahedral mesh:
subplot(2,2,2);
tetramesh(DT);
axis equal;
title('Tetrahedral mesh');
%# Plot the 3-D convex hull:
subplot(2,2,3);
trisurf(hullFacets,DT.X(:,1),DT.X(:,2),DT.X(:,3),'FaceColor','c')
axis equal;
title('Convex hull');
You could treat your data as a sample from a three-dimensional probability density, and estimate that density on a grid, e.g. via a 3d histogram, or better a 3d kernel density estimator. Then apply a threshold and extract the surface using isosurface.
Unfortunately, hist3 included in the Statistics Toolbox is (despite its name) just a 2d histogram, and ksdensity works only with 1d data, so you would have to implement 3d versions yourself.
Let's say I have a polygon, and I want to mesh it. In order to further put constraints on the mesh I get, I will supply a list of fix points ( which must lie inside the polygon) so that they must be connected by the triangle elements generated.
What is the matlab command to do it? I tried delaunay command, but it can't work on concave polygon because the delaunay command will always return me a list of elements that encompass a convex area.
The function you want to use is DelaunayTri, and you would follow these steps to do it:
Create a list of the edge points in your polygon.
Take all of the vertex points of your polygon and combine them with the additional fixed points you want to include inside the polygon.
Create a constrained triangulation (as I've illustrated in other answers here and here).
As you noted, this will create a triangulation of the convex hull (even if you have a concave polygon), so you would have to remove triangles outside of the constrained edges using the method inOutStatus (also illustrated in the answers linked above).
Here's some sample code:
polygonVertices = [0 0;... %# Concave polygon vertices
0 1;...
1 1;...
0.5 0.5;...
1 0];
polygonEdges = [1 2;... %# Polygon edges (indices of connected vertices)
2 3;...
3 4;...
4 5;...
5 1];
otherVertices = [0.5.*rand(5,1) rand(5,1)]; %# Additional vertices to be added
%# inside the polygon
vertices = [polygonVertices; otherVertices]; %# Collect all the vertices
dt = DelaunayTri(vertices,polygonEdges); %# Create a constrained triangulation
isInside = inOutStatus(dt); %# Find the indices of inside triangles
faces = dt(isInside,:); %# Get the face indices of the inside triangles
And now the variables faces and vertices can be used to plot the meshed polygon.
Working with older versions of MATLAB...
Looking through the archived version documentation (note: a MathWorks account is required to do so), one can see that DelaunayTri first appeared in version 7.8.0 (2009a). Prior to that, the only built-in functionality available for performing 2-D Delaunay triangulation was delaunay, which was based on Qhull and was thus unable to support constrained triangulations or triangulations of non-convex surfaces.
The newer DelaunayTri uses CGAL. As such, one option for users of versions older than 7.8.0 is to create MEX-files to interface CGAL routines in MATLAB. For example, if you're faced with triangulating a concave polygon, you can create a MEX-file to interface one of the convex partitioning routines in CGAL in order to break the concave polygon into a set of convex polygons. Then delaunay could be used to triangulate each convex polygon, and the final set of triangulations grouped into one larger triangulation of the concave polygon.
I have a polyhedron, with a list of vertices (v) and surfaces (s). How do I break this polyhedron into a series of tetrahedra?
I would particularly like to know if there are any built-in MATLAB commands for this.
For the convex case (no dents in the surface which cause surfaces to cover each other) and a triangle mesh, the simple solution is to calculate the center of the polyhedron and then connect the three corners of every face with the new center.
If you don't have a triangle mesh, then you must triangulate, first. Delaunay triangulation might help.
If there are holes or caves, this can be come arbitrarily complex.
I'm not sure the OP wanted a 'mesh' (Steiner points added) or a tetrahedralization (partition into tetrahedra, no Steiner points added). for a convex polyhedron, the addition of Steiner points (e.g. the 'center' point) is not necessary.
Stack overflow will not allow me to comment on gnovice's post (WTF, SO?), but the proof of the statement "the surfaces of a convex polyhedron are constraints in a Delaunay Tesselation" is rather simple: by definition, a simplex or subsimplex is a member in the Delaunay Tesselation if and only if there is a n-sphere circumscribing the simplex that strictly contains no point in the point set. for a surface triangle, construct the smallest circumscribing sphere, and 'puff' it outwards, away from the polyhedron, towards 'infinity'; eventually it will contain no other point. (in fact, the limit of the circumscribing sphere is a half-space; thus the convex hull is always a subset of the Delaunay Tesselation.)
for more on DT, see Okabe, et. al, 'Spatial Tesselations', or any of the papers by Shewchuk
(my thesis was on this stuff, but I remember less of it than I should...)
I would suggest trying the built-in function DELAUNAY3. The example given in the documentation link resembles Aaron's answer in that it uses the vertices plus the center point of the polyhedron to create a 3-D Delaunay tessellation, but shabbychef points out that you can still create a tessellation without including the extra point. You can then use TETRAMESH to visualize the resulting tetrahedral elements.
Your code might look something like this (assuming v is an N-by-3 matrix of vertex coordinate values):
v = [v; mean(v)]; %# Add an additional center point, if desired (this code
%# adds the mean of the vertices)
Tes = delaunay3(v(:,1),v(:,2),v(:,3)); %# Create the triangulation
tetramesh(Tes,v); %# Plot the tetrahedrons
Since you said in a comment that your polyhedron is convex, you shouldn't have to worry about specifying the surfaces as constraints in order to do the triangulation (shabbychef appears to give a more rigorous and terse proof of this than my comments below do).
NOTE: According to the documentation, DELAUNAY3 will be removed in a future release and DelaunayTri will effectively take its place (although currently it appears that defining constrained edges is still limited to only 2-D triangulations). For the sake of completeness, here is how you would use DelaunayTri and visualize the convex hull (i.e. polyhedral surface) as well:
DT = DelaunayTri(v); %# Using the same variable v as above
tetramesh(DT); %# Plot the tetrahedrons
figure; %# Make new figure window
ch = convexHull(DT); %# Get the convex hull
trisurf(ch,v(:,1),v(:,2),v(:,3),'FaceColor','cyan'); %# Plot the convex hull