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

Работа с контурами

Recommended Posts

Да, если вектор-контур, то не нужно центровать. А по поводу выравнивания, надо-же как-то определять (сопоставить с эталонным) начальные точки контуров.

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


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

boundingRect не хочет принимать вектор:

error C2664: 'cv::boundingRect' : cannot convert parameter 1 from 'std::vector<_Ty>' to 'const cv::Mat &'
Хотя в документации написано, что можно либо Mat либо std::vector Вот код:
void GetContours(Mat &imgBin, vector<vector<Complexf>> vCntrs, CvSize noiseRect, int adjustTo)

{

	vector<vector<Point>> cntrs, newCntrs;


	findContours(imgBin, cntrs, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);


	int s=cntrs.size();

	Rect rct;

	int newSize=0;

	for (int i=0; i<s; i++)

	{


		rct=boundingRect(cntrs[i]);

...

UPD: Обновил 2.1 -> 2.3. Заработало

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


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

что значит вектор контур ? последовательность точек? постоянный ли шаг?

каким методом потом сравниваются контуры?

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


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

что значит вектор контур ? последовательность точек? постоянный ли шаг?

каким методом потом сравниваются контуры?

Чтобы получить следующую точку, нужно к текущей точке прибавить i-й вектор. {(0,1),(1,0),(0,-1),(-1,0)} - квадрат. Потом контуры можно будет скалярно перемножать

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


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

void myPrint(int* v, int vsize);

//ее можно вызвать так

vector <int> v;

v.push_back(2);

v.push_back(3);

myPrint(&v[0], v.size());

возможно там что то такое?

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


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

возможно там что то такое?

Нет, говорю же, что исправил. В 2.1 не было поддержки контуров у этой функции.

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


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

По логике вещей это сумма длин векторов из которой, но в статейке про контурный анализ написана такая формула:

816edc32469540789f10f386210b14a2.png

Что это?

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


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

Это Евклидово расстояние, разве нет?

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


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

Yi - это не координата, а i-ый вектор во всём контуре. Это теорема из дифгема... "Если имеется Y касательная к кривой (контур в нашем случае), то длина кривой вычисляется по этой формуле (если заменить сумму на интеграл)". Вот такие пироги)

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


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

Yi - это не координата, а i-ый вектор во всём контуре. Это теорема из дифгема... "Если имеется Y касательная к кривой (контур в нашем случае), то длина кривой вычисляется по этой формуле (если заменить сумму на интеграл)". Вот такие пироги)

Что-то сомнительно. Судя по формуле, Yn - это вектора, а не касательные. Иначе, что такое модуль касательной в квадрате? Я бы на твоём месте дал ссылку на статью или выложил саму статью, чтобы не гадать, а посмотреть на контекст.

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


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

http://habrahabr.ru/blogs/image_processing/118486/#b1

Если что, то всё работает)

Могу ещё выложить скрин из учебника по дифгему, но думаю в этом нет необходимости)

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


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

Добрый вечер, написал программу находящую контуры, затем сравниваю контуры при помощи функции cvMatchShapes(), (Hu моменты), вроде как они инвариантны к масштабу и развороту, но у меня получается совсем плохие результаты:

При нажатии на клавишу 1 запоминается первый контур, на клавишу 2 второй контур, на клавишу 3 контуры сравниваются:

int levels = 0; 


void trackbar(int pos)

{

	levels++;

}


IplImage *source;

CvCapture *Capture;

CvSeq *etalon = NULL; 

int _tmain(int argc, _TCHAR* argv[])

{

	Capture = cvCaptureFromCAM(2);

	cvNamedWindow("Source",CV_WINDOW_AUTOSIZE);

	cvNamedWindow("Gray",CV_WINDOW_AUTOSIZE);

	CvMoments moments;

	CvHuMoments HuMoments;

	CvSeq *first = NULL;

	CvSeq *second = NULL;

	CvSeq *result = NULL;

	CvSeq* Templ;

	double mt=0;

	int NumCont1=0;

	CvMat mat;

	cvCreateTrackbar( "Gray", "Gray", &levels, 7, trackbar );

	while (true)

	{

		source = cvQueryFrame(Capture);


		IplImage *img_8uc1 = cvCreateImage( cvGetSize(source), IPL_DEPTH_8U, 1 );

		IplImage *img_edge = cvCreateImage(cvGetSize(source),IPL_DEPTH_8U,1);

		IplImage *img_8uc3 = cvCreateImage(cvGetSize(source),IPL_DEPTH_8U,3);

		IplImage *image = cvCreateImage(cvGetSize(source),IPL_DEPTH_8U,3);


		cvCopyImage(source, image);


		cvSmooth(image,image,CV_GAUSSIAN,9,9);

		cvCvtColor(image, img_8uc1, CV_BGR2GRAY);


		//cvThreshold(img_8uc1,img_edge, 128, 255, CV_THRESH_BINARY );

		cvCanny(img_8uc1,img_8uc1,1,900,5);


		//cvDilate(img_edge,img_edge, 0, 1 );

		cvCopyImage(img_8uc1,img_edge);


		CvMemStorage* storage = cvCreateMemStorage();

		CvSeq* first_contour = NULL;


		int Nc = cvFindContours(img_edge,storage,&first_contour,sizeof(CvContour),CV_RETR_LIST);

		int n = 0;


		printf("Total Contours Detected: %d\n", Nc );


		int mm = 0;

		int NC = 0;

		for( CvSeq* c = first_contour; c!=NULL; c=c->h_next ) 

		{

			result = cvApproxPoly(c, sizeof(CvContour), storage,CV_POLY_APPROX_DP, cvContourPerimeter(c)*0.001, 0 );


			cvCvtColor( img_8uc1, img_8uc3, CV_GRAY2BGR );

			if ( (c != NULL) && (mm != 0) )

			{

				/*cvMoments(c,&moments);

				cvGetHuMoments(&moments,&HuMoments);

				std::cout<<"Moments"<<std::endl;

				std::cout<<""<<std::endl;

				std::cout<<HuMoments.hu1<<std::endl;

				std::cout<<HuMoments.hu2<<std::endl;

				std::cout<<HuMoments.hu3<<std::endl;

				std::cout<<HuMoments.hu4<<std::endl;

				std::cout<<HuMoments.hu5<<std::endl;

				std::cout<<HuMoments.hu6<<std::endl;

				std::cout<<HuMoments.hu7<<std::endl;*/



			}

			cvDrawContours( img_8uc3, result, CV_RGB(255,0,0), CV_RGB(0,255,0), levels, 3, CV_AA, cvPoint(0,0) );

			//printf("Contour #%d\n", n );	

			cvShowImage("image", img_8uc3 );

			//printf("%d elements:\n", c->total );

			//if (n > 20)

			{

				//break;

			}

			//for( int i=0; i<c->total; ++i ) 

			{

				//CvPoint* p = CV_GET_SEQ_ELEM( CvPoint, c, i );


				//printf("(%d,%d)\n", p->x, p->y );

			}

			//cvWaitKey(0);

			char ch = cvWaitKey();

			if (ch == 'q')

				{

					etalon = NULL;

					etalon = result;

				}

			if(  ch == '1' )

				{

					std::cout<<"first"<<std::endl;

					first = NULL;

					first = result;

					//std::cout<<c->first->data;

				}

			if(  ch == '2' )

				{

					std::cout<<"second"<<std::endl;

					second = NULL;

					second = result;

				}

			if(  ch == '3' )

				{

					std::cout<<"//-----------------------------------------------//"<<std::endl;

					double result_f_s = cvMatchShapes(first,second,CV_CONTOURS_MATCH_I3);

					std::cout<<result_f_s<<std::endl;

					/*std::cout<<"first";

					std::cout<<first<<std::endl;


					std::cout<<"second";

					std::cout<<second<<std::endl;*/

					//first = NULL;

					//second = NULL;

					std::cout<<"//-----------------------------------------------//"<<std::endl;

				}

			n++;

			mm++;

			if ( (etalon != NULL) && (c != NULL))

				{

					double val = cvMatchShapes(c,etalon->h_next,2,0);

					if ( (val <= 2) && (val >= 0.1) )

						{

							std::cout<<"COOL"<<std::endl;

							std::cout<<val<<std::endl;

							std::cout<<"//--------------------------"<<std::endl;

						}

				}	

		}



		cvShowImage("Source",source);

		cvShowImage("Gray",img_8uc1);


		cvReleaseMemStorage(&storage);

		cvReleaseImage(&img_8uc3);

		cvReleaseImage(&img_edge);

		cvReleaseImage(&image);

		cvReleaseImage(&img_8uc1);



		char c = cvWaitKey(10);

		if(  c == 27 )

			break;



	}

	cvDestroyAllWindows();

	return 0;

}

Вот какие у меня получились результаты:

Буква А с Б = 0.602732

Буква А с В = 2.32621

Буква А с наклоненной А = 2.85677

Буква A с перевернутой А = 0.196188

Подскажите пожалуйста в чем проблема? получается что буквы А и Б похожи, а А и наклоненная А разные?

1.bmp

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


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

Думаю тут проблема в том, что каждая буква содержит по несколько контуров, и какой с каким сравнивается в каждом случае большой вопрос.

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


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

Дело в MatchShapes. Очень плохая функция. Можно использовать только для достаточно больших контуров (буквы отпадают). Сам недавно писал распознавание текста... Сначала мучался с HU моментами, потом понял что к чему и отказался от них полностью. Работал с вектор-контурами (получилось немного по-сложней, но результат того стоил)

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


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

мм... Если не трудно приведите пожалуйста пример, как из последовательности cvSeq перейти к представлению вектор-контура?

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


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

В статье на хабре см пост выше вроде вся процедура описана:

1)Достаем точки из контура (из cvSeq) в этой теме несколько кусков кода где это делается.

2)

Затем, контур обходится (допустим – по часовой стрелке), и каждый вектор смещения записывается комплексным числом a+ib. Где a – смещение точки по оси X, а b – смещение по оси Y. Смещение берется относительно предыдущей точки.

Комплексные числа и операции с ними в C++ поддерживаются (см. файл complex.h).

Не очень понятно с чем возникли проблемы.

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


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

Я просто никогда не работал с комплексными числами. Вы не могли бы привести пример как с ними работать. Тоесть когда сделал обход, получил вектор-контур, как его лучше представлять в виде одномерного массива или в виде указателя, чтобы в дальнейшем с ним работать? или еще как-то? там ведь получаются нужно хранить еще где-то знак т.е. например -1-i...

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


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


Example

//
// complex.cpp
//
#include <complex>
#include <iostream.h>
int main()
{
complex<double> a(1.2, 3.4);
complex<double> b(-9.8, -7.6);
a += b;
a /= sin(B) * cos(a);
b *= log(a) + pow(b, a);
cout << "a = " << a << ", b = " << b << endl;
return 0;
}
[/code]

На выходе :

a = (1.42804e-06,-0.0002873), b = (58.2199,69.7354)

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


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

мм.... оказывается так просто, спасибо большущее! А можно a и b как-то по-другому объявить ведь мы не знаем первоначальную длинну вектора?

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


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

Инициализируйте их нулями, или можно без инициализации complex<double> a; .

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


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

Здравствуйте все.

Каким образом можно объединить несколько последовательностей с контурами в одну?

Объясню вопрос подробнее:

Допустим, есть функция, которая в качестве одного из параметров принимает указатель на результирующую последовательность контуров.

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

Понятно, что при завершении работы функции все последовательности, чьи хранилища были созданы внутри функции, будут разрушены.

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

Заранее спасибо за ответы.

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


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

Просто создайте хранилище как глобальную переменную (можно использовать его как временную переменную для передачи данных).

CvMemStorage *storage = cvCreateMemStorage(0);

Её не обязательно создавать и разрушать каждый раз заново, есть команда для очистки хранилища cvClearMemStorage(storage).

При выходе из программы освобождайте хранилище командой cvReleaseMemStorage(&storage).

По поводу переноса не знаю, я делал бы новую последовательность и заправлял туда точки по одной (в этой теме есть исходник программы которая создает контур).

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


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

Так создайте хранилище как глобальную переменную (можно использовать его как временную переменную для передачи данных).

CvMemStorage *storage = cvCreateMemStorage(0);

Её же не обязательно создавать и разрушать каждый раз заново, есть же функция для очистки хранилища cvClearMemStorage(storage).

При выходе из программы освобождайте cvReleaseMemStorage(&storage).

Все не совсем так :)

Возможно, я не достаточно верно объяснил задачу.

Требуется именно объединить несколько последовательностей в одну.

То есть из


CvSeq* contours0;

CvSeq* contours1;

CvSeq* contours2;

CvSeq* contours3;

Сделать
CvSeq* contoursSummary;
Чье содержимое равно contours0+contours1+contours2+contours3 При этом, создание одного глобального хранилища проблемы не решит. Потому что в случае:

cvFindContours( img_1, storage1, &contours1, sizeof(CvContour), CV_RETR_LIST, CV_LINK_RUNS, cvPoint(0,0) );

cvFindContours( img_2, storage2, &contours2, sizeof(CvContour), CV_RETR_LIST, CV_LINK_RUNS, cvPoint(0,0) );

В последовательности contours1 сохраняются контуры с изображения img_1, а в последовательности contours2 сохраняются контуры с изображения img_2. Но в случае:

cvFindContours( img_1, storage_global, &contours1, sizeof(CvContour), CV_RETR_LIST, CV_LINK_RUNS, cvPoint(0,0) );

cvFindContours( img_2, storage_global, &contours2, sizeof(CvContour), CV_RETR_LIST, CV_LINK_RUNS, cvPoint(0,0) );

Последовательность contours1 разрушается, а контуры остаются только в последовательности contours2, при этом, там хранятся конуры только с изображения img_2

Складывается впечатление, что функция cvFindContours очищает содержимое storage перед использованием.

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

Напрашивается вывод, что нужно создать вне функции глобальные хранилища для всех последовательностей, которые создаются внутри функции. А по завершению работы все их освобождать. Но это какой-то кривой подход, вы не находите? :)

Разве не логичнее передать в функцию указатель на результирующее хранилище (и, естественно, на результирующую последовательность), а внутри самой функции перенести данные из временных хранилищ в основное?

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


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

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

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

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

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

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

Войти

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

Войти сейчас


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

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

×