Перейти к содержимому
Compvision.ru
mrgloom

point downsampling

Recommended Posts

вообщем после оператора канни получаю контуры.

если брать их как есть, то получается много точек.

аппроксимация отрезками не подходит, надо сделать аппроксимацию точками, но чтобы уменьшить их кол-во(хотя возможно это эквивалентно задаче аппроксимации отрезками заданной длины?)

написал по простому, но это плохо работает.

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

}

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

хмм похоже задачу надо ставить по другому,

http://www.ziegelmann.org/ziegelmann/Mark%20Ziegelmann-Dateien/Linear%20Curve%20Approximation.htm

т.е. есть кривая состоящая из точек, а надо её наилучшим образом сапроксимировать меньшим кол-вом точек.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Может быть свернуть последовательность точек контура гауссианом, а затем посчитать кривизну?

Там где радиус кривизны маленький, ничего не трогать, там где большой можно и удалить часть точек.

Еще ссылка была уже: 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

http://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm

наверно, то что нужно. попробую найти готовую реализацию какую нибудь.

но мне кажется, то что выдаёт канни надо еще как то фильтровать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Так 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

нет я всё таки посмотрел на эту картинку

corsica200_s.gif

и мне кажется, что мне надо не совсем то.

ибо там где участок почти прямой, там почти нет точек, т.е. как бы пробел, т.е. алгоритм старается сохранить форму объекта.

мне же надо просто уменьшить кол-во семплов и мне кажется, что пробелов не должно быть, т.е. всё таки наверно задачу надо поставить еще и с ограничением на расстояние между сэмплами.

и так же получится, что там где углы густота точек будет больше, что тоже непонятно как скажется при регистрации потом 2-х облаков точек.

т.е. наверно можно и дугласа пекера использовать, но надо положить огранчиение, что отрезок не может быть больше какой то величины.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Ну это можно просто сделать.

Сначала применить этот алгоритм как он есть, а после, пробежать по всем отрезкам и покромсать их на кусочки длины не превышающей заданной.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Ну это можно просто сделать.

Сначала применить этот алгоритм как он есть, а после, пробежать по всем отрезкам и покромсать их на кусочки длины не превышающей заданной.

ну в общем случае это не получится, ибо если задать большой шаг загрубления можем получить и большие отрезки, которые если просто делить на маленькие, получим результат хуже чем бы сразу аппроксимировали маленькими.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

В любом случае, ошибка аппроксимации не превысит заданную, т.к. большой отрезок, на котором лежат маленькие отрезки уже был проверен по этому критерию, и любая точка, лежащая на большом отрезке отстоит не далее чем задано от исходной ломаной.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В любом случае, ошибка аппроксимации не превысит заданную, т.к. большой отрезок, на котором лежат маленькие отрезки уже был проверен по этому критерию, и любая точка, лежащая на большом отрезке отстоит не далее чем задано от исходной ломаной.

это то понятно, я говорил, что можно лучше.

а вообще такое постепенное убирание точек будет эквивалентно уменьшению масштаба?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Нет, ломаная должна остаться точно такой же. Просто большие отрезки будут разбиты на меньшие куски.

Масштаб можно менять умножая длины на масштабный коэффициент.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×