Преглед изворни кода

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;
 }