瀏覽代碼

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.
boyska 7 年之前
父節點
當前提交
1ac56e85eb
共有 1 個文件被更改,包括 70 次插入26 次删除
  1. 70 26
      lines.cpp

+ 70 - 26
lines.cpp

@@ -7,6 +7,10 @@
 #include <opencv2/core/core.hpp> //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<cv::Point> 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<cv::Point> 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<std::vector<cv::Point>>
 simplify_hull(std::vector<cv::Point> hull) {
 	return simplify_hull( hull, 0 );
@@ -120,6 +124,46 @@ simplify_hull(std::vector<cv::Point> 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<cv::Point> //two points, actually
+find_longest_line(std::vector<cv::Point> hull, unsigned begin, unsigned end) //the hull can be open
+{
+	std::vector<cv::Point> 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<cv::Point> 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<std::vector<cv::Point>> 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;
 }