sagoma: simplify_hull

we now have lines (and many bugs, too)
This commit is contained in:
boyska 2017-01-06 03:47:22 +01:00
parent f7c0a9a62f
commit afa4e67521

138
lines.cpp
View file

@ -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: