Note that there are some explanatory texts on larger screens.

plurals
  1. POOpenCV C++/Obj-C: Detecting a sheet of paper / Square Detection
    text
    copied!<p>I successfully implemented the OpenCV square-detection example in my test application, but now need to filter the output, because it's quiet messy - or is my code wrong?</p> <p>I'm interested in the four corner points of the paper for skew reduction (like <a href="https://stackoverflow.com/questions/7838487/executing-cvwarpperspective-for-a-fake-deskewing-on-a-set-of-cvpoint">that</a>) and further processing …</p> <p><strong>Input &amp; Output:</strong> <a href="https://i.stack.imgur.com/5e2Mv.jpg" rel="noreferrer"><img src="https://i.stack.imgur.com/5e2Mv.jpg" alt="Input &amp; Output"></a></p> <p><strong>Original image:</strong></p> <p><a href="https://i.stack.imgur.com/MIm24.jpg" rel="noreferrer">click</a></p> <p><strong>Code:</strong></p> <pre><code>double angle( cv::Point pt1, cv::Point pt2, cv::Point pt0 ) { double dx1 = pt1.x - pt0.x; double dy1 = pt1.y - pt0.y; double dx2 = pt2.x - pt0.x; double dy2 = pt2.y - pt0.y; return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10); } - (std::vector&lt;std::vector&lt;cv::Point&gt; &gt;)findSquaresInImage:(cv::Mat)_image { std::vector&lt;std::vector&lt;cv::Point&gt; &gt; squares; cv::Mat pyr, timg, gray0(_image.size(), CV_8U), gray; int thresh = 50, N = 11; cv::pyrDown(_image, pyr, cv::Size(_image.cols/2, _image.rows/2)); cv::pyrUp(pyr, timg, _image.size()); std::vector&lt;std::vector&lt;cv::Point&gt; &gt; contours; for( int c = 0; c &lt; 3; c++ ) { int ch[] = {c, 0}; mixChannels(&amp;timg, 1, &amp;gray0, 1, ch, 1); for( int l = 0; l &lt; N; l++ ) { if( l == 0 ) { cv::Canny(gray0, gray, 0, thresh, 5); cv::dilate(gray, gray, cv::Mat(), cv::Point(-1,-1)); } else { gray = gray0 &gt;= (l+1)*255/N; } cv::findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); std::vector&lt;cv::Point&gt; approx; for( size_t i = 0; i &lt; contours.size(); i++ ) { cv::approxPolyDP(cv::Mat(contours[i]), approx, arcLength(cv::Mat(contours[i]), true)*0.02, true); if( approx.size() == 4 &amp;&amp; fabs(contourArea(cv::Mat(approx))) &gt; 1000 &amp;&amp; cv::isContourConvex(cv::Mat(approx))) { double maxCosine = 0; for( int j = 2; j &lt; 5; j++ ) { double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1])); maxCosine = MAX(maxCosine, cosine); } if( maxCosine &lt; 0.3 ) { squares.push_back(approx); } } } } } return squares; } </code></pre> <p><strong><em>EDIT 17/08/2012:</em></strong></p> <p>To draw the detected squares on the image use this code:</p> <pre><code>cv::Mat debugSquares( std::vector&lt;std::vector&lt;cv::Point&gt; &gt; squares, cv::Mat image ) { for ( int i = 0; i&lt; squares.size(); i++ ) { // draw contour cv::drawContours(image, squares, i, cv::Scalar(255,0,0), 1, 8, std::vector&lt;cv::Vec4i&gt;(), 0, cv::Point()); // draw bounding rect cv::Rect rect = boundingRect(cv::Mat(squares[i])); cv::rectangle(image, rect.tl(), rect.br(), cv::Scalar(0,255,0), 2, 8, 0); // draw rotated rect cv::RotatedRect minRect = minAreaRect(cv::Mat(squares[i])); cv::Point2f rect_points[4]; minRect.points( rect_points ); for ( int j = 0; j &lt; 4; j++ ) { cv::line( image, rect_points[j], rect_points[(j+1)%4], cv::Scalar(0,0,255), 1, 8 ); // blue } } return image; } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload