9. OpenCV шаг за шагом. События от мышки

1. OpenCV шаг за шагом. Введение.
2. OpenCV шаг за шагом. Установка.
3. OpenCV шаг за шагом. Hello World.
4. OpenCV шаг за шагом. Загрузка картинки.
5. OpenCV шаг за шагом. Вывод видео
6. OpenCV шаг за шагом. Ползунок
7. OpenCV шаг за шагом. Захват видео с камеры
8. OpenCV шаг за шагом. Запись видео
9. OpenCV шаг за шагом. События от мышки

Модуль HighGUI, который предоставляет функции пользовательского интерфейса, кроме ползунка умеет так же обрабатывать события от мышки. Рассмотрим как OpenCV это делает.
Перейдём сразу к коду, который загружает картинку и при клике левой кнопкой мышки рисует на картинке целеуказатель.

Обработчик мышки привязывается с помощью функции cvSetMouseCallback(), причём привязка осуществляется к конкретному окну.
В данном случае события от мышки обрабатываются функцией myMouseCallback(), которая при клике левой кнопки мышки (CV_EVENT_LBUTTONDOWN) вызывает мою же функцию drawTarget(), которая рисует красный круг и перекрестие из двух линий.

#include <cv.h>
#include <highgui.h>
#include <stdlib.h>
#include <stdio.h>

IplImage* image = 0;
IplImage* src = 0;

// рисуем целеуказатель
void drawTarget(IplImage* img, int x, int y, int radius)
{
	cvCircle(img,cvPoint(x, y),radius,CV_RGB(250,0,0),1,8);
	cvLine(img, cvPoint(x-radius/2, y-radius/2), cvPoint(x+radius/2, y+radius/2),CV_RGB(250,0,0),1,8);
	cvLine(img, cvPoint(x-radius/2, y+radius/2), cvPoint(x+radius/2, y-radius/2),CV_RGB(250,0,0),1,8);
}

// обработчик событий от мышки
void myMouseCallback( int event, int x, int y, int flags, void* param )
{
	IplImage* img = (IplImage*) param;

	switch( event ){
		case CV_EVENT_MOUSEMOVE: 
			break;

		case CV_EVENT_LBUTTONDOWN:
			printf("%d x %d\n", x, y);
			drawTarget(img, x, y, 10);
			break;

		case CV_EVENT_LBUTTONUP:
			break;
	}
}

int main(int argc, char* argv[])
{
	// имя картинки задаётся первым параметром
	char* filename = argc == 2 ? argv[1] : "Image0.jpg";
	// получаем картинку
	image = cvLoadImage(filename,1);
	// клонируем картинку 
	src = cvCloneImage(image);

	printf("[i] image: %s\n", filename);
	assert( src != 0 );

	// окно для отображения картинки
	cvNamedWindow("original",CV_WINDOW_AUTOSIZE);

	// вешаем обработчик мышки
	cvSetMouseCallback( "original", myMouseCallback, (void*) image);

	while(1){
		// показываем картинку
		cvCopyImage( image, src );
		cvShowImage( "original", src );

		char c = cvWaitKey(33);
		if (c == 27) { // если нажата ESC - выходим
			break;
		}
	}

	// освобождаем ресурсы
	cvReleaseImage(&image);
	cvReleaseImage(&src);
	// удаляем окно
	cvDestroyWindow("original");
	return 0;
}


Вот как у меня получилось накликать буквы CV (Computer Vision)


Рассмотрим новые функции:

void cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param=NULL );
— устанавливает обработчик на события от мышки

window_name — название окна, к которому привязывается событие
on_mouse — указатель на функцию-обработчик, которая будет вызываться для обработки события от мышки над заданным окном
param — дополнительный параметр, который можно передать функции-обработчику (в примере — это указатель на изображение)

функция-обработчик должна иметь вид:
typedef void (CV_CDECL *CvMouseCallback )(int event, int x, int y, int flags, void* param);

, где
event — событие для обработки:
#define CV_EVENT_MOUSEMOVE      0
#define CV_EVENT_LBUTTONDOWN    1
#define CV_EVENT_RBUTTONDOWN    2
#define CV_EVENT_MBUTTONDOWN    3
#define CV_EVENT_LBUTTONUP      4
#define CV_EVENT_RBUTTONUP      5
#define CV_EVENT_MBUTTONUP      6
#define CV_EVENT_LBUTTONDBLCLK  7
#define CV_EVENT_RBUTTONDBLCLK  8
#define CV_EVENT_MBUTTONDBLCLK  9

x, y — координаты положения указателя в координатах изображения
flags — флаг события:
#define CV_EVENT_FLAG_LBUTTON   1
#define CV_EVENT_FLAG_RBUTTON   2
#define CV_EVENT_FLAG_MBUTTON   4
#define CV_EVENT_FLAG_CTRLKEY   8
#define CV_EVENT_FLAG_SHIFTKEY  16
#define CV_EVENT_FLAG_ALTKEY    32


param — параметр, который может задействовать пользователь (в примере — указатель на картинку).

cvCopyImage — на самом деле обёртка для cvCopy
#define cvCopyImage( src, dst )         cvCopy( src, dst, 0 )

CVAPI(void)  cvCopy( const CvArr* src, CvArr* dst, const CvArr* mask CV_DEFAULT(NULL) );
— копирует массив src в массив dst
mask — маска — 8-битный одноканальный массив, с помощью которой можно задать область для копирования
т.е. в dst будет скопированы только элементы src, для которых маска не равна нулю.

void cvLine(CvArr* img, CvPoint pt1, CvPoint pt2, CvScalar color, int thickness=1, int line type=8, int shift=0 );
— рисует отрезок линии между двумя точками
img — картинка для рисования
pt1 — начальная точка отрезка
pt2 — конечная точка отрезка
color — цвет линии, можно задать макросом CV_RGB(r, g, b)
thickness — толщина линии
type — тип линии (4-связанная,8-связанная или CV_AA — сглаживание)
shift — сдвиг

void cvCircle(CvArr* img, CvPoint center, int radius, CvScalar color, int thickness=1, int line type=8, int shift=0 );
— рисует круг
img — картинка для рисования
center — центр круга
radius — радиус круга
color — цвет линии, можно задать макросом CV_RGB(r, g, b)
thickness — толщина линии
type — тип линии (4-связанная,8-связанная или CV_AA — сглаживание)
shift — сдвиг

Связность, определяет число соседних пикселей. Т.е 4-связный- это только 4 пикселя: север, восток, юг и запад,
[ ][o][ ]
[o][x][o]
[ ][o][ ]

а у 8-связного ещё добавляются пиксели по-диагонали: северо-восточный, юго-восточный, юго-западный и северо-западный.
[o][o][o]
[o][x][o]
[o][o][o]




далее: 10. OpenCV шаг за шагом. Обработка изображения — сглаживание
  • 0
  • 24 июля 2010, 09:04
  • noonv

Комментарии (2)

RSS свернуть / развернуть
+
0
Прохожу эти уроки, только пишу на c#. В целом всё интуитивно понятно как переписать.
Не понятно в данном случае: зачем вообще использовать клонирование изображение? Удалил всё что касается переменной src — и так работает.
avatar

JohnJ

  • 4 августа 2015, 09:56
+
0
Всё верно — в данном случае, копировать изображение в цикле совершенно не обязательно.
avatar

noonv

  • 4 августа 2015, 11:33

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.