Smallest length of the perimeter of a rectangular enclosing all points - convex-hull

I'm having a problem: Given N points on 2D plane (3 <= N <= 10^5), the task is calculating the smallest length of the perimeter of a rectangular enclosing all points.
I think the tag of this problem is convexhull, but I can't find any idea for that.
Can someone help me this problem
Problem link: https://open.kattis.com/problems/fenceortho

Related

How can I compute the diameter of the circle that circumscribes an irregular object?

I want a function to compute and get the diameter of the circle that circumscribes the object. Is there a built-in function in MATLAB to do this? Otherwise, what can I do?
Try this algorithm:
Compute the average x and average y for every point in the irregular object. This is done by taking the x and y component for every point and add them into the total x and total y and then divide by the number of points. This average x and average y point algorithm gives you a non-weighted center of the object.
Use that center point to compute the distance for every point in the irregular object again. Keeping the largest distance as the radius of the object.
Use the center point and the radius to compute the circumference.
I am submitting proof that the distance between the 2 points that are furthest apart in the object fails with a simple triangle. See image below. Also, the big-O notation for computing the two points that are the furthest apart is x^2. The big-O for this algorithm is 2x. The diameter of the circle in the image would be computed as 20; distance between -10,0 and 10,0. A circle of diameter 20 will not encompass the point # 0,-11. Any movement of the circle would automatically remove at least one of the two points used to compute the diameter of the circle because both points are on tangents.
Suppose M is a mask in BW, just do :
[b_x,b_y] = find(bwperim(M)== 1)
Check this function bwperim

Measure circularity or ellipticality

I have some binary images that want to classify them base on shape of them in MATLAB. If they have circular or elliptical shape they belong to class one,if they have elliptical shape with dent in their boundary they belong to class two. I dont know how can I use this feature. Can any body help me with this?
You can use the eccentricity property in regionprops. From MATLAB documentation of eccentricity:
The eccentricity is the ratio of the distance between the foci of the ellipse and its major axis length. The value is between 0 and 1. (0 and 1 are degenerate cases. An ellipse whose eccentricity is 0 is actually a circle, while an ellipse whose eccentricity is 1 is a line segment.)
So as the value of eccentricity increases , the ellipse starts becoming flatter. Hence, at its maximum value = 1, it is a line segment.
To check if there is a dent in the ellipse, you can use check for convexity. Whenever there is a dent in an ellipse, it will be non-convex. In other words, if you try to fit a convex polygon, it won't be able to approximate the shape well enough. You can use convexArea property to check the same. From MATLAB documentation of convexArea:
Returns a p-by-2 matrix that specifies the smallest convex polygon that can contain the region. Each row of the matrix contains the x- and y-coordinates of one vertex of the polygon. Only supported for 2-D label matrices.
So you use bwlabel to create a 2-D label matrix from your binary image and then check the difference between the area of your binary image and the area of the fitted convex polygon. Measuring area could be as simple as counting pixels. You already know that the number pixels of your fitted convex polygon = p. Just take the absolute difference between p and the number of pixels in your original binary image. You should be able to easily set a threshold to classify into one of the two classes.
I think you can write the code for this. Hope this helps.

Calculate distance between coordinates but with restrictions

I managed to find the intersections of an arbitrary number of lines within a binary image.
Then i use a function where i detect the intersections between the lines. So now i have the coordinates of the intersections saved in an array.
Now i want to calculate the distance between the intersections(an imaginary line that connects all my intersections) but i want the distance calculation to traverse along the lines that are already on the binary image.
So the distance calculation cannot escape a line while calculating, instead it must ''walk along it''.
The imaginary path(of which eventually we calculate its distance) must walk along the already drawn lines.
EDIT** THIS IS MY INTERSECTION DETECTION ''ALGO''
clear all
pellara4=imread('C:/users/lemesios/desktop/pellara4.jpg');
blackwhitepellara=im2bw(pellara4,0.5);
I = blackwhitepellara;
C = corner(I);
num_of_rows=size(C,1);
num_of_cols=size(C,2);
for z =1:num_of_rows
k=C(z,2);
j=C(z,1);
if (I(k+1,j)==0)&& (I(k,j+1)==0) && (I(k-1,j)==0) && (I(k,j-1)==0)
imshow(I);
hold on
plot((j), (k), 'b*');
disp(k);
disp(j);
end
end
I feel this is similar to Dijkstra's algorithm. You can denote the intersection points by nodes. Then generate a mesh where each intersecting point is connected to every other intersecting point. Then if there exists a line in the binary image, assign a unit weight, otherwise assign inf i.e. infinite weight. When you have to measure distnace between m-th point and n-th point (say), then make m-th point as source and n-th point as destination and find the shortest path according to Dijkstra's algorithm.

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.

Matlab - Propagate points orthogonally on to the edge of shape boundaries

I have a set of points which I want to propagate on to the edge of shape boundary defined by a binary image. The shape boundary is defined by a 1px wide white edge.
I have the coordinates of these points stored in a 2 row by n column matrix. The shape forms a concave boundary with no holes within itself made of around 2500 points. I have approximately 80 to 150 points that I wish to propagate on the shape boundary.
I want to cast a ray from each point from the set of points in an orthogonal direction and detect at which point it intersects the shape boundary at. The orthogonal direction has already been determined. For the required purposes it is calculated taking the normal of the contour calculated for point, using point-1 and point+1.
What would be the best method to do this?
Are there some sort of ray tracing algorithms that could be used?
Thank you very much in advance for any help!
EDIT: I have tried to make the question much clearer and added a image describing the problem. In the image the grey line represents the shape contour, the red dots the points
I want to propagate and the green line an imaginary orthongally cast ray.
alt text http://img504.imageshack.us/img504/3107/orth.png
ANOTHER EDIT: For clarification I have posted the code used to calculate the normals for each point. Where the xt and yt are vectors storing the coordinates for each point. After calculating the normal value it can be propagated by using the linspace function and the requested length of the orthogonal line.
%#derivaties of contour
dx=[xt(2)-xt(1) (xt(3:end)-xt(1:end-2))/2 xt(end)-xt(end-1)];
dy=[yt(2)-yt(1) (yt(3:end)-yt(1:end-2))/2 yt(end)-yt(end-1)];
%#normals of contourpoints
l=sqrt(dx.^2+dy.^2);
nx = -dy./l;
ny = dx./l;
normals = [nx,ny];
It depends on how many unit vectors you want to test against one shape. If you have one shape and many tests, the easiest thing to do is probably to convert your shape coordinates to polar coordinates which implicitly represent your solution already. This may not be a very effective solution however if you have different shapes and only a few tests for every shape.
Update based on the edited question:
If the rays can start from arbitrary points, not only from the origin, you have to test against all the points. This can be done easily by transforming your shape boundary such that your ray to test starts in the origin in either coordinate direction (positive x in my example code)
% vector of shape boundary points (assumed to be image coordinates, i.e. integers)
shapeBoundary = [xs, ys];
% define the start point and direction you want to test
startPoint = [xsp, ysp];
testVector = unit([xv, yv]);
% now transform the shape boundary
shapeBoundaryTrans(:,1) = shapeBoundary(:,1)-startPoint(1);
shapeBoundaryTrans(:,2) = shapeBoundary(:,2)-startPoint(2);
rotMatrix = [testVector(2), testVector(1); ...
testVector(-1), testVector(2)];
% somewhat strange transformation to keep it vectorized
shapeBoundaryTrans = shapeBoundaryTrans * rotMatrix';
% now the test is easy: find the points close to the positive x-axis
selector = (abs(shapeBoundaryTrans(:,2)) < 0.5) & (shapeBoundaryTrans(:,1) > 0);
shapeBoundaryTrans(:,2) = 1:size(shapeBoundaryTrans, 1)';
shapeBoundaryReduced = shapeBoundaryTrans(selector, :);
if (isempty(shapeBoundaryReduced))
[dummy, idx] = min(shapeBoundaryReduced(:, 1));
collIdx = shapeBoundaryReduced(idx, 2);
% you have a collision with point collIdx of your shapeBoundary
else
% no collision
end
This could be done in a nicer way probably, but you get the idea...
If I understand your problem correctly (project each point onto the closest point of the shape boundary), you can
use sub2ind to convert the "2 row by n column matrix" description to a BW image with white pixels, something like
myimage=zeros(imagesize);
myimage(imagesize, x_coords, y_coords) = 1
use imfill to fill the outside of the boundary
run [D,L] = bwdist(BW) on the resulting image, and just read the answers from L.
Should be fairly straightforward.