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

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

Recommended Posts

Еще есть функция: cvPointPolygonTest

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


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

Спасибо большое! Работает все замечательно

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


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

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

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


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

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

SA-CVGIP.PDF

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


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

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

Меня очень заинтересовал этот алгоритм с 1-й страницы этой темы.

Скопировал листинг с сообщения от Alex_grem, запустил проект, а не тут-то было (выдает пару ошибок).

Дело в том, что я новичок в OpenCV и хоть прибей не понимаю что именно тут не правильно.

Товарищи форумчане, посмотрите пожалуйста что не так.

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

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


#include "stdafx.h"

#include <cv.h>

#include <highgui.h>


int main(int argc, char* argv[])

{

   	int Val=100,Val1=100; // Значение переменной (для разных нужд)

        float edge_thresh=100;

	#define WIDTHBYTES(bits) ((((bits) + 31) / 32) * 4)

	CvFont font; // Описатель шрифта

	cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX,0.5,0.5,0,1,8);	// Инициализация шрифта (теперь можем вывести какой-нибудь текст)



	IplImage* frame = cvLoadImage("123.jpg", 0);	//исходное изображение

        IplImage* frame_copy = cvCloneImage(frame);			

        IplImage* gray = cvCloneImage(frame);		


	frame_copy = cvCreateImage( cvSize(frame->width,frame->height),IPL_DEPTH_8U, frame->nChannels );

	gray = cvCreateImage(cvSize(frame->width,frame->height), IPL_DEPTH_8U, 1);



//////////////////////////////////////////////Основная функция///////////////////////////////////////////////////////////////

float pi=3.1415;

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(frame, 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);

[color="#FF0000"]cvGetHuMoments(&moments,&hu_moments);


char m = cvWaitKey(33);

        if( m == 109) 

			{

printf("Hu1 = ", hu_moments.hu1,"\n");                

printf("Hu2 = ", hu_moments.hu2,"\n");                

printf("Hu3 = ", hu_moments.hu3,"\n");                

printf("Hu4 = ", hu_moments.hu4,"\n");                

printf("Hu5 = ", hu_moments.hu5,"\n");                

printf("Hu6 = ", hu_moments.hu6,"\n");                

printf("Hu7 = ", hu_moments.hu7,"\n");                


// Центр тяжести

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( frame, 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( frame,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(frame,pt[0],pt[1],CV_RGB(255,0,0));}

else{cvLine(frame,pt[0],pt[1],CV_RGB(0,255,0));}

}

          }

XC[NC]=xc;

YC[NC]=yc;

S[NC]=area;

NC++;

 } // if

} // for

cvPutText( frame,"NCont1=", cvPoint(20,20),&font, CV_RGB(255,255,0));

//--------------------------------------------------------------------------------------------------------------------------//



cvShowImage("original",frame);		//отображаем исходное изобр.


      while(1)

        {

         if (cvWaitKey(33) > 0) break;

        }


        cvReleaseImage(&frame);

        cvReleaseImage(&frame_copy);

        cvReleaseImage(&gray);

        cvDestroyAllWindows();

        return 0;

}

post-4351-0-48078900-1308135122_thumb.jp

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


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

Текст ошибок-то имеется ?

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


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

Текст ошибок-то имеется ?

Осталось немного ошибок, вот текст:

1>------ Построение начато: проект: CircleDetection, Конфигурация: Debug Win32 ------

1>Компиляция...

1>CircleDetection.cpp

1>d:\visual c++ projects\circledetection.cpp(24) : warning C4305: инициализация: усечение из 'double' к 'float'

1>d:\visual c++ projects\circledetection.cpp(92) : warning C4244: инициализация: преобразование 'double' в 'float', возможна потеря данных

1>d:\visual c++ projects\circledetection.cpp(93) : warning C4244: инициализация: преобразование 'double' в 'float', возможна потеря данных

1>d:\visual c++ projects\circledetection.cpp(130) : warning C4244: аргумент: преобразование 'float' в 'int', возможна потеря данных

1>d:\visual c++ projects\circledetection.cpp(130) : warning C4244: аргумент: преобразование 'float' в 'int', возможна потеря данных

1>d:\visual c++ projects\circledetection.cpp(132) : warning C4244: аргумент: преобразование 'float' в 'int', возможна потеря данных

1>d:\visual c++ projects\circledetection.cpp(132) : warning C4244: аргумент: преобразование 'float' в 'int', возможна потеря данных

1>d:\visual c++ projects\circledetection.cpp(145) : warning C4244: =: преобразование 'double' в 'float', возможна потеря данных

1>d:\visual c++ projects\circledetection.cpp(166) : fatal error C1075: конец файла обнаружен ранее, чем левая фигурная скобка '{' в "d:\visual c++ projects\circledetection.cpp(42)"

1>Журнал построения был сохранен в "file://d:\Visual C++ Projects\Debug\BuildLog.htm"

1>CircleDetection - ошибок 1, предупреждений 8

Было 34 ошибки, все поисправлял, осталась одна. Просто у меня сложности с переводом с БИЛДЕРА на СТУДИЮ, т.к. с БИЛДЕРОМ не работал никогда.

Со скобками явно запутался, а распутаться не могу.

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


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

Выдели в студии весь текст и нажми Ctrl+K+F. Весь код отформатируется, сразу увидишь недостающую скобку.

  • Like 1

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


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

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

вот фрагмент кода:


Mat img= imread("C:/images/1.jpg",CV_LOAD_IMAGE_GRAYSCALE);

Canny(img,tsImg,20,100);

vector<vector<Point>> v;

findContours(tsImg,v,CV_RETR_LIST,CV_CHAIN_APPROX_NONE,Point(0,0));

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


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

возможно как то сравнивать контуры помимо Ху моментов?

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


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

Тут обязательно твой exe в отладке должен быть собран с отладочными dll из OpenCV и использовать динамические отладочные CRT.

В релизе exe должен быть собран с релизными dll из OpenCV и использовать динамические релизные CRT.

Ну и твой exe и OpenCV должны быть собранными компилятором одной версии.

Если какое-нибудь из этих условий не соблюдается, то С++ API из OpenCV использовать тебе нельзя.

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


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

Еще неплохо бы проверить грузит-ли изображение. imshow сразу после загрузки что нибудь показывает?

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


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

Есть хорошая книжка по этому поводу "Введение в контурный анализ" Фурман А.Я.

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


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

изображение грузится canny тоже отрабатывается и можно тоже вывести изображение всё ок ошибка как я понял наверное тут findContours(tsImg,v,CV_RETR_LIST,CV_CHAIN_APPROX_NONE,Point(0,0)); при её выполнении вылетает Нарушение прав доступа при чтении

Тут обязательно твой exe в отладке должен быть собран с отладочными dll из OpenCV и использовать динамические отладочные CRT.

В релизе exe должен быть собран с релизными dll из OpenCV и использовать динамические релизные CRT.

Ну и твой exe и OpenCV должны быть собранными компилятором одной версии.

а как это проверить. У меня 2008 студия openCV 2.2 проект собирается ну как написано на страничке opencv добавляю дополнительные зависимости в компоновщик-->Ввод это в свойствах проекта

C:\OpenCV2.2\lib\opencv_core220d.lib

C:\OpenCV2.2\lib\opencv_highgui220d.lib

C:\OpenCV2.2\lib\opencv_video220d.lib

C:\OpenCV2.2\lib\opencv_ml220d.lib

C:\OpenCV2.2\lib\opencv_legacy220d.lib

C:\OpenCV2.2\lib\opencv_imgproc220d.lib

и

затем сервис-> параметры-> каталоги

C:\OpenCV2.2\include

C:\OpenCV2.2\include\opencv

включаемые файлы

C:\OpenCV2.2\lib

файлы библиотек

ну и с самого начала надо ещё debug на release поменять

может я не то написал я не так давно пишу на с++ поэтому извиняюсь)

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


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

Кусочек кода из примеров:


Mat img;
vector<Vec4i> hierarchy;
//show the faces
namedWindow( "image", 1 );
imshow( "image", img );
//Extract the contours so that
vector<vector<Point> > contours0;
findContours( img, contours0, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
[/code]

Попробуйте его подставить.

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


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

попробовал подставить, но что-то тоже не пошло.. даже не с компилировалось...

Ошибка 15 general error c101008d: Failed to write the updated manifest to the resource of file

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


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

Проверить легко: напиши поиск контуров не через С++ API, а через C-функции. Или попробуй вызвать любую другую функцию из OpenCV, принимающую агрументом std::vector

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


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

попробую поискать потом книгу.

нашел вот обзор методов http://ipg.zesoi.fer.hr/papers/pr98.pdf

я так понимаю что в OpenCV ничего кроме моментов Ху нету?

вот еще через фурье дескрипторы

http://read.pudn.com/downloads142/sourcecode/graph/texture_mapping/618021/FourierDescriptor/FourierDescriptor.cpp__.htm

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


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

Есть ещё hierarchical matching: cvCreateContourTree + cvContourFromContourTree + cvMatchContourTrees.

  • Like 1

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


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

Много интересного google выдает на "hierarchical matching".

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


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

написал поиск контуров через С-функции


    IplImage* src = cvLoadImage( "C:/images/1_1.jpg", CV_LOAD_IMAGE_GRAYSCALE );

    IplImage* src1= cvCreateImage( cvGetSize(src), 8, 1 );


    CvMemStorage* storage = cvCreateMemStorage(0);

    CvSeq* contour = 0;


    cvThreshold(src,src1,110,255,CV_THRESH_BINARY);

    cvNamedWindow( "Source", 1 );

    cvShowImage( "Source", src1 );


    cvFindContours( src1, storage, &contour, sizeof(CvContour),

       CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );

вроде бы всё замечательно всё работает ну в отличии от С++, но вот что странно, картинку которую я использую для теста я прикрепил к сообщению у меня получаются 10-ть точек контура.. и они расположены практически в одном месте вот вывод точек контура

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

{

	CvPoint* p = (CvPoint*)cvGetSeqElem ( contour, i );

	int x = p->x;

	int y = p->y;

	circle(ts1,Point(x,y),5,Scalar(100,100,100));	

}

post-2515-0-78831600-1310480125_thumb.jp

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


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

Здесь смотрели? ,Имею ввиду процедуру доставания точек через итератор.

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

PS: cvDrawContours еще посмотрите.

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


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

вроде бы всё замечательно всё работает ну в отличии от С++, но вот что странно, картинку которую я использую для теста я прикрепил к сообщению у меня получаются 10-ть точек контура.. и они расположены практически в одном месте

вот вывод точек контура

Раз работает, то первоначальная проблема: разные рантаймы OpenCV и твоего приложения (то есть CRT - C run time).

И ты ведь нашёл только один контур - найди и выведи все, должно быть всё нормально..

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


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

Я почитал ветку форума Работа с контурами

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


// Объявление читалки точек

CvSeqReader reader;

// Инициализация читалки точек

cvStartReadSeq( contour, &reader, 0 );

// Две точки

CvPoint pt[2];


for( int i=0; i<contour->total-1; i++ )

{

	CV_READ_SEQ_ELEM( pt[0], reader );

	CV_READ_SEQ_ELEM( pt[1], reader );

	cvLine(img12,pt[0],pt[1],CV_RGB(255,0,0),4);

}

но контур по этим точкам выводится совсем уж странный

post-2515-0-52989000-1310542645_thumb.jp

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


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

Контуры могут представляться по-разному. Если ты хочешь получить все точки контура, то используй флаг CV_CHAIN_APPROX_NONE. В книге "Learning OpenCV" про каждое представление написано подробней.

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


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

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

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

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

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

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

Войти

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

Войти сейчас


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

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

×