sagoma: simplify_hull
we now have lines (and many bugs, too)
This commit is contained in:
parent
f7c0a9a62f
commit
afa4e67521
1 changed files with 124 additions and 14 deletions
138
lines.cpp
138
lines.cpp
|
@ -1,21 +1,36 @@
|
|||
#include<cmath>
|
||||
#include<algorithm>
|
||||
#include<opencv2/opencv.hpp>
|
||||
#include"lines.h"
|
||||
|
||||
// all those colors are still visible on b/w (the first component is not so low)
|
||||
auto WHITE = cv::Scalar(255,255,255);
|
||||
auto BLUE = cv::Scalar(200,10,10);
|
||||
auto BLUE = cv::Scalar(200,50,50);
|
||||
auto MAGENTA = cv::Scalar(110,10,200);
|
||||
auto BROWN = cv::Scalar(90,100,60);
|
||||
|
||||
double dist(cv::Point a, cv::Point b)
|
||||
{
|
||||
return sqrt((double)pow(a.x-b.x,2)+pow(a.y-b.y,2));
|
||||
}
|
||||
// takes the two points that are more distant from the next, ie:
|
||||
// i st distance(hull[i], hull[i+1]) is maximum and 2nd maximum
|
||||
int* max2_distance(std::vector<cv::Point> hull)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Hull = ";
|
||||
for(auto p: hull) {
|
||||
std::cout << p << " ";
|
||||
}
|
||||
#endif
|
||||
std::cout << std::endl;
|
||||
int *idx = (int*) calloc(2, sizeof(int));
|
||||
int distance[2];
|
||||
double distance[2] = {0};
|
||||
for( unsigned i=0; hull.size()>i; i++ )
|
||||
{
|
||||
cv::Point thispoint=hull[i];
|
||||
cv::Point nextpoint=hull[(i+1)%hull.size()];
|
||||
int d=pow(thispoint.x-nextpoint.x,2)+pow(thispoint.y-nextpoint.y,2);
|
||||
int d=dist(thispoint,nextpoint);
|
||||
if( d>distance[0] ) //the biggest till now
|
||||
{
|
||||
idx[1]=idx[0];
|
||||
|
@ -33,6 +48,67 @@ int* max2_distance(std::vector<cv::Point> hull)
|
|||
return idx;
|
||||
}
|
||||
|
||||
|
||||
/* check if a,b,newpoint belong to the same line (with minor approximation) */
|
||||
bool similar_fit(cv::Point a, cv::Point b, cv::Point newpoint) {
|
||||
if( newpoint.x==b.x && newpoint.y==b.y )
|
||||
return true;
|
||||
if( a.x==b.x || b.x==newpoint.x )
|
||||
return a.x==b.x && b.x==newpoint.x; // TODO: this is just too harsh, there is no tolerance!
|
||||
|
||||
double coeff1 = ((double)a.y-b.y) / (a.x-b.x);
|
||||
double coeff2 = ((double)b.y-newpoint.y) / (b.x-newpoint.x);
|
||||
|
||||
if( abs(std::max(coeff1,coeff2)/std::min(coeff1,coeff2)) < 2 ) {
|
||||
std::cout << "No fit " << b << newpoint << " " << coeff1 << " " << coeff2 << std::endl;
|
||||
return true;
|
||||
}
|
||||
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
|
||||
*/
|
||||
|
||||
/* 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 );
|
||||
}
|
||||
std::vector<std::vector<cv::Point>>
|
||||
simplify_hull(std::vector<cv::Point> hull, double mindistance) {
|
||||
//each element is a group of point; a group of point is a vector of points that were
|
||||
//contigous and that "fit together"
|
||||
std::vector<std::vector<cv::Point>> pointgroups;
|
||||
std::vector<cv::Point> *group = new std::vector<cv::Point>();
|
||||
cv::Point last, current;
|
||||
group->push_back(hull[0]);
|
||||
group->push_back(hull[1]);
|
||||
for( unsigned i=2; hull.size()>i; i++ )
|
||||
{
|
||||
current = hull[i];
|
||||
last = (*group)[group->size()-1];
|
||||
if( similar_fit((*group)[0], last, hull[i]) )
|
||||
{
|
||||
group->push_back( hull[i] );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( dist((*group)[0],last)>=mindistance )
|
||||
pointgroups.push_back(*group);
|
||||
group = new std::vector<cv::Point>();
|
||||
group->push_back(last);
|
||||
group->push_back(hull[i]);
|
||||
}
|
||||
}
|
||||
pointgroups.push_back(*group);
|
||||
//TODO: first and last might just be the same
|
||||
return pointgroups;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char const *fname = "files/masckera.png";
|
||||
|
@ -53,7 +129,9 @@ int main(int argc, char *argv[])
|
|||
std::vector<cv::Vec4i> hierarchy;
|
||||
cv::findContours(img,contours,hierarchy,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE);
|
||||
|
||||
cv::drawContours(img,contours,-1,cv::Scalar(255,255,255),5);
|
||||
unsigned short dotwidth = img.cols >> 6; // divide by 64, so efficient
|
||||
//img = cv::imread(fname,CV_LOAD_IMAGE_COLOR); // uncomment to this to display image with colors
|
||||
cv::drawContours(img,contours,-1,BROWN,dotwidth>>4);
|
||||
|
||||
if( 0==contours.size() ) {
|
||||
std::cerr << "No contours found" << std::endl;
|
||||
|
@ -75,18 +153,50 @@ int main(int argc, char *argv[])
|
|||
|
||||
int *maxdistances = max2_distance(hull);
|
||||
|
||||
#ifdef _DEBUG
|
||||
//img = cv::imread(fname,CV_LOAD_IMAGE_COLOR); // uncomment to this to display image with colors
|
||||
unsigned short dotwidth = img.cols >> 6; // divide by 64, so efficient
|
||||
cv::circle(img,hull[maxdistances[0]],dotwidth,MAGENTA,-1);
|
||||
cv::circle(img,hull[(maxdistances[0]+1)%hull.size()],dotwidth,MAGENTA,-1);
|
||||
cv::circle(img,hull[maxdistances[1]],dotwidth>>1,BLUE,-1);
|
||||
cv::circle(img,hull[(maxdistances[1]+1)%hull.size()],dotwidth>>1,BLUE,-1);
|
||||
|
||||
cv::namedWindow("4 corners",CV_WINDOW_NORMAL);
|
||||
cv::imshow("4 corners",img);
|
||||
cv::waitKey(0);
|
||||
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);
|
||||
// cv::imshow("4 corners",img);
|
||||
// cv::waitKey(0);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
auto simplifiedHull = simplify_hull(hull, dist(
|
||||
hull[maxdistances[0]],
|
||||
hull[(maxdistances[0]+1)%hull.size()]) / 5
|
||||
);
|
||||
|
||||
#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 )
|
||||
{
|
||||
color = (color==BLUE) ? MAGENTA : BLUE; //flip color at every group
|
||||
cv::Point p1 = group[0];
|
||||
cv::Point p2 = group[group.size()-1];
|
||||
cv::arrowedLine(img, p1, p2, color, dotwidth>>2);
|
||||
std::cout << "simplified line: ";
|
||||
for(cv::Point p: group)
|
||||
{
|
||||
cv::circle(img,p,dotwidth>>2,color,dotwidth>>3);
|
||||
std::cout << "(" << p.x << "," << p.y << ") ";
|
||||
}
|
||||
std::cout << ";" << std::endl;
|
||||
}
|
||||
cv::imshow("win",img);
|
||||
while(1)
|
||||
{
|
||||
if( cv::waitKey(0) == 113 )
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
// vim: set noet ts=4 sw=4:
|
||||
|
|
Loading…
Reference in a new issue