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:
And it looks like this after corner detection:
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:
- That stamp is violet color, so first thing you should do is color segmentation.
- After you've done with step 1 you can use Houhg transform to detect lines on binary image. Or find all contours in image.
- And the final step is to detect rectangle.
Update:
Here's another solution that should also work in gray images.
- Do a threshold to convert image to 1bit (I used 200 from 255 as threshold).
- Find all contours in new image which have area bigger than some constant (I took 1000).
- 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:
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);
}
}
}
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)
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?
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
来源:https://stackoverflow.com/questions/12158396/how-to-check-if-four-points-form-a-rectangle