mrgloom 242 Жалоба Опубликовано September 19, 2012 вообщем после оператора канни получаю контуры. если брать их как есть, то получается много точек. аппроксимация отрезками не подходит, надо сделать аппроксимацию точками, но чтобы уменьшить их кол-во(хотя возможно это эквивалентно задаче аппроксимации отрезками заданной длины?) написал по простому, но это плохо работает. void WriteDotsToTxt(string filename,vector<vector<Point>>& vec) { ofstream filestr(filename.c_str()); for(int i=0;i<vec.size();++i) { for(int j=0;j<vec[i].size();++j) { filestr<<" ";//? filestr<<vec[i][j].x<<" "<<vec[i][j].y; filestr<<"\n"; } } filestr.close(); } CvScalar random_color(CvRNG* rng) { int color = cvRandInt(rng); return CV_RGB(color&255, (color>>8)&255, (color>>16)&255); } /*IplImage**/void raster_downsample(/*IplImage* img*/) { Mat img= imread("./test_cases/test.tif",0); medianBlur(img,img,5); Canny(img,img,100,200);//параметры Mat dst; cvtColor(img,dst,CV_GRAY2RGB); //dst=0; Mat_<uchar> bgrMat(img); Mat_<Vec3b> dstMat(dst); vector<vector<Point>> paths; //можно и просто как вектор Mat mask;//бинарная маска прошли не прошли img.copyTo(mask); mask=0; Mat_<uchar> maskMat(mask); for(int y=1;y<img.rows-1;++y) for(int x=1;x<img.cols-1;++x) { if(maskMat(y,x)==0) { vector<Point> vec; list<Point> t; if(bgrMat(y,x)>0) { //кладём текущую точку vec.push_back(Point(x,y)); maskMat(y,x)=255; //ищем соседей if(x>0&&y>0&&x<img.cols-1&&y<img.rows-1) { //по идее на каждом этапе мы должны иметь только 1 соседа, иначе это особая точка int c=0; //1 if(bgrMat(y-1,x-1)>0&&maskMat(y-1,x-1)==0&&c==0) { t.push_back(Point(x-1,y-1)); ++c; } //2 if(bgrMat(y-1,x)>0&&maskMat(y-1,x)==0&&c==0) { t.push_back(Point(x,y-1)); ++c; } //3 if(bgrMat(y-1,x+1)>0&&maskMat(y-1,x+1)==0&&c==0) { t.push_back(Point(x+1,y-1)); ++c; } //4 if(bgrMat(y,x-1)>0&&maskMat(y,x-1)==0&&c==0) { t.push_back(Point(x-1,y)); ++c; } //5 if(bgrMat(y,x+1)>0&&maskMat(y,x+1)==0&&c==0) { t.push_back(Point(x+1,y)); ++c; } //6 if(bgrMat(y+1,x-1)>0&&maskMat(y+1,x-1)==0&&c==0) { t.push_back(Point(x-1,y+1)); ++c; } //7 if(bgrMat(y+1,x)>0&&maskMat(y+1,x)==0&&c==0) { t.push_back(Point(x,y+1)); ++c; } //8 if(bgrMat(y+1,x+1)>0&&maskMat(y+1,x+1)==0&&c==0) { t.push_back(Point(x+1,y+1)); ++c; } } //проходим по всем пока не кончатся соседи while(t.size()>0) { Point p=t.front(); int cx= p.x; int cy= p.y; vec.push_back(Point(cx,cy)); maskMat(cy,cx)=255; if(cx>0&&cy>0&&cx<img.cols-1&&cy<img.rows-1) { int c=0; //1 if(bgrMat(cy-1,cx-1)>0&&maskMat(cy-1,cx-1)==0&&c==0) { t.push_back(Point(cx-1,cy-1)); ++c; } //2 if(bgrMat(cy-1,cx)>0&&maskMat(cy-1,cx)==0&&c==0) { t.push_back(Point(cx,cy-1)); ++c; } //3 if(bgrMat(cy-1,cx+1)>0&&maskMat(cy-1,cx+1)==0&&c==0) { t.push_back(Point(cx+1,cy-1)); ++c; } //4 if(bgrMat(cy,cx-1)>0&&maskMat(cy,cx-1)==0&&c==0) { t.push_back(Point(cx-1,cy)); ++c; } //5 if(bgrMat(cy,cx+1)>0&&maskMat(cy,cx+1)==0&&c==0) { t.push_back(Point(cx+1,cy)); ++c; } //6 if(bgrMat(cy+1,cx-1)>0&&maskMat(cy+1,cx-1)==0&&c==0) { t.push_back(Point(cx-1,cy+1)); ++c; } //7 if(bgrMat(cy+1,cx)>0&&maskMat(cy+1,cx)==0&&c==0) { t.push_back(Point(cx,cy+1)); ++c; } //8 if(bgrMat(cy+1,cx+1)>0&&maskMat(cy+1,cx+1)==0&&c==0) { t.push_back(Point(cx+1,cy+1)); ++c; } } t.pop_front(); } paths.push_back(vec); } } } //уменьшаем кол-во сэмлов //тупо убираем точки в каждой цепочке, но т.к. цепочки не прямые получается плохо int k=20; //через каждые k for(int i=0;i<paths.size();++i) { vector<Point> t; for(int j=0;j<paths[i].size();++j) { //кладём конченые точки + те которые попадают по шагу if(j==0||j==paths[i].size()-1||j%k==0) t.push_back(paths[i][j]); } paths[i]=t; t.clear(); } //сделать отрисовку через раскраску рэндомным цветом CvRNG rng(35435345); CvScalar* Colors=new CvScalar[paths.size()]; for (int i=0;i<paths.size();i++) { Colors[i]=random_color(&rng); } //рисуем int p_n=0; for(int i=0;i<paths.size();++i) { for(int j=0;j<paths[i].size();++j) { int x= paths[i][j].x; int y= paths[i][j].y; dstMat(y,x)= Vec3b(Colors[i].val[0],Colors[i].val[1],Colors[i].val[2]); ++p_n; } } delete Colors; cout<<p_n; WriteDotsToTxt("big_raster_10.txt",paths); imwrite("raster_.png",dst); } Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано September 19, 2012 хмм похоже задачу надо ставить по другому, http://www.ziegelmann.org/ziegelmann/Mark%20Ziegelmann-Dateien/Linear%20Curve%20Approximation.htm т.е. есть кривая состоящая из точек, а надо её наилучшим образом сапроксимировать меньшим кол-вом точек. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано September 19, 2012 Может быть свернуть последовательность точек контура гауссианом, а затем посчитать кривизну? Там где радиус кривизны маленький, ничего не трогать, там где большой можно и удалить часть точек. Еще ссылка была уже: http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A0%D0%B0%D0%BC%D0%B5%D1%80%D0%B0-%D0%94%D1%83%D0%B3%D0%BB%D0%B0%D1%81%D0%B0-%D0%9F%D0%B5%D0%BA%D0%B5%D1%80%D0%B0 и http://hal.inria.fr/docs/00/57/94/67/PDF/main.pdf Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано September 19, 2012 http://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm наверно, то что нужно. попробую найти готовую реализацию какую нибудь. но мне кажется, то что выдаёт канни надо еще как то фильтровать. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано September 19, 2012 Так openCV знает этот метод и использует его по умолчанию в функции cvApproxPoly #define CV_POLY_APPROX_DP 0 // Douglas-Peucker algorithm и есть отдельная функция: http://opencv.willowgarage.com/documentation/cpp/structural_analysis_and_shape_descriptors.html#cv-approxpolydp Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано September 19, 2012 нет я всё таки посмотрел на эту картинку и мне кажется, что мне надо не совсем то. ибо там где участок почти прямой, там почти нет точек, т.е. как бы пробел, т.е. алгоритм старается сохранить форму объекта. мне же надо просто уменьшить кол-во семплов и мне кажется, что пробелов не должно быть, т.е. всё таки наверно задачу надо поставить еще и с ограничением на расстояние между сэмплами. и так же получится, что там где углы густота точек будет больше, что тоже непонятно как скажется при регистрации потом 2-х облаков точек. т.е. наверно можно и дугласа пекера использовать, но надо положить огранчиение, что отрезок не может быть больше какой то величины. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано September 19, 2012 Ну это можно просто сделать. Сначала применить этот алгоритм как он есть, а после, пробежать по всем отрезкам и покромсать их на кусочки длины не превышающей заданной. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано September 19, 2012 Ну это можно просто сделать. Сначала применить этот алгоритм как он есть, а после, пробежать по всем отрезкам и покромсать их на кусочки длины не превышающей заданной. ну в общем случае это не получится, ибо если задать большой шаг загрубления можем получить и большие отрезки, которые если просто делить на маленькие, получим результат хуже чем бы сразу аппроксимировали маленькими. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано September 19, 2012 В любом случае, ошибка аппроксимации не превысит заданную, т.к. большой отрезок, на котором лежат маленькие отрезки уже был проверен по этому критерию, и любая точка, лежащая на большом отрезке отстоит не далее чем задано от исходной ломаной. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано September 19, 2012 В любом случае, ошибка аппроксимации не превысит заданную, т.к. большой отрезок, на котором лежат маленькие отрезки уже был проверен по этому критерию, и любая точка, лежащая на большом отрезке отстоит не далее чем задано от исходной ломаной. это то понятно, я говорил, что можно лучше. а вообще такое постепенное убирание точек будет эквивалентно уменьшению масштаба? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано September 19, 2012 Нет, ломаная должна остаться точно такой же. Просто большие отрезки будут разбиты на меньшие куски. Масштаб можно менять умножая длины на масштабный коэффициент. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах