본문 바로가기
OpenCV

OpenCV , C++ ] 키보드와 마우스의 이벤트 처리

by eteo 2022. 8. 16.

 

1. 키보드 이벤트 처리

i 또는 I 키를 누르면 영상의 색상이 반전되는 예제

 

void keyboard() {

	Mat img = imread("lenna.bmp");

	if (img.empty()) {
		cerr << "Image load failed!" << endl;
		return;
	}

	namedWindow("img");
	imshow("img", img);

	while (true) {
		int keycode = waitKey();
		// 매개변수인 밀리초 단위로 대기하고 delay<=0 이면 무한히 기다림. 반환값은 눌려진 키 값

		if (keycode == 'i' || keycode == 'I')
		{
			img = ~img;
			imshow("img", img);
		}
		else if( keycode == 27 || keycode=='q'|| keycode == 'Q')
		{
			break;
		}
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

2. 마우스 이벤트 처리 (+키보드 이벤트 처리)

 

구현한 기능

1) 마우스 왼쪽 클릭한 채로 드래그 하면 노란 직선 그리기

2) c 또는 C키 입력시 영상에서 지금까지 그린 도형 없애기

3) ctrl키를 누른채로 마우스 왼쪽을 클릭해 드래그 하면 파란색 사각형 그리기

4) f 버튼을 누르면 3)을 내부 안채운 버전 또는 채운 버전으로 토글 가능

 

// OpenCV는 영상 출력 창에서 발생하는 마우스 이벤트를 사용자에게 전달하는 기능을 제공하는데 이를 위해선
// 먼저 마우스 콜백 함수를 등록하고 마우스 콜백 함수에 마우스 이벤트를 처리하는 코드를 추가해야 함

// 콜백 함수 내에서 사용할 변수는 전역으로 선언
Mat img;
Point ptOld;
Point ptNew;
int toggleFill=1;
void on_mouse(int event, int x, int y, int flags, void*);

void mouse() {	

	img = imread("lenna.bmp");

	if (img.empty()) {
		cerr << "Image load failed!" << endl;
		return;
	}

	namedWindow("img");

	// 마우스 콜백 함수를 등록하는 함수
	//void setMouseCallback(const String & winname, MouseCallback onMouse, void* userdata = 0);
	//winname : 이벤트 처리를 할 창의 이름, onMouse : 마우스콜백 함수 이름, userdata : 콜백함수에 전달한 데이터의 포인터로 전달할 값이 없으면 비움
	setMouseCallback("img", on_mouse);

	imshow("img", img);

	while (true) {
		int keycode = waitKey();

		if (keycode == 'c' || keycode == 'C')
		{
			img = imread("lenna.bmp");
			imshow("img", img);
		}
        // f키가 눌리는 경우 toggleFill 변수를 -1 또는 1로 토글시킴
        else if (keycode == 'f' || keycode == 'F')
		{
			toggleFill = toggleFill > -1 ? -1 : 1;
		}
		else if (keycode == 27 || keycode == 'q' || keycode == 'Q')
		{
			break;
		}
	}
}

// 마우스 콜백 함수는 마우스 이벤트가 발생할 때 호출되는 함수로 형식은
// typedef void (*MouseCallback)(int event, int x, int y, int flags, void* userdata);
// 매개변수 event 는 MouseEventTypes로 정의된 enum 중 하나가 전달됨
// 매개변수 x, y는 마우스 이벤트가 발생한 위치의 x, y 좌표
// 매개변수 flags 는 마우스 이벤트가 발생할 때의 마우스 또는 키보드의 상태 정보를 담고 있는데,
// MouseEventFlags enum의 논리합 조합이 전달됨. 두 가지 이상 상태가 동시에 일어났으면 OR 비트연산(|)의 값이 전달되는 것.
// void* 타입의 마지막 매개변수는 콜백함수 등록시 설정한 사용자 데이터의 포인터로, 설정하지 않았다면 항상 0(NULL)이 전달됨

void on_mouse(int event, int x, int y, int flags, void*) {

	// 디버깅을 위해 매개변수로 들어온 flags 출력
	cout << "flags: " << flags << endl;
	
	switch (event) {
    // 좌클릭이 되는 순간 ptOld에 좌표 저장
	case EVENT_LBUTTONDOWN:
		ptOld = Point(x, y);
		//cout << "EVENT_LBUTTONDOWN: " << x << ", " << y << endl;
		break;
    // 좌측버튼에서 손이 떼지는 순간 ptOld부터 ptNew까지 사각형을 그리고
    // ptNew는 다시 0,0으로 바꿈
    // rectangle() 함수의 5번째 인자인 toggleFill은 키보드 이벤트에 의해 1 또는 -1로 토글됨
	case EVENT_LBUTTONUP:
		//cout << "EVENT_LBUTTONDOWN: " << x << ", " << y << endl;
		if (ptNew.x != 0 && ptNew.y != 0) {
			rectangle(img, ptOld, ptNew, Scalar(255, 0, 0), toggleFill);
			imshow("img", img);
			ptNew = Point(0, 0);
		}
		break;
	case EVENT_MOUSEMOVE:
    	// Ctrl이 눌린상태 + 좌측버튼이 눌린상태로 마우스가 움직이는 경우 ptNEW변수에 좌표 갱신        
		if (flags == (EVENT_FLAG_LBUTTON | EVENT_FLAG_CTRLKEY)) {
			ptNew = Point(x, y);
		}
        // 좌측버튼이 눌린채로 마우스를 움직이는 경우 현재 Point까지 직선을 그림
        // 단 Ctrl이 눌린 상태라면 이 분기로 들어오지 않음
        else if (flags & EVENT_FLAG_LBUTTON) {
			line(img, ptOld, Point(x, y), Scalar(0, 255, 255), 2);
			imshow("img", img);
			ptOld = Point(x, y);
		}
		break;
	default:
		break;
	}	
}

 

 

 

 

MouseEventTypes

출처 : OpenCV 4로 배우는 컴퓨터 비전과 머신러닝

 

 

MouseEventFlags

출처 : OpenCV 4로 배우는 컴퓨터 비전과 머신러닝

 

 

디버깅을 위해 출력한 flags를 보면 왼쪽 버튼이 눌려있을 땐 1, Ctrl 키가 눌려있을 땐 8, 왼쪽 버튼이 눌려있고 동시에 Crtl 키가 눌려있을 땐 논리합 조합(OR 비트연산 값)인 9가 들어오는 것을 확인할 수 있다.