How to check if four points form a rectangle

4.8k views Asked by At

I am working on a shape recognition app. At this moment a set of points (x,y) is determined by corner detector (red points, img. 2.). Four of these points (in red frames, img. 2.) are vertices of a rectangle (sometimes a little deformed rectangle). What would be the best way to find them among others?

Here is an example of an input image: Input image

And it looks like this after corner detection:

Image with detected corners

4

There are 4 answers

13
ArtemStorozhuk On BEST ANSWER

This is not an answer to your question - it's just suggestion.

In my opinion corner detector is a bad way to detect rectangles - it will take much time to calculate all point distances as mathematician1975 suggested. You have to use another technique in this situation:

  1. That stamp is violet color, so first thing you should do is color segmentation.
  2. After you've done with step 1 you can use Houhg transform to detect lines on binary image. Or find all contours in image.
  3. And the final step is to detect rectangle.

Update:

Here's another solution that should also work in gray images.

  1. Do a threshold to convert image to 1bit (I used 200 from 255 as threshold).
  2. Find all contours in new image which have area bigger than some constant (I took 1000).
  3. Find bounding rectangle for each contour and do a check:

ContourArea / BoundingReactangleArea > constant

I take this constant as 0.9.

And this algorithm gave me next result: enter image description here

Here's OpenCV code:

Mat src = imread("input.jpg"), gray, result;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;

result = Mat(src.size(), CV_8UC1);

cvtColor(src, src, CV_BGR2GRAY);
threshold(src, gray, 200, 255, THRESH_BINARY_INV);
findContours(gray, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

result = Scalar::all(0);
for (size_t i=0; i<contours.size(); i++)
{
    Rect rect = boundingRect(contours[i]);
    if (rect.area() > 1000)
    {
        double area = contourArea(contours[i]);
        if (area/rect.area() > 0.9)
        {
            drawContours(result, contours, i, Scalar(255), -1);
        }
    }
}
5
mathematician1975 On

Calculate the set of 6 lengths that you will have between each pair of 4 distinct points. Within that set of 6 lengths if there are more than 3 distinct values, you do not have a rectangle (2 equal side lengths plus equal diagonal lengths)

0
user1630095 On

Consider you should have got number 8 but you got number 7, then you are going to add number 1 (called delta or error correction) to correct it.

In a similar manner have a delta rectangle coordinates to correct the rectangle. Check that point(coordinate) falls inside delta rectangle.

The rectangle coordinates are as mentioned below:

x+delta,y+delta
x-delta,y+delta
x+delta,y-delta
x-delta,y-delta

Let me know if this works fine for you or if you find a better solution

2
Rody Oldenhuis On

You are aware that by visually inspecting the point cloud you can already distinguish a multitude of rectangles? In other words, you will likely find many rectangles if you don't do a sort of pre-selection routine...

Anyway, aside from the method already given by @mathematician1975, you can also just check if the sides are (more or less) parallel.

Let's call @mathematician1975's method method 1 and parallel-check method 2. Then:

%# method 1: 
n1 = |u1-u2|    %#  3 sub., 3 mult, 2 add. per distance
n2 = |u3-u2|    %#  total of 6 distances to compute.
n3 = |u4-u3|    %#  then max 5+4+3+2+1 = 15 comp. to find unique distances
n4 = |u1-u4|    
n5 = |u4-u2|    %#  Total:
n6 = |u3-u1|    %#  12 sub., 18 mult., 12 add, 15 comp



%# method 2:
w1 = u1-u2       %#  3 subtractions per vector
w2 = u3-u2       %#  total of 4 vectors to compute 
w3 = u3-u2
w4 = u1-u4                
                        %#  12 sub.
abs(w1-w3) == [0 0 0]   %#  3 sub., 3 comp., 1 sign.
abs(w2-w4) == [0 0 0]   %#  3 sub., 3 comp., 1 sign.

                        %# Total: 18 sub., 6 comp. 2 sign.

Note that these are both worst-case; with a bit of bookkeeping you can drastically reduce the cost of both.

Note also that method 2 needs to know beforehand that the vertices are already in the right order. If this is not the case, it'll increase the cost by a factor of 4, which is more that method 1..

May I ask how you are computing the distances?