How do I get the "boundary" of a Delaunay triangulation? - scipy

Visually, it is clear to me that given a Delaunay triangulation, there are some points which form its "boundary". This boundary is different from a convex hull, since it is not minimal in the number of points, and it is not necessarily convex.
What is it called? Is there a way to get it from a scipy Delaunay triangulation?
(Note: I am not looking for an algorithm on how to determine this boundary, but rather a pre-baked scipy function. I already have an idea for how I can get the boundary of a Delaunay triangulation, but prefer to not re-invent the wheel.)

This is actually quite simple, there is no need for convex/concave hulls.
Assuming you have triangulated a closed surface, the key observation is to note that an edge of the triangulation belongs to the boundary if it's not shared by two different triangles.
From the scipy.spatial.Delaunay documentation, If P is a set of points and you have computed T = Delaunay(P), then T.neighbors equals -1 in it's kth coordinate if the edge opposite to the kth vertex belongs to the boundary.
Example code:
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import Delaunay
# Create triangulation of a rectangle
x = np.linspace(0,1,9)
y = np.linspace(0,1,9)
X,Y = np.meshgrid(x,y)
P = np.array([X.flatten(),Y.flatten()]).T
T = Delaunay(P)
# Find edges at the boundary
boundary = set()
for i in range(len(T.neighbors)):
for k in range(3):
if (T.neighbors[i][k] == -1):
nk1,nk2 = (k+1)%3, (k+2)%3
boundary.add(T.simplices[i][nk1])
boundary.add(T.simplices[i][nk2])
# Plot result
plt.triplot(P[:,0], P[:,1], T.simplices)
plt.plot(P[:,0], P[:,1], 'o')
plt.plot(P[list(boundary),0], P[list(boundary),1], 'or')
plt.show()

I'm pretty sure this is not recently present in scipy, it would make no sense to place it somewhere else than among the scipy.spatial.Delaunay object methods, and list of the methods is pretty short and doesn't contain anything that specific.
The method find_simplex might help you find the convex hull (assuming this means the smallest convex superset), but the engagement of the circumscribed circle (if I understood well the Delaunay triangulation definition) seemms like a completely new kind of obstacle.
Assuming that the simplex is a word for a "side" of this "triangle" , you would need to find union of all such simplexes to find the convex hull, so for the boundary you don't want all simplexex, only some of them, and here my imagination ends.

Related

Get Trajectory from Voronoi Diagram for Polygonal Obstacles

I'm trying to get the Trajectory from Voronoi Diagram using the library voronoi from Matlab. I'm using this code:
vo = (all the obstacles from a binary picture, plotted in a figure), where:
vo(1,:) : x-axis points
vo(2,:) : y-axis points
Code:
figure; hold on;
plot(vo(1,:),vo(2,:),'sr');
[vx,vy] = voronoi(vo(1,:),vo(2,:));
plot(vx,vy,'-b');
Obtaining:
In other words, how can I separate all the useless lines from the real trajectory?
The distinguishing property of the useless lines in this case is that they contain at least one vertex inside the polygonal obstacles.
There are many ways you might choose to decide if a vertex satisfies this condition but given that the coordinates come from a binary image, one of the most straightforward might be to check if the vertex comes within a pixel's distance of any point in vo:
[~,D] = knnsearch(vo,[vx(:),vy(:)]);
inObstacle = any(reshape(D,size(vx)) < 1);
plot(vx(:,~inObstacle),vy(:,~inObstacle),'-b');
If you cannot rely on the obstacles being filled with pixels (e.g. they may be hollow) then you probably need to determine which pixels belong to the same obstacle (perhaps using kmeans or bwconncomp) and then eliminate Voronoi edges that intrude into each object's convex hull. For a given obstacle made up of the pixels in vo listed by the linear indices idx:
K = convhull(vo(idx,1),vo(idx,2));
inObstacle = inpolygon(vx,vy,vo(idx(K),1),vo(idx(K),2));

find area of 3D polygon

Given a matrix nx3 that represents n points in 3D space. All points lie on a plane. The plane is given by its normal and a point lying on it. Is there a Matlab function or any Matlabby way to find the area directly from the matrix?
What i was trying to do is write a function that first computes the centroid,c, of the n-gon. Then form triangles : (1,2,c),(2,3,c),...,(n,1,c). Compute their area and sum up. But then i had to organise the polygon points in a cyclic order as they were unordered which i figured was hard. Is there a easy way to do so?
Is there a easier way in Matlab to just call some function on the matrix?
Here is perhaps an easier method.
First suppose that your plane is not parallel to the z-axis.
Then project the polygon down to the xy-plane simply by removing the 3rd coordinate.
Now compute the area A' in the xy-plane by the usual techniques.
If your plane makes an angle θ with the xy-plane, then your 3D
area A = A' / cos θ.
If your plane is parallel to the z-axis, do the same computation
w.r.t. the y-axis instead, projecting to the xz-plane.
To project from 3D to the plane normal to N, take some non-parallel vector A and compute the cross products U = N x A and V = N x U. After normalizing U and V, the dot products P.U and P.V give you 2D coordinates in the plane.
Joseph's solution is even easier (I'd recommend to drop the coordinate with the smallest absolute cosine).
You said the points all lie on a plane and you have the normal. You should then be able to reproject the 3-D points into 2-D coordinates in a new 2-D basis. I am not aware of a canned function in Matlab to do this , but coding it should not be difficult, this answer from Math.SE and this Matlab Central post should help you.
If you already solved the problem of finding the coordinates of the points in the 2-D plane they are in, you could use the Matlab boundary or convex hull function to compute the area of the boundary or convex hull enclosing the points.
[k,v]= boundary(x,y)
or
[k,v] =convhull(x,y)
where k is the vector of indices into points x,y, that define the boundary or convex hull, v is the area enclosed, and x, y are vectors of the x and y coordinates of your points.
What you were describing with trying to find triangles with the points sounds like a first attempt toward Delaunay triangulation. I think more recent versions of Matlab have functions to do Delaunay triangulation as well.

Output of delaunay triangulation from lidar data

I have to generate the mesh of the 3D-point cloud. So I used the delaunay function to perform the triangulation of points. The lidar data is a result of a human head scanning.
dt = delaunay(X,Y);
trisurf(dt,X,Y,Z);
When I used delaunay with two inputs it gives me output but not perfect. So I used three inputs (X,Y,Z)
dt = delaunay(X,Y,Z);
trisurf(dt,X,Y,Z);
But now the result comes out worse. I don't know what the problem is?
This is the full code that I have written:
load Head_cloud_point.txt;
data = Head_cloud_point;
for i = 1 : 3
X = data(:, 1);
end
for i = 1 : 3
Y = data(:, 2);
end
for i = 1 : 3
Z = data(:, 3);
end
[m n] = size(X);
[o p] = size(Y);
[r s] = size(Z);
[XI,YI]= meshgrid(X(m,n),Y(o,p));
ZI = interp2(X,Y,Z,XI,YI);
% dt = delaunay(X,Y);
% trisurf(dt,X,Y,ZI);
Head_cloud_point is the file with X,Y,Z coordinates. I have to generate the mesh using these coordinates.
Well, Delaunay is not going to do the trick directly here, neither the 2D nor the 3D version. The main reason is the way Delaunay is working. You can get some of the way, but the result is in general not going to be perfect.
You have not specified whether the poing cloud is the surface of the head, or the entire inner of the head (though another answer indicates the former).
First remember that Delaunay is going to triangulate the convex hull of the data, filling out any concavities, e.g. a C-like shape will have the inner part of the C triangulated (Ending like a mirrored D triangulation).
Assuming the point cloud is the surface of the head.
When using 2D Delaunay on all (X,Y), it can not distinguish between coordinates at the top of the head and at the bottom/neck, so it will mix those when generating the triangulation. Basically you can not have two layers of skin for the same (X,Y) coordinate.
One way to circumvent this is to split the data in a top and bottom part, probably around the height of the tip of the nose, triangulate them individually and merge the result. That could give something fairly nice to look at, though there are other places where there are similar issues, for example around the lips and ears. You may also have to connect the two triangulations, which is somewhat difficult to do.
Another alternative could be to transform the (X,Y,Z) to spherical coordinates (radius, theta, gamma) with origin in the center of the head and then using 2D Delaunay on (theta,gamma). That may not work well around the ear, where there can be several layers of skin at the same (theta,gamma) direction, where again Delaunay will mix those. Also, at the back of the head (at the coordinate discontinuity) some connections will be missing. But at the rest of the head, results are probably nice. The Delaunay triangulation in (theta, gamma) is not going to be a Delaunay triangulation in (X,Y,Z) (the circumcircle associated with each triangle may contain other point in its interior), but for visualization purposes, it is fine.
When using the 3D Delaunay using (X,Y,Z), then all concavities are filled out, especially around the tip of the nose and the eyes. In this case you will need to remove all elements/rows in the triangulation matrix that represents something "outside" the head. That seems difficult to do with the data at hand.
For the perfect result, you need another tool. Try search for something like:
meshing of surface point cloud
Since you have a cloud of raw data representing a 3D surface, you need to do a 3D surface interpolation to remove the noise. This will determine a function z=f(x,y) that best fits your data. To do that, you can use griddata, triscatteredinterp (deprecated) or interp2.
Note: From the context of your question, I assumed you use MATLAB.
[EDIT]
As you indicated that your data represents a head, the surface of a head which is a spheroid, it is not a function of the form z=f(x,y). See this post concerning possible solutions to visualizing spherical surfaces http://www.mathworks.com/matlabcentral/newsreader/view_thread/2287.

matlab: triangulate point set

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

How do I break a polyhedron into tetrahedra in MATLAB?

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