The question is
a.write a function which finds the circle with the minimal area s.t it bounds a given list of points (use fminsearch and give appropriate plot).
b.If you managed do the same for sphere (find one with minimal volume)
What I've tried so far:
%%Main function
function minarea= mincircle(points)
maxx=max(points(1,:));
maxy=max(points(2m:));
radius=max(maxx,maxy);
minarea=fminsearch(#(x) circle(x,r,c),[0,0])
end
%%This function is supposed to give equalation of circle
function eq=circle(x,r,c)
eq=(x(1)-c(1)).^2+(x(2)-c(2)).^2 %=r?
% and here I don't know how to insert r:
end`
For better understanding I'll attach a sketch.
In these terms I want to find the area of the circle whose center is in O
Note: I don't believe that the circle you drew is the smallest possible bounding circle. It should be a little smaller, up and to the right, and should touch at least two points on its perimeter.
Approaching the problem
We have a set of points, and we want to draw a circle that encompasses all of them. The problem is that you need three bits of information to define a circle: the X and Y coordinates of the circle's center, and the circle's radius. So the problem doesn't seem straightforward.
However, there is a related problem that is much easier to solve. Suppose the circle's center is fixed. From that point, we make a circle grow concentrically outwards so that it becomes bigger and bigger. At some point, the circle will encompass one of the points in our set. As it gets bigger, it will encompass a second point, and a third, until all the points in our set fall within our circle. Clearly, as soon as the last point in the set falls within our circle, we have the smallest possible circle that encompasses all the points, given that we started by fixing the center point of the circle.
Moreover, we can determine what the radius of this circle is. It is simply the maximum distance from any point in the set to the center of the circle, since we stop when the last point is touched by the perimeter of our expanding circle.
The next problem is to determine What is the best starting point to place the center of our circle? Clearly if the starting point is far away from all the points in our set, then the radius must be very large to even encompass one point in the set. Intuitively, it must be "in the middle" of our points somewhere. But where, exactly?
Using fminsearch
My suggestion is that you want to find the point P(x, y) that minimises how large you have to grow the circle to encompass all the points in the set. And we're in luck that we can use fminsearch to find P.
According to the fminsearch documentation, the function you pass in must be a function of one parameter (which may be an array), and it must return a scalar. The idea is that you want the output of your function to be as small as possible, and you want to find out what inputs will make that possible.
In our case, we want to write a function that outputs the size of our circle, given the center of the circle as input. That way, fminsearch will find the center of the smallest possible circle that will still encompass all the points. I'm going to write a function that outputs the radius required to encompass all the points given a center point P.
pointsX = [..]; % X-coordinates of points in the set
pointsY = [..]; % Y-coordinates of points in the set
function r = radiusFromPoint(P)
px = P(1);
py = P(2);
distanceSquared = (pointsX - px).^2 + (pointsY - py).^2;
r = sqrt(max(distanceSquared));
end
Then we want to use fminsearch to find the point that gives us the smallest radius. I've just naively used the origin (0, 0) as my starting estimate, but you may have a better idea (like using the first point in the set)
P0 = [0, 0]; % starting estimate
[P, radiusMin] = fminsearch(#radiusFromPoint, P0);
The circle is defined by its center at P and radius of radiusMin.
And I'll leave it to you to plot the output and generalize to the 3D case!
Actually, while you may need it to complete your homework assignment (I assume that is what this is) you don't really need to use an optimizer at all. The minboundcircle code posted with my minimal bounding tools does it without use of an optimizer. (There is also a minboundsphere tool.)
Regardless, you might find a few tricks in there that will be useful. At the very least, learn how to reduce the size of the problem (and so the speed of solution) by use of a convex hull. After all, it is only the points on the convex hull that can determine a minimal bounding circle. All other points are simply a waste of CPU time.
Related
I am making game in Unity engine, where car is moving along the bezier curve by percentage of bezier curve legth.
On this image you can see curve with 8 stop points (yellow spheres). Between each stop point is 20% gap of total distance.
On the image above everything is working correctly, but when I move handles, that the handles have different length problem occurs.
As you can see on image above, distances between stop points are not equal. It is because of my algorithm, because I am finding point of segment by multiplying segment length by interpolation (t). In short problem is that: if t=0.5 it is not in the 50% percent of the segment. As you can see on first image, stop points are in half of segment, but in the second image it is not in half of segment. This problem will be fixed, if there is some mathematical formula, how to find distance middle point.
As you can see on the image above, there are two mid points. T param mid point can be found by setting t to 0.5 (it is what i am doing now), but it is not half of the distance.
How can I find distance mid point (for cubic bezier curve, that have handles in different distance)?
You have correctly observed that the parameter value t=0.5 is generally not the point in the middle of the length. That is a good start but the difficulty lies in the mathematics beneath.
Denoting the components of your parametric curve by x(t) and y(t), the length of the curve
between t=0 (the beginning) and a chosen parameter value t = u is equal to
What you are trying to do is to find u such that l(u) is one half of l(1). This is sometimes possible but often difficult or impossible. So what can you do?
One possibility is to approximate the point you want. A straightforward way is to approximate your Bezier curve by a piecewise linear curve (simply by choosing many parameter values 0 = t_0 < t_1 < ... < t_n = 1 and connecting the values in these parameters by line segments). Now it is easy to compute the entire length (Pythagoras Theorem is your friend) as well as the middle point (walk along the piecewise linear curve the prescribed length). The more points you sample, the more precise you will be and the more time your computation will take, so there is a trade-off. Of course, you can use a more complicated numerical scheme for the approximation but that is beyond the scope of the answer.
The second possibility is to restrict yourself to a subclass of Bezier curves that will let you do what you want. These are called Pythagorean-Hodograph (shortly PH) curves. They have the extremely useful property that there exists a polynomial sigma(t) such that
This means that you can compute the integral above and search for the correct value of u. However, everything comes at a price and the price here is that you will have less freedom, where to put the control points (for me as a mathematician, a cubic Bézier curve has four control points; computer graphics people often speak of "handles" so you might have to translate into your terminology). For the cubic case you can find the conditions on slide 15 of this seminar talk by Vito Vitrih.
Denote:
the control points,
;
then the Bézier curve is a PH curve if and only if
.
It is up to you to figure out, if you can enforce this condition in your situation or if it is too restrictive for your application.
I am reviewing some MATLAB code that is publicly available at the following location:
https://github.com/mattools/matGeom/blob/master/matGeom/geom2d/orientedBox.m
This is an implementation of the rotating calipers algorithm on the convex hull of a set of points in order to compute an oriented bounding box. My review was to understand intuitively how the algorithm works however I seek clarification on certain lines within the file which I am confused on.
On line 44: hull = bsxfun(#minus, hull, center);. This appears to translate all the points within the convex hull set so the calculated centroid is at (0,0). Is there any particular reason why this is performed? My only guess would be that it allows straightforward rotational transforms later on in the code, as rotating about the real origin would cause significant problems.
On line 71 and 74: indA2 = mod(indA, nV) + 1; , indB2 = mod(indB, nV) + 1;. Is this a trick in order to prevent the access index going out of bounds? My guess is to prevent out of bounds access, it will roll the index over upon reaching the end.
On line 125: y2 = - x * sit + y * cot;. This is the correct transformation as the code behaves properly, but I am not sure why this is actually used and different from the other rotational transforms done later and also prior (with the calls to rotateVector). My best guess is that I am simply not visualizing what rotation needs to be done in my head correctly.
Side note: The external function calls vectorAngle, rotateVector, createLine, and distancePointLine can all be found under the same repository, in files named after the function name (as per MATLAB standard). They are relatively uninteresting and do what you would expect aside from the fact that there is normalization of vector angles going on.
I'm the author of the above piece of code, so I can give some explanations about it:
First of all, the algorithm is indeed a rotating caliper algorithm. In the current implementation, only the width of the algorithm is tested (I did not check the west and est vertice). Actually, it seems the two results correspond most of the time.
Line 44 -> the goal of translating to origin was to improve numerical accuracy. When a polygon is located far away from the origin, coordinates may be large, and close together. Many computation involve products of coordinates. By translating the polygon around the origin, the coordinates are smaller, and the precision of the resulting products are expected to be improved. Well, to be honest, I did not evidenced this effect directly, this is more a careful way of coding than a fix…
Line 71-74! Yes. The idea is to find the index of the next vertex along the polygon. If the current vertex is the last vertex of the polygon, then the next vertex index should be 1. The use of modulo rescale between 0 and N-1. The two lines ensure correct iteration.
Line 125: There are several transformations involved. Using the rotateVector() function, one simply computes the minimal with for a given edge. On line 125, one rotate the points (of the convex hull) to align with the “best” direction (the one that minimizes the width). The last change of coordinates (lines 132->140) is due to the fact that the center of the oriented box is different from the centroid of the polygon. Then we add a shift, which is corrected by the rotation.
I did not really look at the code, this is an explanation of how the rotating calipers work.
A fundamental property is that the tightest bounding box is such that one of its sides overlaps an edge of the hull. So what you do is essentially
try every edge in turn;
for a given edge, seen as being horizontal, south, find the farthest vertices north, west and east;
evaluate the area or the perimeter of the rectangle that they define;
remember the best area.
It is important to note that when you switch from an edge to the next, the N/W/E vertices can only move forward, and are readily found by finding the next decrease of the relevant coordinate. This is how the total processing time is linear in the number of edges (the search for the initial N/E/W vertices takes 3(N-3) comparisons, then the updates take 3(N-1)+Nn+Nw+Ne comparisons, where Nn, Nw, Ne are the number of moves from a vertex to the next; obviously Nn+Nw+Ne = 3N in total).
The modulos are there to implement the cyclic indexing of the edges and vertices.
As you may have already noticed, in the newer versions of matlab the
boundary function (which computes the boundary for a set of 2d or 3d points) has been improved.
Now it is possible to give the function a parameter called 'shrink factor'. If the shrink factor is 0, then the boundary traced is the traditional convex hull. The boundary is more shrinked when the shrink parameter is bigger. The default value for the shrink factor is 0.5, in case you don't specify any value.
So, I understand its use and what it does (actually I've already used the function in a project), but I don't know how it works. What are the geometrical principles of this shrink factor?
Thanks!
Found your question while loooking for the answer myself. Hope you've solved it by now. I've figured it out and in case someone else finds this question, here's my understanding of the boundary() function.
The boundary function is an implementation of alpha shapes. Using alpha shapes, a set of points can be assigned a polygon by using a set of circles of a specific radius:
imagine an arbitrary shape drawn around the points and proceed to remove as much of this shape as possible using circles of a specific radius. Continue as long as possible, without enclosing any points. A small radius will mean more "material" can be removed, a larger radius means less "removal", i.e. a small radius creates a close cropped shape whereas an infinite radius recreates a convex hull of the set. The points determined to be edge points are then conencted with straight edges. This can create hollow areas inside the point set.
See e.g. http://doc.cgal.org/latest/Alpha_shapes_2/index.html
MATLAB has an alphashape() function which calculates alphashapes with all possible alpha radii giving different shapes. This is used in the boundary function.
boundary() workflow:
(1) Create alphashape
(2) Find critical alpha radius, needed to create a single region for alpha shape
(3) Extract all alphavalues that create unique shapes above this critical value
(4) Use the shrink factor, S, to select a single alpha value to use.
Example: with S=0.25, use alpha radius with index (1-.25)*numel(alphavalues>=alpha_crit). This creates an alpha shape
using the 75th smallest alpha radius giving rise to a single region
(for S=0.25).
If S=1 (max shrink), gives the lowest alpha-radius that gives a single
region for the alpha-shape.
If S=0 (no shrink), gives the maximum alpha-radius that gives a unique
shape. (Incraesing alpha radius further has no effect).
(5) set the threshold for filling in holes in the alphashape to be the same as the alphashape's area, i.e. fill in all holes
(6) Return the indices of the original point cloud correspocing to the vertices of this alphashape.
The relevant section of the boundary.m file (lines 79-86)
Acrit = shp.criticalAlpha('one-region'); %alpha-radius required for single region
spec = shp.alphaSpectrum();%all alphavalues
idx = find(spec==Acrit);
subspec = spec(1:idx);%alphavalues up to criticalAlpha
subspec = flipud(subspec);%reverse order
idx = max(ceil((1-S)*numel(subspec)),1); %find index from shrink factor
alphaval = subspec(idx);
shp.Alpha = alphaval; %set alpha value of alpha shape
shp.HoleThreshold = areavol; % remove holes in interior
Hope this is clear enough and useful to someone.
I use MATLAB R2014b
YiraDati's answer provides great details.
You can also type "open boundary" in command windows, and then all procedures are written in boundary function. And all subfunctions shown in boundary function are accessible using matlab documentation, like area(), criticalAlpha(), alphaSpectrum(), etc...
I have a multiple plants in a single binary image. How would I identify each leaf in the image assuming that each leaf is approximately elliptical?
example input: http://i.imgur.com/BwhLVmd.png
I was thinking a good place to start would be finding the tip of each leaf and then getting the center of each plant. Then I could fit the curves starting from the tip and then going to the center. I've been looking online and saw something involving a watershed method, but I do not know where to begin with that idea.
You should be aware that these things are tricky to get working robustly - there will always be a failure case.
This said, I think your idea is not bad.
You could start as follows:
Identify the boundary curve of each plant (i.e. pixels with both foreground and background in their neighbourhood).
Compute the centroid of each plant.
Convert each plant boundary to a polar coordinate system, with the centroid as the origin. This amounts to setting up a coordinate system with the distance of each boundary curve point on the Y axis and the angle on the X axis.
In this representation of the boundary curve, try to identify maxima; these are the tips of the leaves. You will probably need to do some smoothing. Use the parts of the curve before and after the maxima the start fitting your ellipses or some other shape.
Generally, a polar coordinate system is always useful for analysing stuff thats roughly circular.
To fit you ellipses, once you have a rough initial position, I would probably try an EM-style approach.
I would do something like this (I is your binary image)
I=bwmorph(bwmorph(I, 'bridge'), 'clean');
SK=bwmorph(I, 'skel', Inf);
endpts = bwmorph(SK,'endpoints');
props=regionprops(I, 'All');
And then connect every segment from the centroids listed in props.centroid to the elements of endpts that should give you your leaves (petals?).
A bit of filtering is probably necessary, bwmorph is your friend. Have fun!
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.