Hi.. I have problem with rectangle detection which has irregular side (not straight) like figure above. actually with method houghline can detect lines on the rectangle with some parameter configuration. After compute intersect and get 4 corner, I can rotate it to normal position.
But if I change the image with another rectangle (different size and still has irregular side), I need to reconfigure the parameters again. This is because the line is not detected on four sides, beside that the line can be more than 4.
is there any other method beside houghline which is more simple (does not require reconfiguration / difficult configuration)?
Try this:
1.Run findCountours on the image.
2.Apply approxPolyDP to approximate the contour to a rectangle. The contour sides will be a lot more regular.
3.Segment the rectangular contours using moments and/or geometry.
This way is to compute the rotated rectangle that holds all your rectangle pixels.
Maybe you can combine that with vasanth's answer, so you can first approximate the polynome to get a regular border and afterwards extract the rotated rectangle with cv::minAreaRect
Here's 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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With