Jump to content
Compvision.ru
Alex_grem

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

Recommended Posts

Можно ли идентифицировать объекты на изображении, имея готовые контуры этих объектов?

Share this post


Link to post
Share on other sites
Можно ли идентифицировать объекты на изображении, имея готовые контуры этих объектов?

Можно, например как здесь: http://www.compvision.ru/forum/index.php?showtopic=6

Share this post


Link to post
Share on other sites

Не могли бы Вы объяснить, что означают слова: "Проект находит контуры и выводит степень их похожести, сравнение идет с первым найденным контуром...". Получается мы находим на картинке контуры объектов, запоминаем их...а с чем сравниваем, с теми же объектами что ли?

Share this post


Link to post
Share on other sites
Не могли бы Вы объяснить, что означают слова "Проект находит контуры и выводит степень их похожести, сравнение идет с первым найденным контуром...". Получается мы находим на картинке контуры объектов, запоминаем их...а с чем сравниваем, с теми же объектами что ли?

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

PS: просто запустите пример, предварительно нарисовав на бумаге разные (и одинаковые) фигуры и многое должно проясниться :)

ЗЫ: вообще то он выводит степень их непохожести (моя опечатка) :) контур, с которым идет сравнение имеет значение 0.

Share this post


Link to post
Share on other sites

Тогда такой вопрос: если мы в какой-то момент сохранили контур для сравнения, то при изменении расстояния до плоскости, в которой находится контур, он не всегда будет обнаруживаться?

Share this post


Link to post
Share on other sites
Тогда такой вопрос: если мы в какой-то момент сохранили контур для сравнения, то при изменении расстояния до плоскости, в которой находится контур, он не всегда будет обнаруживаться?

Обнаружение (выделение из изображения) контура не зависит от алгоритмов сравнения.

Я так понял, что Вы имеете ввиду изменение масштаба контура.

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

Share this post


Link to post
Share on other sites

Скажите, пожалуйста, существуют ли какие-нибудь численные характеристики для отличия геометрии контуров. Т.е. есть ли какая-то численная характеристика, отличающая контур в форме круга от прямоугольного контура или контура в виде овала?

Share this post


Link to post
Share on other sites
Скажите, пожалуйста, существуют ли какие-нибудь численные характеристики для отличия геометрии контуров. Т.е. есть ли какая-то численная характеристика, отличающая контур в форме круга от прямоугольного контура или контура в виде овала?

Есть - моменты, например. Можете посмотреть моменты Ху (Hu invariant или Hu moment).

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites
Попробовал сделать следующее: создал ч/б рисунок 100*100 с окружностью по центру, нашел контур, посчитал инвариантные моменты, затем переместил эту окружность на другую позицию и получил совершенно другие значения инвариантных моментов. Почему?

Рамочку вокруг кадра наверное не удалили, а она там есть :) .

Share this post


Link to post
Share on other sites

я использовал код вашей программы (ContourMatching). в ней вроде вы удалили края вокруг рамки

Share this post


Link to post
Share on other sites
я использовал код вашей программы (ContourMatching). в ней вроде вы удалили края вокруг рамки

Может версия OpenCV другая?

Если кусок кода покажете (с тестовой картинкой), попробую посмотреть поближе.

Share this post


Link to post
Share on other sites

Версия opencv 1.2. Весь код, собственно, Ваша функция.... Все что я добавил, отмечено комментарием

float XC[1000]={0};
float YC[1000]={0};
float S[1000]={0};
double mt=0;
int ID=0;
int NumCont=0;
int NumCont1=0;
CvMemStorage* storage = 0;
CvSeq* contours;
CvSeq* Templ;
CvSeq* result;
storage = cvCreateMemStorage(0);
CvSeq* polygons = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage );
CvMoments moments;
CvHuMoments hu_moments;
//while(1)
//{
cvCvtColor(Grab, gray, CV_BGR2GRAY); // Получаем серый цвет

cvThreshold( gray, gray, 150,255,CV_THRESH_BINARY);

// Необходимо удалить белый бордюр
cvRectangle(gray, cvPoint(0,0), cvPoint(gray->width-1,gray->height-1),CV_RGB(0,0,0));
// Утолщаем контуры
cvDilate( gray, gray, 0, 1 );
// Нах. границы
cvCanny( gray, gray, 50, Val1, 5 );
// Нах. контуры
cvFindContours( gray, storage,&contours,sizeof(CvContour),CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE,cvPoint(0,0))
;
//--------------
if(contours!=0)
{
NumCont=contours->total; // количество найденных контуров
}

int NC=0;
for(;contours!=0;contours = contours->h_next)
{
// Аппр. контуров полигонами
result = cvApproxPoly( contours, sizeof(CvContour), storage,CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.001, 0 );
// Площадь полигона
double area=fabs(cvContourArea(result,CV_WHOLE_SEQ));
// Объявление читалки точек
CvSeqReader reader;
// Инициализация читалки точек
cvStartReadSeq( result, &reader, 0 );
// Две точки
CvPoint pt[2];
if(area>500)
{
// Вычисляем моменты
cvMoments( result, &moments);

// Добавленный код 
cvGetHuMoments(&moments,&hu_moments);

char m = cvWaitKey(33);
if( m == 109)
{
cout<<"Hu1 = "<<hu_moments.hu1<<endl;
cout<<"Hu2 = "<<hu_moments.hu2<<endl;
cout<<"Hu3 = "<<hu_moments.hu3<<endl;
cout<<"Hu4 = "<<hu_moments.hu4<<endl;
cout<<"Hu5 = "<<hu_moments.hu5<<endl;
cout<<"Hu6 = "<<hu_moments.hu6<<endl;
cout<<"Hu7 = "<<hu_moments.hu7<<endl<<endl;
}
// Коней добавленного кода

// Центр тяжести
float xc=(moments.m10/moments.m00);
float yc=(moments.m01/moments.m00);

// Обрубаем клонов
bool ok=1;
for (int o=0;o<NC;o++)
{
if( ((xc-XC[o])*(xc-XC[o])+(yc-YC[o])*(yc-YC[o]))<10 && fabs((area-S[o])/(area+S[o]))<0.3){ok=0;}
}
//
if(ok){

// Запоминаем шаблон
if(NumCont1==0)
{Templ=cvCloneSeq(result);}
// Сравниваем с найденными контурами
mt=cvMatchShapes( Templ, result,CV_CONTOURS_MATCH_I3);

NumCont1++;
double M00=moments.m00;
double M20=moments.m20;
double M02=moments.m02;
double M11=moments.m11;

double A=(M20/M00)-xc*xc;
double B=2*((M11/M00)-xc*yc);
double C=(M02/M00)-yc*yc;

double LL=sqrt( ( (A+C)+sqrt(B*B+(A-C)*(A-C)) )/2)*2;
double LW=sqrt( ( (A+C)-sqrt(B*B+(A-C)*(A-C)) )/2)*2;

// Для вычисления угла нужны центральные моменты инерции
M20=moments.mu20;
M02=moments.mu02;
M11=moments.mu11;

double theta=(atan2(2*M11,(M02-M20))/2)*(180/pi);
// Отмечаем центр
cvCircle( Grab, cvPoint(xc,yc), 3, CV_RGB(0,255,255), -1, 8, 0 );
//string str1 = str(format("%lf") % mt);
_fcvt_s(NumChar, 10, mt, 2, &Decimal, &Sign);
cvPutText( Grab,NumChar, cvPoint(xc,yc),&font, CV_RGB(255,255,0));

// Достаем точки из хранилища точек и рисуем линии
for (int i=0;i<result->total-1;i++)
{
CV_READ_SEQ_ELEM( pt[0], reader );
CV_READ_SEQ_ELEM( pt[1], reader );
if(mt>0.5){cvLine(Grab,pt[0],pt[1],CV_RGB(255,0,0));}
else{cvLine(Grab,pt[0],pt[1],CV_RGB(0,255,0));}
}
}
XC[NC]=xc;
YC[NC]=yc;
S[NC]=area;
NC++;
} // if
} // for
cvPutText( Grab,"NCont1=", cvPoint(20,20),&font, CV_RGB(255,255,0));

результат:
7f481ebeae8e.jpg

Share this post


Link to post
Share on other sites

По моему все нормально, порядок цифр: e-24 до e-7 в пределах ошибки вычисления для подобных алгоритмов с типом переменных double.

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

Share this post


Link to post
Share on other sites

поставлена следующая задача, найти на картинке(очень далека от идеала) определенные объекты.

решал задачу следующим образом:

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

2. задал цикл в котором готовлю картинку для поиска контура ( treshold от 0 до 255)

2.1 внутренний цикл ищет контуры сравнивая их с идеальными

2.2. получаю координаты центра

Из 16 нахожу всего 4-6.

может следует копать в другую сторону? отказаться от cvMatchShapes();

прикреплю картинку, может посоветуете чего?

каким еще методом можно эффективно искать на изображении предметы?

начал читать главу про ML в книге по OpenCV. есть сомнения, это ли мне нужно? или смотреть HMM?

16x.bmp

Share this post


Link to post
Share on other sites

Ну, лица ищутся bosting'ом. Пример работает так себе.

Share this post


Link to post
Share on other sites
поставлена следующая задача, найти на картинке(очень далека от идеала) определенные объекты.

решал задачу следующим образом:

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

2. задал цикл в котором готовлю картинку для поиска контура ( treshold от 0 до 255)

2.1 внутренний цикл ищет контуры сравнивая их с идеальными

2.2. получаю координаты центра

Из 16 нахожу всего 4-6.

а каким образом осуществляется поиск контуров для распознавания? конкретизируйте, вместе посмотрим

Share this post


Link to post
Share on other sites

посмотрел как в примере с камерой, правда не знаю что за последние 2а аргумента cvFindContours

кусок

 

for(int porog=0;porog!=255;++porog){
cvSmooth( Image_1, Image_1, CV_GAUSSIAN, 5, 5, 1, 1 );
cvThreshold( Image_1, Image_1, porog, 100, CV_THRESH_BINARY_INV);
cvCanny( Image_1, Image_1, 50, 100, 5 );
int kolich=cvFindContours( Image_1, storage_img,&img_contour,sizeof(CvContour),CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE,cvPoint(0,
0));


if(kolich)
Find_Cont(&Value_in,&Value_out, img_contour, Image_2);
//и переход в ф-ю, которая сравнивает все img_contour с шаблоном
}

Share this post


Link to post
Share on other sites

посмотрел как в примере с камерой, правда не знаю что за последние 2а аргумента cvFindContours
кусок
for(int porog=0;porog!=255;++porog){
cvSmooth( Image_1, Image_1, CV_GAUSSIAN, 5, 5, 1, 1 );
cvThreshold( Image_1, Image_1, porog, 100, CV_THRESH_BINARY_INV);
cvCanny( Image_1, Image_1, 50, 100, 5 );
int kolich=cvFindContours( Image_1, storage_img,&img_contour,sizeof(CvContour),CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE,cvPoint(0,
0));


if(kolich)
Find_Cont(&Value_in,&Value_out, img_contour, Image_2);
//и переход в ф-ю, которая сравнивает все img_contour с шаблоном
}


По поводу последних двух параметров (method и offset) в руководстве говорится (может где переврал, но немного):

* method –
Метод аппроксимации (для всех режимов, кроме CV_LINK_RUNS, который использует свою, встроенную аппроксимацию)

* CV_CHAIN_CODE - выдает контуры в цепном коде Фримана. Другие методы выдают полигонами (последовательностями вершин)
* CV_CHAIN_APPROX_NONE - полигон со ВСЕМИ точками цепного кода.
* CV_CHAIN_APPROX_SIMPLE - сжимает горизонтальные, вертикальные, и диагональные сегменты и оставляет только их конечные точки.
* CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS - один из вариантов аппроксимирующего алгоритма Teh-Chin (не спрашивайте что это smile.gif ).
* CV_LINK_RUNS - использует абсолютно другой алгоритм извлечения контуров по горизонтальным сегментам единичных точек (насколько я понял, работает по сканлайнам). Используется только с CV_RETR_LIST.

* offset – Смещение, смещает все точки контура на заданное расстояние. Это полезно когда контур извлекается с использованием ROI а анализ производится на полном изображении

Share this post


Link to post
Share on other sites

Использовать cvCanny я думаю не стоит, из-за него только внутренние контуры появляются, да и для работы cvFindContours он совершенно не требуется.

А если картинка плохого качества возможно стоит использовать адаптивный порог

Share this post


Link to post
Share on other sites
Использовать cvCanny я думаю не стоит,

Согласен, он лишний.

> Пример работает так себе.

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

Share this post


Link to post
Share on other sites

Убрал cvCanny стало немного лучше находить.

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

//cvAdaptiveThreshold ( Image_1, Image_1, porog,CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY_INV);

я ищу на картинке 1 объект как сочетание из 4х. найдет 1-3 из 4х кусков - считай не нашло ничего.

а Есть ли способ найти сразу целиком объект? просто контурами по-моему довольно сложно получается.

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

84471.gif

Share this post


Link to post
Share on other sites
Убрал cvCanny стало немного лучше находить.

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

//cvAdaptiveThreshold ( Image_1, Image_1, porog,CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY_INV);

я ищу на картинке 1 объект как сочетание из 4х. найдет 1-3 из 4х кусков - считай не нашло ничего.

а Есть ли способ найти сразу целиком объект? просто контурами по-моему довольно сложно получается.

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

84471.gif

Может попробовать искать отрезки?

http://www.compvision.ru/forum/index.php?showtopic=31

Ведь линии прослеживаются достаточно четко.

Share this post


Link to post
Share on other sites
я ищу на картинке 1 объект как сочетание из 4х. найдет 1-3 из 4х кусков - считай не нашло ничего.

а Есть ли способ найти сразу целиком объект? просто контурами по-моему довольно сложно получается.

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

Пробовал так:

cvFindContours( Image_1, storage_img,&img_contour,sizeof(CvContour),CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE,cvPoint(0,0));

CvSeq* q = cvCreateSeq(4620,sizeof(CvContour),sizeof(CvPoint),storage);

for (contours!=0;contours=contours-h_next)

{

	result = cvApproxPoly(...

	CvSeqPush(q,result);

}

cvMoments(q,&moments)

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

Share this post


Link to post
Share on other sites

Функция может искать моменты не только контуров, но и двоичных изображений:

Вот из хелпа:

void cvMoments(const CvArr* arr, CvMoments* moments, int binary=0)

Calculates all of the moments up to the third order of a polygon or rasterized shape.

Parameters:

* arr – Image (1-channel or 3-channel with COI set) or polygon (CvSeq of points or a vector of points)

* moments – Pointer to returned moment’s state structure

* binary – (For images only) If the flag is non-zero, all of the zero pixel values are treated as zeroes, and all of the others are treated as 1’s

The function cvMoments() calculates spatial and central moments up to the third order and writes them to moments. The moments may then be used then to calculate the gravity center of the shape, its area, main axises and various shape characeteristics including 7 Hu invariants.

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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.

×