Jump to content
Compvision.ru
Alex_grem

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

Recommended Posts

Отлично! Я нашел решение проблемы.

При создании sequence надо делать так:

CvSeq* seq = cvCreateSeq( (CV_SEQ_FLAG_CLOSED|CV_SEQ_KIND_CURVE|CV_SEQ_ELTYPE_POINT), sizeof(CvContour), sizeof(CvPoint), storage );

Что делает ее полигоном!

Share this post


Link to post
Share on other sites

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

Как вырезать полученный контур в ROI?

НАШЁЛ ОТВЕТ:

CvRect rect = cvBoundingRect(temp);

cvRectangle(img, cvPoint(rect.x, rect.y), cvPoint(rect.x+rect.width,rect.y+rect.height),CV_RGB(0,255,0), 0);

Edited by anton

Share this post


Link to post
Share on other sites

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

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

Видать проблема в том, что Вы указываете глубину прорисовки равной 0! - попробуйте cvDrawContours( src, seq, color, color,1,3,8); и всё зарисуется!

Share this post


Link to post
Share on other sites

я вот не могу никак понять, зачем вычислять моменты и прочее, если за похожесть контуров отвечает 1 строка: cvMatchShapes, которая и даёт результат?

Share this post


Link to post
Share on other sites

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

Нормально всё в мануале написано :)

Ни про какое "количество пикселей" там не может быть речи, так как у функции поиска контуров есть куча разных методов аппроксимации.

И то что в чьем-то там конкретном случае в контуре оказался именно список пикселей это конечно же классно, но ведь там запросто могла очутиться и запись в цепном коде Фримена, и аппроксимация по Teh-Chin, и сжатые горизонтальные\вертикальные\диагональные доли и т.п.

Так что именно фраза "total number of elements" как нельзя более точно описывает что там на самом деле находится.

А если кто-то хочет позаблуждаться, то он всё равно это сделает, не взирая на то, насколько точно и подробно ему составят мануал :)

Share this post


Link to post
Share on other sites

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

Есть изображение, на нём я нахожу нужные знаки по заранее сохраненному шаблону (образцу контура), по алгоритму Smorodov'а (огромное спасибо за алгоритм!) .

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

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

Сравнение хочу попробовать матричное (т.е. попиксельное).

Пожалуйста, подскажите, как убрать фон.

P.s. степень "похожести" из примера Smorodov'а умножена у меня на 1000, чтобы не выводить дробную часть.

Share this post


Link to post
Share on other sites

Привет всем!

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

хотел использовать поле angle в структуре CvBox2D, но не могу понять как интерпретировать это значение.

в исходниках есть коммент:

/* Angle between the horizontal axis */

/* and the first side (i.e. length) in degrees */

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

буду благодарен за помощь!!!

Share this post


Link to post
Share on other sites

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

Есть изображение, на нём я нахожу нужные знаки по заранее сохраненному шаблону (образцу контура), по алгоритму Smorodov'а (огромное спасибо за алгоритм!) .

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

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

Сравнение хочу попробовать матричное (т.е. попиксельное).

Пожалуйста, подскажите, как убрать фон.

P.s. степень "похожести" из примера Smorodov'а умножена у меня на 1000, чтобы не выводить дробную часть.

Здесь нужно использовать маску. Рисуем контур (можно все подходящие контуры) (с заливкой) на изображении маски, а затем объединяем с исходным изображением по "И".

Share this post


Link to post
Share on other sites

Привет всем!

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

хотел использовать поле angle в структуре CvBox2D, но не могу понять как интерпретировать это значение.

в исходниках есть коммент:

/* Angle between the horizontal axis */

/* and the first side (i.e. length) in degrees */

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

для это изображения:

угол: -80

ширина: 190

высота: 78

а для этого:

угол: -10

ширина: 78

высота: 190

буду благодарен за помощь!!!

На первой странице топика есть код и там такой кусок:

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);[/code]

theta - это угол наклона главной (большей) оси.

Share this post


Link to post
Share on other sites

Smorodov, большое спасибо!

Вот что у меня вышло:


#include "stdio.h"

#include "cv.h"

#include "highgui.h"


CvArr* temp;

CvSeq* contours = 0; 

CvMemStorage* storage = cvCreateMemStorage(0);


CvSeq* result;

CvSeq* polygons = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage );


int main()

{

	IplImage* img1 = 0;

	IplImage* gray = 0;

	IplImage* black = 0;

	IplImage* end = 0;

	IplImage* cann = 0;

	cvNamedWindow("RGB", 1);

	cvNamedWindow("Gray", 1);

	cvNamedWindow("Black", 1);

	cvNamedWindow("End", 1);


	char name0[] = "image2.jpeg";

	img1 = cvLoadImage(name0, 1);

	gray = cvCreateImage( cvSize(img1->width, img1->height), 8, 1);

	black = cvCreateImage( cvSize(img1->width, img1->height), 8, 1);

	end = cvCreateImage( cvSize(img1->width, img1->height), 8, 1);

	cann = cvCreateImage( cvSize(img1->width, img1->height), 8, 1);

	// делаем маску, заливаем изображение чёрным

	cvFillImage(black, 0);


	// переводим основное изображение в серый

  	cvCvtColor( img1, gray, CV_BGR2GRAY);

	// применяем пороговое преобразование

	cvThreshold( gray, cann, 120, 255, CV_THRESH_BINARY );

	// удаляем наружный контур

 	cvRectangle( cann, cvPoint(0,0), cvPoint( cann->width-1, cann->height-1), CV_RGB(0,0,0));

	// утолщаем границы

	cvDilate( cann, cann, 0, 1 );

	// выделяем контура

	cvCanny( cann, cann, 50, 150, 5 );

	// находим контура

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

	// рисуем найденный контур НА маске и заливаем его белым (атрибут CV_FILLED)

	cvDrawContours( black, contours, CV_RGB(255,255,255),CV_RGB(255,255,255), 0, CV_FILLED, CV_AA, cvPoint(0,0));

	// сравниваем логическим "и",

	cvAnd(gray, black, end);

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

	cvDrawContours( gray, contours, CV_RGB(255,0,0),CV_RGB(0,255,0), 2, 1, CV_AA, cvPoint(0,0));	


	cvShowImage("RGB", img1);

	cvShowImage("Gray", gray);

	cvShowImage("Black", black);

	cvShowImage("End", end);


		char c = cvWaitKey();


	cvDestroyWindow( "RGB" );

	cvDestroyWindow( "Gray" );

    cvDestroyWindow( "Black" );

	cvDestroyWindow( "End" );

	cvReleaseImage(&img1);


  return 0;

}

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

Собственно, именно это мне и нужно было. Теперь буду думать как сравнить знак с эталоном.

Share this post


Link to post
Share on other sites

Smorodov, спасибо что откликнулись!

а у меня новая проблема :(

есть изображение:

нужно получить контур этой микросхемы

так как некоторые лапки не связаны с остальными, то я нахожу все контуры, добавляю их точки в одну последовательность, а потом нахожу ConvexHull, таким образом получаю один контур вокруг всех лапок => и вокруг микросхемы, НО... на этом изображении в правом верхнем углу есть блик.

в бинарном виде она выглядит так:

post-1-0-73161700-1301772265_thumb.jpg

этот блик (а в общем любой шум за пределами нужного мне контура) так же расценивается как объект и естественно его точки добавляются в общий контур и все не правильно :(

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

Share this post


Link to post
Share on other sites

Если микросхема всегда выровнена, то можно попробовать находить суммы по столбцам и строкам. Максимумы этих сумм покажут габариты микросхемы. см. функцию cvReduce (описание)

Пример использования функции : http://www.compvision.ru/wiki/%D0%9F%D1%80%D0%BE%D0%B5%D0%BA%D1%86%D0%B8%D0%B8_%D0%B8%D0%B7%D0%BE%D0%B1%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F_%D0%BB%D0%B8%D1%86%D0%B0

Share this post


Link to post
Share on other sites

Если микросхема всегда выровнена, то можно попробовать находить суммы по столбцам и строкам. Максимумы этих сумм покажут габариты микросхемы. см. функцию cvReduce (описание)

Пример использования функции : http://www.compvision.ru/wiki/%D0%9F%D1%80%D0%BE%D0%B5%D0%BA%D1%86%D0%B8%D0%B8_%D0%B8%D0%B7%D0%BE%D0%B1%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F_%D0%BB%D0%B8%D1%86%D0%B0

спасибо, посмотрю, но микросхема может быть смещена от центра и быть под углом к горизонтали, мне-то как раз и нужно определить это смещение и угол :(

Share this post


Link to post
Share on other sites

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

Эффекта слияния ножек в одну линию можно достичь так-же парой функций cvDilate+cvErode, а затем искать квадраты или линии.

post-1-0-50863400-1301772107_thumb.png

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites

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

а можно поподробнее? что значит

прогнать через стандартный пример squares

Эффекта слияния ножек в одну линию можно достичь так-же парой функций cvDilate+cvErode, а затем искать квадраты или линии.

хм, cvDilate пробовал, а вот про последующий cvErode не подумал, спасибо...

Share this post


Link to post
Share on other sites

В директории opencv2.2/Bin/ (у меня) лежит пример squares.exe он открывает картинки pic1.png - pic6.png и ищет на них прямоугольники (или квадраты). См. картинку выше.

Исходник squares лежит в директории c:\OpenCV-2.2.0\samples\cpp\

Share this post


Link to post
Share on other sites

В директории opencv2.2/Bin/ (у меня) лежит пример squares.exe он открывает картинки pic1.png - pic6.png и ищет на них прямоугольники (или квадраты). См. картинку выше.

Исходник squares лежит в директории c:\OpenCV-2.2.0\samples\cpp\

ага, нашел, спасибо, буду изучать...

Share this post


Link to post
Share on other sites

Здравствуйте! У меня не получается выцепить последовательность координат, по которым строится внутренний контур объекта при использовании cvFindContours. Посоветуйте что-нибудь.

Share this post


Link to post
Share on other sites

Выкладывай свой код, поможем конечно.

Share this post


Link to post
Share on other sites

Здравствуйте! Возник вопрос - как можно проверить находится ли точка внутри контура или нет ? контур нахожу при помощи cvFindContours. Т.е. мне известны координаты точек, по которым строится контур, и есть еще набор точек. мне нужны только те, что внутри контура.

Share this post


Link to post
Share on other sites

Если точек для проверки много, то можно поступить следующим образом: закрасить лежащую снаружи контура область изображения одним цветом, нарисовать контур другим, а внутренность контура - третьим. И просто брать значение пикселя по координатам точек. То есть:

1. Создать одноканальное изображение размеров с исходное, закрасить его нулями (cvSet).

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

3. Нарисовать контур цветом, скажем, 128.

4. В точке bounding_rect.x + 1 и bounding_rect.y + 1 вызвать функцию cvFloodFill с белым цветом.

5. Для каждой интересующей точки проверить значение пикселя.

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

  • Like 1

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

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.

×