Calculate angle of matrix with topography for each triangle - matlab

I have a matrix with data of a topography, let's say several hills. I want to have information of the angle of each data point to the vertical line. Here are two examples:
If I consider a place near the foot of the hill that is totally flat, I have a degree of 90° (90° to the vertical line).
If I am at the steepest point of the hill, I have a lower angle of let's say 50°.
To compute this I guess I have to to connect all the topography data so that (at least) three near pixels form triangle. After that I have to compute the angle(s) of this triangle.
Can I use a existing algorithm?

If your heightmap is a matrix A then you could approximate the the gradient components of every inner point (without the egdes) by
Xgrad = (A(2:end-1,3:end)-A(2:end-1,1:end-2))/2;
Ygrad = (A(3:end,2:end-1)-A(1:end-2,2:end-1))/2;
The angulars will then be
deg = (pi/2 - atan(sqrt(Xgrad.^2 + Ygrad.^2),1))/pi*180;
Depending on your heightmap, differentiating numerically can produce "fuzzy" results. Maybe you have to do some blur-filtering in order to produce smoother gradients.

Related

Can I compute contour orientation without using polygon area sign?

Most of the times, I determine contour orientation generating 2D points and computing the closed polygon area. Depending on the area value sign I can understand if the contour is oriented clockwise or not (see How to determine if a list of polygon points are in clockwise order?).
Would it be possible to do the same computations without generating 2D points? I mean, relying only on geometric curve properties?
We are interested in determining the orientation of contours like these ones without sampling them with 2D points.
EDIT: Some interesting solutions can be found here:
https://math.stackexchange.com/questions/423718/general-way-to-find-out-whether-a-curve-is-positively-oriented
Scientific paper: Determining the orientation of closed planar curves, DJ Filip (1990)
How are those geometric curves defined?
Do you have an angle for them? The radius doesn't matter, only the difference between entry-angle and exit-angle of each curve.
In that case, a trivial idea crossing my mind is to just sum up all the angles. If the result is positive, you know you had more curves towards the right meaning it's a clockwise contour. If it was negative, then more curves were leftwards -> anti-clockwise contour. (assuming that positive angels determine a right-curve and vica versa)
After thinking about this for awhile, for polygons that contain arcs I think there are three ways to do this.
One, is to break the arcs into line segments and then use the area formula as described above. The success of this approach seems to be tied to how close the interpolation of the arcs is as this could cause the polygon to intersect itself.
A quicker way than the above would be to do the interpolation of the arcs and then find a vertex in the corner (minimal Y, if tie minimal X) and use the sign of the cross product for that vertex. Positive CCW, negative CW. Again, this is still tied to the accuracy of the interpolation.
I think a better approach would be to find the midpoint of the arc and create two line segments, one from the beginning of the arc to the midpoint and another from the midpoint to the end of the arc and replace the arc with these line segments. Now you have a polygon with only line segments. Then you can add up all the normalized cross products of all the vertices. The sign will tell you the direction. Positive is counter-clockwise, negative is clockwise. In this case it doesn't matter if the polygon self-intersects.

Optimizing computation of distance to triangle using barycentric coordinates

Building on the discussions here and here. I'm trying to compute the shortest distance between a 3D line and a 3D triangle.
I'm using barycentric coordinates to determine whether or not the point is inside the triangle. So given a triangle defined by vertices UVW and a line defined by point AB, I first compute the intersection of line AB with the plane defined by UVW. Let's call this intersection P and assume I've already done the checks to verify whether or not the point actually intersects the plane at all.
I then compute barycentric coordinates (S,T) such that S is defined along the edge UV and T is defined along the edge UW. Naturally, if 0≤S and 0≤T and S+T≤1 then P is on the triangle (or its edge) and my distance to the triangle is obviously zero.
If that's not true then P is outside the triangle and I need to compute the distance. The guidance of from the first link says to project point P onto all three edges to get three candidate points. Adding those points to the three triangle's vertices, you then have six points to test against.
Isn't it easier than that, though? If T<0, then don't you already know that UV is the closest edge and you only have to test against the projection of P onto that line? Similarly, if S<0 then UW would be the closest edge. If T>0 and S>0 then VW is the closest edge.
Thus based on the signs of S and T you already know the closest edge and only have to compute the distance from P to its projection onto that edge. If the projection isn't inside the triangle, then the closest point is either vertex. Thus your computations are about 1/3 of the proposed methods.
Am I missing something here, or is this a valid optimization? I'm fairly new to barycentric coordinates and their attributes.
It turns out that the problem of closest distance from a point and from a line are very similar and can both be reduced to a pure 2D problem.
Distance from a point
By Pythagoras, the squared distance from a point to a point of the triangle is the sum of the squared distance to the plane of support of the triangle and the squared distance of the projection of the point to that plane.
The latter distance is precisely the distance from the normal line to the triangle.
Distance from a line
Looking in the direction of the line, you see the projected triangle and the line is reduced to a single point. The requested 3D distance is equal to the 2D distance seen on the projection.
To obtain the desired coordinates, you use an auxiliary coordinate frame such that Z is in the direction of the line (and XY is a perpendicular plane); for convenience, choose the origin of the new frame to be on the line. Then by just ignoring Z, you get a planar problem in XY. The change of coordinates is an affine tranformation.
Point vs. triangle
Consider the three triangles formed by the origin (projection of the point/line) and a pair of triangle vertices (taken in cyclic order). The signed area of these triangles is a mere 2x2 determinant.
If the three areas have the same sign, the point is inside. Otherwise, the signs tell you where you are among the six surrounding regions, either past an edge or past a vertex.
On the upper figure, the point is inside (three positive areas). On the other figure, it is outside of the top-right edge (one negative area). Also note that dividing an area by the length of the corresponding side, you get the distance to the side. (Factor 2 omitted.)
The total work is
compute the affine frame;
convert the coordinates of the 3 or 4 points;
compute the three signed areas;
if inside, you are done;
otherwise, if in an edge region, compute a distance to a line and two distances to points;
otherwise you are in a vertex region, compute two distances to lines and one distance to vertex.

How do I interpret the orientation of the gradient when using imgradient in MATLAB?

I am finding the gradient of an image. For now I am simply using a 5 x 5 image. I am more interested in finding the direction of the gradient but I am not getting the results manually on paper as I get them using MATLAB function imgradient. Please refer to the following images to know more about the input images and the Sobel filter that is used here to find the gradient of an image. One of the 3 x 3 sobel operator used here is the one that I get using the function
f1 = fspecial('sobel');
and the other one is obtained by just transposing the f1.
Please note that I am trying to find the direction of only one pixel here that is rounded by red color. Here in the first two cases my result matches with that i obtain using imgradient function but in the third case imgradient gives -135 degree whereas I am getting it to be -45. Please help me find the error.
Also please explain how to interpret the following gradient directions as shown in the follwing image.
Your calculations are correct but it is highly recommended that you don't use the atan(y/x) definition because this calculation is not cognizant of the quadrant that the angle of the gradient resides in. Doing atan(y/x) with your components would falsely report the angle to be -45 degrees when that isn't correct. You should use atan2 instead.
Now the internals of imgradient are quite straight forward. I'd like to point out that the angle reported by imgradient is assuming that the y coordinate is increasing from bottom to top. In addition, imgradient should report the angle of orientation that is pointing to the greatest rate of change. In the case of images, this points in the direction where we progress from dark pixels to light pixels.
First a call to imgradientxy is called and a call to fspecial('sobel') is made if you provide the sobel flag to imgradient. In fact, this portion of imgradientxy is what is important to remember (starting at line 75: MATLAB R2015a):
case 'sobel'
h = -fspecial('sobel'); %// Align mask correctly along the x- and y- axes
Gx = imfilter(I,h','replicate'); %'
if nargout > 1
Gy = imfilter(I,h,'replicate');
end
Notice that the negative of the output of fspecial is performed as well as the comment provided at that line. This is to ensure that the mask to detect horizontal edges (i.e. Gy) is y-down (as it is commonly known in computer graphics). Specifically, the origin of the image is at the top-left corner and not the bottom left.
This is a pictorial representation of how the coordinate system is laid out in y-down:
Source: Wikipedia - Rotation Matrix
As such, when finding the orientation there is an additional requirement to ensure that the angle of the orientation of the gradient is with respect to the y-up coordinate system which is what we're used to. Therefore when you are finding the angle of orientation of the gradient, you need to negate the y coordinate before calculating the angle so that the angle is with respect to the standard convention instead.
Pursuing the definition of the gradient that you seek is the conventional system of the y coordinate increasing from bottom to top. The negation is required and in fact if you examine the source code for imgradient, this is precisely what is being done at line 127 of the code (version R2015a):
Gdir = atan2(-Gy,Gx)*180/pi; %// Radians to degrees
You may be asking yourself why there is a need to negate the mask and again negate the y coordinate after to find the orientation. The reason why is because the modified mask is required to properly capture the magnitude of the gradient and so we negate the mask once and find the gradient magnitude and then we negate the y coordinate so that we can find the angle with respect to the conventional coordinate system.
In your case, given that Gx = 765 and Gy = -765, substituting these quantities into the above equation yields:
>> Gy = 765;
>> Gx = -765;
>> Gdir = atan2(-Gy,Gx)*180/pi
Gdir =
-135
This makes sense because the gradient direction corresponds to the direction towards the greatest rate of change. -135 degrees means that we're pointing to the south west which does make sense as we are progressing from dark pixels to light pixels.
Now if you consult your third example image, the angles reported by imgradient are indeed correct. Simply draw a line from the dark area to the light area and see what angle it makes with the x axis where it is aligned with the columns increasing towards the right. The first angle of +90 degrees makes sense as we are moving from bottom to top to follow the dark area and light. This is a similar situation with the situation where the image is reversed. The third situation is what we have seen before and the fourth situation is simply the third situation rotated by 180 degrees and so naturally the angle of orientation from dark to light is now +45 degrees as opposed to -135 degrees previously.

Arrange the vertices of a 3D convex polygonal plane in counter clockwise direction in MATLAB

I have a convex polygon in 3D. For simplicity, let it be a square with vertices, (0,0,0),(1,1,0),(1,1,1),(0,0,1).. I need to arrange these vertices in counter clockwise order. I found a solution here. It is suggested to determine the angle at the center of the polygon and sort them. I am not clear how is that going to work. Does anyone have a solution? I need a solution which is robust and even works when the vertices get very close.
A sample MATLAB code would be much appreciated!
This is actually quite a tedious problem so instead of actually doing it I am just going to explain how I would do it. First find the equation of the plane (you only need to use 3 points for this) and then find your rotation matrix. Then find your vectors in your new rotated space. After that is all said and done find which quadrant your point is in and if n > 1 in a particular quadrant then you must find the angle of each point (theta = arctan(y/x)). Then simply sort each quadrant by their angle (arguably you can just do separation by pi instead of quadrants (sort the points into when the y-component (post-rotation) is greater than zero).
Sorry I don't have time to actually test this but give it a go and feel free to post your code and I can help debug it if you like.
Luckily you have a convex polygon, so you can use the angle trick: find a point in the interior (e.g., find the midpoint of two non-adjacent points), and draw vectors to all the vertices. Choose one vector as a base, calculate the angles to the other vectors and order them. You can calculate the angles using the dot product: A · B = A B cos θ = |A||B| cos θ.
Below are the steps I followed.
The 3D planar polygon can be rotated to 2D plane using the known formulas. Use the one under the section Rotation matrix from axis and angle.
Then as indicated by #Glenn, an internal points needs to be calculated to find the angles. I take that internal point as the mean of the vertex locations.
Using the x-axis as the reference axis, the angle, on a 0 to 2pi scale, for each vertex can be calculated using atan2 function as explained here.
The non-negative angle measured counterclockwise from vector a to vector b, in the range [0,2pi], if a = [x1,y1] and b = [x2,y2], is given by:
angle = mod(atan2(y2-y1,x2-x1),2*pi);
Finally, sort the angles, [~,XI] = sort(angle);.
It's a long time since I used this, so I might be wrong, but I believe the command convhull does what you need - it returns the convex hull of a set of points (which, since you say your points are a convex set, should be the set of points themselves), arranged in counter-clockwise order.
Note that MathWorks recently delivered a new class DelaunayTri which is intended to superseded the functionality of convhull and other older computational geometry stuff. I believe it's more accurate, especially when the points get very close together. However I haven't tried it.
Hope that helps!
So here's another answer if you want to use convhull. Easily project your polygon into an axes plane by setting one coordinate zero. For example, in (0,0,0),(1,1,0),(1,1,1),(0,0,1) set y=0 to get (0,0),(1,0),(1,1),(0,1). Now your problem is 2D.
You might have to do some work to pick the right coordinate if your polygon's plane is orthogonal to some axis, if it is, pick that axis. The criterion is to make sure that your projected points don't end up on a line.

Principal direction in a binary image

As shown in image, there is a binary polygonal image. I want to find the principal direction in the image with respect to X-axis. I have shown the principal direction and X-axis with blue line. This can be done using PCA but my problem is such a small rectangle will have around 1000 pixels and I have to find Principal directions for around 100 polygons (polygon can be of arbitrary shape).
One approach that I have thought is:
Project that rectangle onto a line which is oriented at degrees at an interval (say) 5 degrees. The projection which has the maximum variance is the desired projection axis, and thus that is the desired angle. But this also falls under a greedy approach and thus will take time. Is there a smarter approach?
Also, if anybody could explain the exact procedure to do this using PCA, it would be helpful. I know the steps:
1. Take the covariance matrix.
2. Get the top eigenvector corresponding to largest eigenvalue -> that will be the principal direction.
But I am confused in the following statement which I often read everywhere:
A column vector: [0.5 0.5] is the first principal component and it gives the direction of the maximum variance. So can do I exactly calculate the angle by which I should rotate the data so that it will become parallel to X-axis.
Compute the eigenvector associated with the highest eigen value. Call that v. Normalize v. v = v/norm(v);
Compute angle between that and the horizontal direction: angle=acos(sum(v.*[1,0]))
Rotate by -angle, transformation matrix T = [cos(-angle) -sin(-angle); sin(-angle) cos(-angle)], multiply all points by that matrix. Do that for all polygons.