Tutorial: Detection / recognition of multiple rectangles and extracting with OpenCV
This tutorial will be focused on being able to take a picture and extract the rectangles in the image that are above a certain size:
I am using OpenCV 2.4.2 on Microsoft Visual Express 2008 but it should work with other version as well.
Thanks to: opencv-code.com for their helpful guides
Step 1: Clean up
//Apply blur to smooth edges and use adapative thresholding cv::Size size(3,3); cv::GaussianBlur(img,img,size,0); adaptiveThreshold(img, img,255,CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY,75,10); cv::bitwise_not(img, img);
Step 2: Hough Line detection
vector<Vec4i> lines; HoughLinesP(img, lines, 1, CV_PI/180, 80, 100, 10);
Step 3: Use connected components to determine what they shapes are
cv::Point2f computeIntersect(cv::Vec4i a, cv::Vec4i b) { int x1 = a[0], y1 = a[1], x2 = a[2], y2 = a[3]; int x3 = b[0], y3 = b[1], x4 = b[2], y4 = b[3]; if (float d = ((float)(x1-x2) * (y3-y4)) - ((y1-y2) * (x3-x4))) { cv::Point2f pt; pt.x = ((x1*y2 - y1*x2) * (x3-x4) - (x1-x2) * (x3*y4 - y3*x4)) / d; pt.y = ((x1*y2 - y1*x2) * (y3-y4) - (y1-y2) * (x3*y4 - y3*x4)) / d; //-10 is a threshold, the POI can be off by at most 10 pixels if(pt.x<min(x1,x2)-10||pt.x>max(x1,x2)+10||pt.y<min(y1,y2)-10||pt.y>max(y1,y2)+10){ return Point2f(-1,-1); } if(pt.x<min(x3,x4)-10||pt.x>max(x3,x4)+10||pt.y<min(y3,y4)-10||pt.y>max(y3,y4)+10){ return Point2f(-1,-1); } return pt; } else return cv::Point2f(-1, -1); }
int* poly = new int[lines.size()]; for(int i=0;i<lines.size();i++)poly[i] = - 1; int curPoly = 0; vector<vector<cv::Point2f> > corners; for (int i = 0; i < lines.size(); i++) { for (int j = i+1; j < lines.size(); j++) { cv::Point2f pt = computeIntersect(lines[i], lines[j]); if (pt.x >= 0 && pt.y >= 0&&pt.x<img2.size().width&&pt.y<img2.size().height){ if(poly[i]==-1&&poly[j] == -1){ vector<Point2f> v; v.push_back(pt); corners.push_back(v); poly[i] = curPoly; poly[j] = curPoly; curPoly++; continue; } if(poly[i]==-1&&poly[j]>=0){ corners[poly[j]].push_back(pt); poly[i] = poly[j]; continue; } if(poly[i]>=0&&poly[j]==-1){ corners[poly[i]].push_back(pt); poly[j] = poly[i]; continue; } if(poly[i]>=0&&poly[j]>=0){ if(poly[i]==poly[j]){ corners[poly[i]].push_back(pt); continue; } for(int k=0;k<corners[poly[j]].size();k++){ corners[poly[i]].push_back(corners[poly[j]][k]); } corners[poly[j]].clear(); poly[j] = poly[i]; continue; } } } }
Step 4: Find corners of the polygon
bool comparator(Point2f a,Point2f b){ return a.x<b.x; } void sortCorners(std::vector<cv::Point2f>& corners, cv::Point2f center) { std::vector<cv::Point2f> top, bot; for (int i = 0; i < corners.size(); i++) { if (corners[i].y < center.y) top.push_back(corners[i]); else bot.push_back(corners[i]); } sort(top.begin(),top.end(),comparator); sort(bot.begin(),bot.end(),comparator); cv::Point2f tl = top[0]; cv::Point2f tr = top[top.size()-1]; cv::Point2f bl = bot[0]; cv::Point2f br = bot[bot.size()-1]; corners.clear(); corners.push_back(tl); corners.push_back(tr); corners.push_back(br); corners.push_back(bl); }
for(int i=0;i<corners.size();i++){ cv::Point2f center(0,0); if(corners[i].size()<4)continue; for(int j=0;j<corners[i].size();j++){ center += corners[i][j]; } center *= (1. / corners[i].size()); sortCorners(corners[i], center); }
Step 5: Extraction
for(int i=0;i<corners.size();i++){ if(corners[i].size()<4)continue; Rect r = boundingRect(corners[i]); if(r.area()<50000)continue; cout<<r.area()<<endl; // Define the destination image cv::Mat quad = cv::Mat::zeros(r.height, r.width, CV_8UC3); // Corners of the destination image std::vector<cv::Point2f> quad_pts; quad_pts.push_back(cv::Point2f(0, 0)); quad_pts.push_back(cv::Point2f(quad.cols, 0)); quad_pts.push_back(cv::Point2f(quad.cols, quad.rows)); quad_pts.push_back(cv::Point2f(0, quad.rows)); // Get transformation matrix cv::Mat transmtx = cv::getPerspectiveTransform(corners[i], quad_pts); // Apply perspective transformation cv::warpPerspective(img3, quad, transmtx, quad.size()); stringstream ss; ss<<i<<".jpg"; imshow(ss.str(), quad); }
Leave a Reply