OpenCV C ++ - detecting a rectangle that has the wrong side

enter image description here

Hi .. I have a problem with finding a rectangle, which has the wrong side (not straight), as in the figure above, using the houghline method, you can actually detect lines on a rectangle with some configuration of parameters. After calculating the intersection and getting 4 angles, I can rotate it to its normal position.

But if I change the image to another rectangular rectangle (of a different size and still have the wrong side), I need to reconfigure the parameters. This is due to the fact that the line was not detected on four sides, in addition, it can be more than 4.

is there any other method besides simpler (not requiring reconfiguration / complex configuration)?

+5
source share
3 answers

This method consists in calculating a rotating rectangle that contains all the pixels of the rectangle.

Maybe you can combine this with vasanth's answer, so you can first approach the polynomial to get a regular border, and then cut the rotated rectangle with cv::minAreaRect

Here is my code:

 int main() { cv::Mat input = cv::imread("../inputData/RotatedRect.png"); // convert to grayscale (you could load as grayscale instead) cv::Mat gray; cv::cvtColor(input,gray, CV_BGR2GRAY); // compute mask (you could use a simple threshold if the image is always as good as the one you provided) cv::Mat mask; cv::threshold(gray, mask, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU); // find contours (if always so easy to segment as your image, you could just add the black/rect pixels to a vector) std::vector<std::vector<cv::Point>> contours; std::vector<cv::Vec4i> hierarchy; cv::findContours(mask,contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); /// Draw contours and find biggest contour (if there are other contours in the image, we assume the biggest one is the desired rect) // drawing here is only for demonstration! int biggestContourIdx = -1; float biggestContourArea = 0; cv::Mat drawing = cv::Mat::zeros( mask.size(), CV_8UC3 ); for( int i = 0; i< contours.size(); i++ ) { cv::Scalar color = cv::Scalar(0, 100, 0); drawContours( drawing, contours, i, color, 1, 8, hierarchy, 0, cv::Point() ); float ctArea= cv::contourArea(contours[i]); if(ctArea > biggestContourArea) { biggestContourArea = ctArea; biggestContourIdx = i; } } // if no contour found if(biggestContourIdx < 0) { std::cout << "no contour found" << std::endl; return 1; } // compute the rotated bounding rect of the biggest contour! (this is the part that does what you want/need) cv::RotatedRect boundingBox = cv::minAreaRect(contours[biggestContourIdx]); // one thing to remark: this will compute the OUTER boundary box, so maybe you have to erode/dilate if you want something between the ragged lines // draw the rotated rect cv::Point2f corners[4]; boundingBox.points(corners); cv::line(drawing, corners[0], corners[1], cv::Scalar(255,255,255)); cv::line(drawing, corners[1], corners[2], cv::Scalar(255,255,255)); cv::line(drawing, corners[2], corners[3], cv::Scalar(255,255,255)); cv::line(drawing, corners[3], corners[0], cv::Scalar(255,255,255)); // display cv::imshow("input", input); cv::imshow("drawing", drawing); cv::waitKey(0); cv::imwrite("rotatedRect.png",drawing); return 0; } 

giving this result:

enter image description here

+5
source

Try it:

1. Enter findCountours on the image.

2. Apply approximately PolyDP to bring the contour closer to a rectangular box. The sides of the outline will be much more regular.

3. Segment the rectangular shapes using moments and / or geometry.

+5
source

Using elementary geometry, you need to find the coordinate where

  • The location of the black pixels with the smallest x coordinate
  • The location of the black pixels with the largest x coordinate
  • The location of the black pixel with the smallest y coordinate
  • The location of the black pixel with the largest y coordinate

These 4 points will be the edges of your rectangle.

+4
source

All Articles