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

Определение прямоугольной рамки

Recommended Posts

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

Я знаю точно, что эту задачу можно решить с помощью OpenCV, я уже начал с ней разбираться. Но хотелось бы узнать в каком направлении нужно работать, что бы это сделать и подходит ли представленный рисунок для этого? До этого положение центров цветных прямоугольников я находил по их центрам масс, но при этом не учитывал вероятности принодлежности точек к ним. Для очень контрастных изображений результат был довольно хороший, а вот для фотографий всё сложнее.

Примерный вид рамки:

i-60.jpg

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


Ссылка на сообщение
Поделиться на других сайтах
Недавно столкнулся с такой задачей, поиск прямоугольной рамки на фотографии. Что важно это определить её углы и узнать какой это именно угол. Рамка может быть так же затемнена и на неё можно смотреть под разными углами, т.е. на некоторых изображениях она может выглядеть как ромб.

Я знаю точно, что эту задачу можно решить с помощью OpenCV, я уже начал с ней разбираться. Но хотелось бы узнать в каком направлении нужно работать, что бы это сделать и подходит ли представленный рисунок для этого? До этого положение центров цветных прямоугольников я находил по их центрам масс, но при этом не учитывал вероятности принодлежности точек к ним. Для очень контрастных изображений результат был довольно хороший, а вот для фотографий всё сложнее.

Примерный вид рамки:

i-60.jpg

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

Вообще, насчет ориентации, можно поискать по слову Homography или Homography transform, для начала в руководстве по OpenCV.

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

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


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

Спасибо за ответ. Всё попробую, может получится. Вот просматривал примеры, которые устанавливаются в месте с OpeCV, и наткнулся на пример демонстрирующий работу SURF Speeded Up Robust Features алгоритма (название примера find_obj). Этот алгоритм очень хорошо работает, вот только не уверен можно ли его использовать для работы с камерой. Если всё таки можно то рамки могут выглядеть так. Кстати он определяет и перевернутые объекты.

1.

i-61.jpg

2.

i-62.jpg

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


Ссылка на сообщение
Поделиться на других сайтах
Спасибо за ответ. Всё попробую, может получится. Вот просматривал примеры, которые устанавливаются в месте с OpeCV, и наткнулся на пример демонстрирующий работу SURF Speeded Up Robust Features алгоритма (название примера find_obj). Этот алгоритм очень хорошо работает, вот только не уверен можно ли его использовать для работы с камерой. Если всё таки можно то рамки могут выглядеть так. Кстати он определяет и перевернутые объекты.

1.

i-61.jpg

2.

i-62.jpg

Все примеры могут работать с камерой (некоторые после незначительной переделки), главное там функция обработки изображения, а как Вы его получили дело Ваше. Кстати, по моему на основе этого примера и была сделана программка из этой темы http://www.compvision.ru/forum/index.php?showtopic=11

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


Ссылка на сообщение
Поделиться на других сайтах
Кстати, по моему на основе этого примера и была сделана программка из этой темы http://www.compvision.ru/forum/index.php?showtopic=11

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

Если вы не против я буду писать сюда небольшие отчеты о продвижении.

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


Ссылка на сообщение
Поделиться на других сайтах
Если вы не против я буду писать сюда небольшие отчеты о продвижении.

Думаю всем это будет интересно.

Для скорости надо поставить IPP, если еще не установлены, с ними заметно быстрее работает. У меня кадров 15-20 дает на Athlon64x2 5000 (вэбка примерно 350х280 пикселей). На Вашей же картинке (вэбкой с экрана) все отлично. Кстати, в каком разрешении работаете? Может после считывания изображения уменьшать его, до разумных размеров?

IPP существенно (в разы) ускоряющая работу OpenCV хреновина берется с сайта Intel.

Ставим интелловский компилятор Intel C Plus Plus Compiler v10.1.025

Google рулит.

IPP ставится после установки компилятора. И использует его лицензию smile.gif

Подключается автоматически, нужно только указать в системной переменной Path путь к директории, /bin библиотеки IPP, в самой программе ничего отдельно указывать не нужно.

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


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

У меня обычная камера, подключаемая к компьютеру через DV. Её разрешение 720 на 576, довольно большое. Я уменьшил его в два раза до 360 на 288, производительность выросла примерно до того уровня что и у вас 15-20 фпс.

Насчёт IPP я не могу понять, он бесплатный или нет? На сайте Интела я нашел вот это http://software.intel.com/en-us/intel-ipp это оно?

Если не трудно, дайте прямую ссылку.

Спасибо.

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


Ссылка на сообщение
Поделиться на других сайтах
У меня обычная камера, подключаемая к компьютеру через DV. Её разрешение 720 на 576, довольно большое. Я уменьшил его в два раза до 360 на 288, производительность выросла примерно до того уровня что и у вас 15-20 фпс.

Насчёт IPP я не могу понять, он бесплатный или нет? На сайте Интела я нашел вот это http://software.intel.com/en-us/intel-ipp это оно?

Если не трудно, дайте прямую ссылку.

Спасибо.

Для линукс, насколько я знаю бесплатный, а для windows платный.

Качается отсюда раздел "Performance Libraries" : http://software.intel.com/en-us/articles/i...luation-center/

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


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

Недавно меня спросили о коде получившейся программы. Я вот и подумал, что он может пригодиться еще кому то, и хотя эта программа всего лишь переделанный пример из OpenCV архива, под работу с видео. Я ничего не менял касающегося SURF алгоритма, только добавил работу с видео. Программа написана для MV С++.

image.bmp - имя файла картинки, которая обводится рамкой.

#include <cv.h>

#include <highgui.h>

#include <ctype.h>

#include <stdio.h>

#include <stdlib.h>


#include <iostream>

#include <vector>


#define ZOOM 2


using namespace std;


IplImage *image = 0;


double compareSURFDescriptors( const float* d1, const float* d2, double best, int length )

{

	double total_cost = 0;

	assert( length % 4 == 0 );

	for( int i = 0; i < length; i += 4 )

	{

		double t0 = d1[i] - d2[i];

		double t1 = d1[i+1] - d2[i+1];

		double t2 = d1[i+2] - d2[i+2];

		double t3 = d1[i+3] - d2[i+3];

		total_cost += t0*t0 + t1*t1 + t2*t2 + t3*t3;

		if( total_cost > best )

			break;

	}

	return total_cost;

}


int naiveNearestNeighbor( const float* vec, int laplacian,

					  const CvSeq* model_keypoints,

					  const CvSeq* model_descriptors )

{

	int length = (int)(model_descriptors->elem_size/sizeof(float));

	int i, neighbor = -1;

	double d, dist1 = 1e6, dist2 = 1e6;

	CvSeqReader reader, kreader;

	cvStartReadSeq( model_keypoints, &kreader, 0 );

	cvStartReadSeq( model_descriptors, &reader, 0 );


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

	{

		const CvSURFPoint* kp = (const CvSURFPoint*)kreader.ptr;

		const float* mvec = (const float*)reader.ptr;

		CV_NEXT_SEQ_ELEM( kreader.seq->elem_size, kreader );

		CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );

		if( laplacian != kp->laplacian )

			continue;

		d = compareSURFDescriptors( vec, mvec, dist2, length );

		if( d < dist1 )

		{

			dist2 = dist1;

			dist1 = d;

			neighbor = i;

		}

		else if ( d < dist2 )

			dist2 = d;

	}

	if ( dist1 < 0.6*dist2 )

		return neighbor;

	return -1;

}


void findPairs( const CvSeq* objectKeypoints, const CvSeq* objectDescriptors,

		   const CvSeq* imageKeypoints, const CvSeq* imageDescriptors, vector<int>& ptpairs )

{

	int i;

	CvSeqReader reader, kreader;

	cvStartReadSeq( objectKeypoints, &kreader );

	cvStartReadSeq( objectDescriptors, &reader );

	ptpairs.clear();


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

	{

		const CvSURFPoint* kp = (const CvSURFPoint*)kreader.ptr;

		const float* descriptor = (const float*)reader.ptr;

		CV_NEXT_SEQ_ELEM( kreader.seq->elem_size, kreader );

		CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );

		int nearest_neighbor = naiveNearestNeighbor( descriptor, kp->laplacian, imageKeypoints, imageDescriptors );

		if( nearest_neighbor >= 0 )

		{

			ptpairs.push_back(i);

			ptpairs.push_back(nearest_neighbor);

		}

	}

}


/* a rough implementation for object location */

int locatePlanarObject( const CvSeq* objectKeypoints, const CvSeq* objectDescriptors,

					const CvSeq* imageKeypoints, const CvSeq* imageDescriptors,

					const CvPoint src_corners[4], CvPoint dst_corners[4] )

{

	double h[9];

	CvMat _h = cvMat(3, 3, CV_64F, h);

	vector<int> ptpairs;

	vector<CvPoint2D32f> pt1, pt2;

	CvMat _pt1, _pt2;

	int i, n;


	findPairs( objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors, ptpairs );

	n = ptpairs.size()/2;

	if( n < 4 )

		return 0;


	pt1.resize(n);

	pt2.resize(n);

	for( i = 0; i < n; i++ )

	{

		pt1[i] = ((CvSURFPoint*)cvGetSeqElem(objectKeypoints,ptpairs[i*2]))->pt;

		pt2[i] = ((CvSURFPoint*)cvGetSeqElem(imageKeypoints,ptpairs[i*2+1]))->pt;

	}


	_pt1 = cvMat(1, n, CV_32FC2, &pt1[0] );

	_pt2 = cvMat(1, n, CV_32FC2, &pt2[0] );

	if( !cvFindHomography( &_pt1, &_pt2, &_h, CV_RANSAC, 5 ))

		return 0;


	for( i = 0; i < 4; i++ )

	{

		double x = src_corners[i].x, y = src_corners[i].y;

		double Z = 1./(h[6]*x + h[7]*y + h[8]);

		double X = (h[0]*x + h[1]*y + h[2])*Z;

		double Y = (h[3]*x + h[4]*y + h[5])*Z;

		dst_corners[i] = cvPoint(cvRound(X), cvRound(Y));

	}


	return 1;

}


int main(int argc, char** argv)

{


	const char* object_filename = argc == 3 ? argv[1] : "image.bmp";


	CvMemStorage* storage = cvCreateMemStorage(0);


	cvNamedWindow("Object", 1);

	cvNamedWindow("Object Correspond", 1);


	static CvScalar colors[] = 

	{

		{{0,0,255}},

		{{0,128,255}},

		{{0,255,255}},

		{{0,255,0}},

		{{255,128,0}},

		{{255,255,0}},

		{{255,0,0}},

		{{255,0,255}},

		{{255,255,255}}

	};


	IplImage* object = cvLoadImage( object_filename, CV_LOAD_IMAGE_GRAYSCALE );


	IplImage* object_color = cvCreateImage(cvGetSize(object), 8, 3);

	cvCvtColor( object, object_color, CV_GRAY2BGR );


	CvSeq *objectKeypoints = 0, *objectDescriptors = 0;

	int i;

	CvSURFParams params = cvSURFParams(500, 1);



	cvExtractSURF( object, 0, &objectKeypoints, &objectDescriptors, storage, params );


	CvPoint src_corners[4] = {{0,0}, {object->width,0}, {object->width, object->height}, {0, object->height}};

	CvPoint dst_corners[4];


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

	{

		CvSURFPoint* r = (CvSURFPoint*)cvGetSeqElem( objectKeypoints, i );

		CvPoint center;

		int radius;

		center.x = cvRound(r->pt.x);

		center.y = cvRound(r->pt.y);

		radius = cvRound(r->size*1.2/9.*2);

		cvCircle( object_color, center, radius, colors[0], 1, 8, 0 );

	}

	cvShowImage( "Object", object_color );


	CvCapture* capture = cvCreateCameraCapture(0);

	IplImage* frame;

	//Размеры входного изображения

	int width = (int)cvGetCaptureProperty( capture, CV_CAP_PROP_FRAME_WIDTH);

	int height= (int)cvGetCaptureProperty( capture, CV_CAP_PROP_FRAME_HEIGHT);

	CvSize size = cvSize(width,height);

	//Для серого изображения

	IplImage* image1 = cvCreateImage(size, 8, 1);

	//Для уменьшенного в ZOOM раз серого изображения

	IplImage* image2 = cvCreateImage(cvSize((int)(width/ZOOM),(int)(height/ZOOM)), 8, 1);


	while(1){

		frame = cvQueryFrame( capture );

		if( !frame ) break;


		//Делаем входное изображение серым

		cvCvtColor( frame, image1, CV_RGBA2GRAY );

		//Уменьшаем серое изображение

		cvResize(image1,image2,CV_INTER_LINEAR);


		CvSeq *imageKeypoints = 0, *imageDescriptors = 0;

		cvExtractSURF( image2, 0, &imageKeypoints, &imageDescriptors, storage, params );


		if( locatePlanarObject( objectKeypoints, objectDescriptors, imageKeypoints,

			imageDescriptors, src_corners, dst_corners ))

		{

			//Рисуем линии контура рамки на входном изображении(frame)

			for( i = 0; i < 4; i++ )

			{

				CvPoint r1 = dst_corners[i%4];

				CvPoint r2 = dst_corners[(i+1)%4];

				cvLine( frame, cvPoint(r1.x*ZOOM, r1.y*ZOOM),

					cvPoint(r2.x*ZOOM, r2.y*ZOOM), colors[8] );


			}

		}

		//Выводим входное изображение(frame) в окно программы

		cvShowImage( "Object Correspond", frame );

		char c = cvWaitKey(33);

		if( c == 27 ) break;

	}

	cvReleaseCapture( &capture );

	cvDestroyWindow("Object");

	cvDestroyWindow("Object Correspond");


	return 0;

}

  • Like 1

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


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

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

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

Для некоммерческого использования Intel® C++ Composer XE 2011 for Linux, который ключает в себя Intel® C++ Compiler, Intel® Integrated Performance Primitives (IPP), Intel® Math Kernel Library, Intel® Parallel Building Blocks (PBB), можно бесплатно скачать отсюда.

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


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

У меня программа вылетала с ошибкой "divizion by zero" на строчке:

if( !cvFindHomography( &_pt1, &_pt2, &_h, CV_RANSAC, 5 ))
Стал искать причину, обнаружил, что функция naiveNearestNeighbor может возвращать одну и ту же точку сколько угодно раз. То есть, для примера, у нас найдено n особенностей для исходного изображения и 1 особенность для изображения с камеры, тогда эта одна точка почему-то будет считаться парой для всех n точек из шаблона. Скорее всего функция naiveNearestNeighbor не очень верно работает (я с ней особо не разбирался), возможно, необходимо добавить туда еще какой-то порог или изменить существующие параметры. Добавил в функцию findPairs вот такую заглушку:
                if( nearest_neighbor >= 0 && nearest_neighbor != last_neighbor)

                {

                        ptpairs.push_back(i);

                        ptpairs.push_back(nearest_neighbor);

                        last_neighbor = nearest_neighbor;

                }

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

На всякий случай прикрепляю проект для borland builder 6, вдруг кому-то пригодится.

OpenCV SURF.rar

  • Like 2

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


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

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

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

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

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

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

Войти

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

Войти сейчас


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

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

×