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 комментариев на «“9. OpenCV шаг за шагом. События от мышки”»

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

    • Всё верно — в данном случае, копировать изображение в цикле совершенно не обязательно.

Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Android Arduino Bluetooth CraftDuino DIY IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна конкурс манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение