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

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

Recommended Posts

Smorodov    523
Да, спасибо, пример хороший.

Только там двумя строчками выше вот какая конструкция:

cvFindContours( gray, storage,&contours,sizeof(CvContour),CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE,cvPoint(0,0))

;

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

if(contours!=0)

{

NumCont=contours->total; // количество найденных контуров

}

Если я правильно понимаю тип CvSeq, то в NumCont попадает не общее количество найденных контуров, а количество точек в первом контуре (ну, у меня во всяком случае) - я это имел ввиду.

Андрей.

Если честно, не замечал этого, все работало :blink:, но возможно Вы правы (но я, как нибудь проверю ).

----------------------

Проверил правильно так:

int Nc = cvFindContours(************);

Nc-кол-во найденных контуров.

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


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

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

http://willperone.net/Code/spline.php

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


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

По поводу contours->total согласен,это количесвто пикселей в контуре=) просто в мануале написано это это total number of elements,это и вызывает заблуждение=)

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


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

Здравствуйте, коллеги,

Есть такая функция cvMatchTemplate. Она работает, но только если темплейт совпадает по положению с изображением:

match.png

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

Я хочу соорудить аналог cvMatchTemplate, но так, чтобы она была нечувствительна к повороту/масштабу/сдвигу.

Примерно как вот здесь: http://www.lps.usp.br/~hae/software/cirateg/index.html (но там нет исходников)

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

Спасибо,

Андрей.

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


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

Думаю нужно посмотреть в сторону алгоритмов SURF/SIFT, открытые реализации в сети есть, да и в opencv есть функция cvExtractSURF

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


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

cvMatchTemplate срабатывает и при повороте на 10-15 градусов. Я делал несколько копий с поворотом и прогнял их через cvMatchTemplate. Хуже это с размерами.. При этом надо помнить что могут быть несколько попаданий в один обьект :blink:

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


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

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

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


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

Вот тут почитайте статейки, про детектирование прямых:

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

Непосредственно в этом виде вам он не подходит, но если разберетесь с методом, модифицировать под Вашу задачу труда не составит.

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


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

У меня пару вопросов по контурам.

1. Как сохранить контуры в файле после их поиска функцией cvFindContours;

2. Как можно сегментировать контуры.

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


Ссылка на сообщение
Поделиться на других сайтах
Smorodov    523
У меня пару вопросов по контурам.

1. Как сохранить контуры в файле после их поиска функцией cvFindContours;

2. Как можно сегментировать контуры.

Сохранение контура:

CvFileStorage* fs = cvOpenFileStorage( "example.yml", 0, CV_STORAGE_WRITE );

cvWrite( fs, "result", result, cvAttrList(0,0) );

cvReleaseFileStorage( &fs );

Считывание контура:

CvFileStorage* fs = cvOpenFileStorage( "example.yml", 0, CV_STORAGE_READ );

CvFileNode* fn= cvGetFileNodeByName( fs, cvGetRootFileNode(fs), "result" );

result=(CvSeq*)cvRead( fs, fn );

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

// работа с контуром

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

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

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

// освобождение хранилища

cvReleaseFileStorage( &fs );

Что Вы имеете ввиду под сегментацией контура? Разбить на отрезки (точки), или что то другое ?

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


Ссылка на сообщение
Поделиться на других сайтах
anry    0
Что Вы имеете ввиду под сегментацией контура? Разбить на отрезки (точки), или что то другое ?

Извиняюсь, не уточнил. Я имел ввиду сегментацию формы.

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

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


Ссылка на сообщение
Поделиться на других сайтах
Smorodov    523
Извиняюсь, не уточнил. Я имел ввиду сегментацию формы.

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

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

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


Ссылка на сообщение
Поделиться на других сайтах
anry    0
Может лучше сегментировать изображение (при помощи cvFloodfill, например получить маски для каждого цветового пятна) а потом определять контуры? Контуры можно конечно распутать, если они обладают свойством гладкости и не имеют разрывов в производных, но это сложный путь, лучше поработать с изображением до выделения контуров.

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

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


Ссылка на сообщение
Поделиться на других сайтах
Smorodov    523
Дело в том, что объекты имеют один и тот же цвет. Контуры можно отличить друг от друга функцией cvDilate, но при этом теряется их форма и дальше их уже не распознать. Сейчас я пробую этим методом найти объекты, а их идентифицировать с помощью cvMatchTemplate, но он нечувствителен к повороту.

Насколько я знаю, cvMatchTemplate сохраняет работоспособность при углах поворота плюс-минус 15 градусов, можно делать несколько прогонов. Можно, для сокращения области поиска использовать ROI вычисленную по бинаризованному изображению, которое у Вас уже имеется. Можно попробовать (к бинарному изображению) применить функцию cvDistTransform. Тем самым получите центры объектов. А после этого, по максимальному отклику cvMatchTemplate найти и поворот.

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


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

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

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


Ссылка на сообщение
Поделиться на других сайтах
Smorodov    523
А можно ли найти наклон произвольного контура с помощью моментов, если известно, что он имеет вытянутую форму по высоте, и большую площадь в верхней части?

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

Вот кусок кода:

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/M_PI);[/code] где xc и yc ищется так:
[code]float xc=(moments.m10/moments.m00);
float yc=(moments.m01/moments.m00);

PS: квадрант может скакать.

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


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

Спасибо, вроде угол наклона правильно считает. Осталось только проблема, что половина изображений вверх ногами получаются. А в примере LL и LW что за величины?

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


Ссылка на сообщение
Поделиться на других сайтах
Smorodov    523
Спасибо, вроде угол наклона правильно считает. Осталось только проблема, что половина изображений вверх ногами получаются. А в примере LL и LW что за величины?

Зто дины осей эллипса (или полуосей, не помню). Насчет переворота - я про квадрант предупреждал :D. Надо доп. обработку какую-то делать.

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


Ссылка на сообщение
Поделиться на других сайтах
anry    0
Зто дины осей эллипса (или полуосей, не помню). Насчет переворота - я про квадрант предупреждал :D. Надо доп. обработку какую-то делать.

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

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


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

OpenCVReferenceManual.pdf страница 2-15 :D

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


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

здравствуйте! Есть задача: точно и однозначно позиционировать 2 точки на изображении (камера закреплена, а объект перемещается, нужно постоянно знать его относительные координаты). Какой объект лучше всего для этого использовать? В принципе с этой задачей неплохо справляется яркий светодиод, если к камере приложить светофильтр, но все равно периодически появляются лишние точки.

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


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

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

У меня небольшая проблема - создаю контур cvSeq, а потом рисую его с помощью cvDrawContours, но ничего программа не рисует.

Вот код:

int main(int argc, char** argv)
{
IplImage* src;
const char* main_name = "Workspace";
src = cvCreateImage(cvSize( 400, 400), 8, 3);
cvZero(src);
CvScalar color = CV_RGB( 200,0,0);

CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage );
CvSeqWriter writer;
//CvSeqReader reader;
int i;
cvStartAppendToSeq( seq, &writer );

CvPoint pt = cvPoint(20,20);
CV_WRITE_SEQ_ELEM( pt, writer );
printf("[%d,%d] is written\n", pt.x, pt.y );
pt = cvPoint(30,50);
CV_WRITE_SEQ_ELEM( pt, writer );
printf("[%d,%d] is written\n", pt.x, pt.y );
pt = cvPoint(50,60);
CV_WRITE_SEQ_ELEM( pt, writer );
printf("[%d,%d] is written\n", pt.x, pt.y );
pt = cvPoint(45,30);
CV_WRITE_SEQ_ELEM( pt, writer );
printf("[%d,%d] is written\n", pt.x, pt.y );
cvEndWriteSeq( &writer );
for (i = 0;i<4;i++)
{
CvPoint* pts = (CvPoint*) cvGetSeqElem(seq, i);
printf("[%d,%d] is read\n", pts->x, pts->y );
}
cvDrawContours( src, seq, color, color,0,3,8);
cvCircle( src, pt, 8, color,1,8,0);

cvNamedWindow( main_name, 1);
cvShowImage( main_name, src);
cvWaitKey(0);
return 0;
}[/codebox]

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


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

У меня небольшая проблема - создаю контур cvSeq, а потом рисую его с помощью cvDrawContours, но ничего программа не рисует.

Вот код:

int main(int argc, char** argv)
{
IplImage* src;
const char* main_name = "Workspace";
src = cvCreateImage(cvSize( 400, 400), 8, 3);
cvZero(src);
CvScalar color = CV_RGB( 200,0,0);

CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage );
CvSeqWriter writer;
//CvSeqReader reader;
int i;
cvStartAppendToSeq( seq, &writer );

CvPoint pt = cvPoint(20,20);
CV_WRITE_SEQ_ELEM( pt, writer );
printf("[%d,%d] is written\n", pt.x, pt.y );
pt = cvPoint(30,50);
CV_WRITE_SEQ_ELEM( pt, writer );
printf("[%d,%d] is written\n", pt.x, pt.y );
pt = cvPoint(50,60);
CV_WRITE_SEQ_ELEM( pt, writer );
printf("[%d,%d] is written\n", pt.x, pt.y );
pt = cvPoint(45,30);
CV_WRITE_SEQ_ELEM( pt, writer );
printf("[%d,%d] is written\n", pt.x, pt.y );
cvEndWriteSeq( &writer );
for (i = 0;i<4;i++)
{
CvPoint* pts = (CvPoint*) cvGetSeqElem(seq, i);
printf("[%d,%d] is read\n", pts->x, pts->y );
}
cvDrawContours( src, seq, color, color,0,3,8);
cvCircle( src, pt, 8, color,1,8,0);

cvNamedWindow( main_name, 1);
cvShowImage( main_name, src);
cvWaitKey(0);
return 0;
}[/codebox]

На эту тему, можете посмотреть примеры из opencv/samples/c/convexhull.c и squares.c, там правда для записи элементов используется cvSeqPush.

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


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

В squares.c вручную рисуют контур, тут проблем нет - считывается из массива все прекрасно. В convexhull.c тоже ничего не нашел. Проблема в том, что cvDrawContours ничего не рисует, и почему так происходит я понять не могу. Думаю, что проблема со списком CvSeq... Но пока ничего поделать с этим не могу. Может с указателем на первый контур что-то не так?

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


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

я так понял проблема в характеристиках контура. Функция CvMoments с этим контуром вообще пишет ошибку. Не проходит определение

#define CV_IS_SEQ_POLYGON( seq ) \

(CV_IS_SEQ_POLYLINE(seq) && CV_IS_SEQ_CLOSED(seq))

где

#define CV_IS_SEQ_POLYLINE( seq ) \

(CV_SEQ_KIND(seq) == CV_SEQ_KIND_CURVE && CV_IS_SEQ_POINT_SET(seq))

и

#define CV_IS_SEQ_CLOSED( seq ) (((seq)->flags & CV_SEQ_FLAG_CLOSED) != 0)

получается мой контур не полигон) И как его сделать полигоном?

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


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

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

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

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

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

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

Войти

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

Войти сейчас


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

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

×