From 1ac56e85eb38e6a3b2f44695449391051952d910 Mon Sep 17 00:00:00 2001 From: boyska Date: Sat, 7 Jan 2017 01:32:49 +0100 Subject: [PATCH] find vertical lines we are considering only the "external" part of the hull so that the processing is faster and the longest line is the vertical one. --- lines.cpp | 96 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 26 deletions(-) diff --git a/lines.cpp b/lines.cpp index 717ea9f..1921e73 100644 --- a/lines.cpp +++ b/lines.cpp @@ -7,6 +7,10 @@ #include //Any Opencv2 code #endif #include"lines.h" +using namespace cv; + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) // all those colors are still visible on b/w (the first component is not so low) auto WHITE = cv::Scalar(255,255,255); @@ -76,15 +80,15 @@ bool similar_fit(cv::Point a, cv::Point b, cv::Point newpoint, float tolerance_d } return false; } -/* TODO: bool similar_fit(std::vector group, cv::Point newpoint) { - * TODO: such a prototype is better because it can do a fit on the group - * instead of just taking the two sides - */ +bool similar_fit(std::vector group, cv::Point newpoint) { + // TODO: it should perform a fit instead of just taking first and last + assert(group.size()>=2); + return similar_fit(group[0], group[group.size()-1], newpoint); +} /* simplify_hull will group all the points of the hull in groups that fit * each group is a "line" */ - std::vector> simplify_hull(std::vector hull) { return simplify_hull( hull, 0 ); @@ -120,6 +124,46 @@ simplify_hull(std::vector hull, double mindistance) { return pointgroups; } +/* find_longest_line: similar to simplify_hull, except it just returns the longest line. + * you must not expect to find the whole line in the returned vector + * just use the first and last point in it + * arg hull: the whole convex hull + * arg begin: index of the array to start from + * arg end: index of the array to end. It can be lower than start, in which case + * the hull is used "circularly" + */ +std::vector //two points, actually +find_longest_line(std::vector hull, unsigned begin, unsigned end) //the hull can be open +{ + std::vector bestline, thisline; + int bestdistance = 0; + thisline.push_back(hull[begin++]); + thisline.push_back(hull[(begin++)%hull.size()]); + for(unsigned i=begin; i!=end; i++) + { + if(unlikely(i==hull.size())) + i=0; + if(similar_fit(thisline, hull[i])) { + thisline.push_back(hull[i]); + } else { // considering if the just-finished line is the best + if(dist(thisline[0],thisline[thisline.size()-1])>bestdistance) { + bestline = thisline; + bestdistance = dist(thisline[0],thisline[thisline.size()-1]); + } + thisline.clear(); + assert(bestline.size()>=2); + thisline.push_back(hull[(i-1)%hull.size()]); + thisline.push_back(hull[i]); + }; + } + if(bestline.size()==0) { // this is the case only when the first line is the best line + assert(0==bestdistance); + bestline = thisline; + } + assert(bestline.size()>=2); + return bestline; +} + int main(int argc, char *argv[]) { char const *fname = "files/masckera.png"; @@ -162,42 +206,40 @@ int main(int argc, char *argv[]) std::vector hull; cv::convexHull(cv::Mat(contour),hull,false); + //these are the "horizontal" lines int *maxdistances = max2_distance(hull); #ifdef _DEBUG //img = cv::imread(fname,CV_LOAD_IMAGE_COLOR); // uncomment to this to display image with colors - std::cout << "Maxdist1: " << hull[maxdistances[0]] << hull[(maxdistances[0]+1)%hull.size()] << std::endl; - std::cout << "Maxdist2: " << hull[maxdistances[1]] << hull[(maxdistances[1]+1)%hull.size()] << std::endl; - cv::circle(img,hull[maxdistances[0]],dotwidth,WHITE,-1); - cv::circle(img,hull[(maxdistances[0]+1)%hull.size()],dotwidth,WHITE,-1); - cv::circle(img,hull[maxdistances[1]],dotwidth>>1,WHITE,-1); - cv::circle(img,hull[(maxdistances[1]+1)%hull.size()],dotwidth>>1,WHITE,-1); - // cv::namedWindow("win", CV_GUI_NORMAL); + std::cout << "Maxdist1:" << maxdistances[0] << " " << hull[maxdistances[0]] << hull[(maxdistances[0]+1)%hull.size()] << std::endl; + std::cout << "Maxdist2:" << maxdistances[1] << " " << hull[maxdistances[1]] << hull[(maxdistances[1]+1)%hull.size()] << std::endl; + cv::circle(img,hull[maxdistances[0]],dotwidth>>2,BROWN,2); + cv::circle(img,hull[(maxdistances[0]+1)%hull.size()],dotwidth>>2,BROWN,2); + cv::circle(img,hull[maxdistances[1]],dotwidth>>2,BROWN,2); + cv::circle(img,hull[(maxdistances[1]+1)%hull.size()],dotwidth>>2,BROWN,2); + cv::namedWindow("win", CV_GUI_NORMAL); // cv::imshow("4 corners",img); // cv::waitKey(0); #endif - auto simplifiedHull = simplify_hull(hull, dist( - hull[maxdistances[0]], - hull[(maxdistances[0]+1)%hull.size()]) / 5 - ); + std::vector> verticals; + verticals.push_back(find_longest_line(hull, (maxdistances[0]+1)%hull.size(), maxdistances[1])); + verticals.push_back(find_longest_line(hull, (maxdistances[1]+1)%hull.size(), maxdistances[0])); #ifdef _DEBUG //img = cv::imread(fname,CV_LOAD_IMAGE_COLOR); // uncomment to this to display image with colors auto color = MAGENTA; - for( auto group: simplifiedHull ) + for( auto line: verticals ) { - color = (color==BLUE) ? MAGENTA : BLUE; //flip color at every group - cv::Point p1 = group[0]; - cv::Point p2 = group[group.size()-1]; - cv::line(img, p1, p2, color, dotwidth>>2); - std::cout << "simplified line: "; - for(cv::Point p: group) + color = (color==BLUE) ? MAGENTA : BLUE; //flip color for the two lines + cv::Point p1 = line[0]; + cv::Point p2 = line[line.size()-1]; + cv::line(img, p1, p2, color, dotwidth>>4); + std::cout << "vertical: " << line[0] << line[line.size()-1] << std::endl; + for(cv::Point p: line) { - cv::circle(img,p,dotwidth>>2,color,dotwidth>>3); - std::cout << "(" << p.x << "," << p.y << ") "; + cv::circle(img,p,dotwidth>>3,color,-1); } - std::cout << ";" << std::endl; } cv::imshow("win",img); while(1) @@ -207,6 +249,8 @@ int main(int argc, char *argv[]) } #endif + + return EXIT_SUCCESS; }