Just My Life & My Work

[OpenCV] 滑鼠事件 (Mouse Event)

視窗程式若能對滑鼠事件 (Mouse Event)產生反應,那麼這個程式就比較友善:P,因為要做圖形辨識project的關係,我要讓使用者能在影像上做標記,接著對標記內容做分析,然後我要做的是車輛顏色分類 (Car Color Classification)
我寫的程式碼並不長,在這裡秀出來:

/**
	Theme: Mouse Event
	Compiler: Dev C++ 4.9.9.2
	Date: 100/06/10
	Author: ShengWen
	Blog: https://cg2010studio.wordpress.com/
*/
#include <cv.h>
#include <highgui.h>
#include <iostream>
using namespace std;
void onMouse(int event,int x,int y,int flags,void* param);
	IplImage *Imagex;//original
	IplImage *Image;//modified
	CvPoint VertexOne,VertexThree;//長方形的左上點和右下點
	CvScalar Color;//框框顏色
	int Thickness;//框框粗細
	int Shift;//框框大小(0為正常)
	int key;//按鍵碼
int main(){
	//初始化參數
	Imagex = cvLoadImage("apple.jpg",1);
	Image = cvCloneImage(Imagex);
	VertexOne=cvPoint(0,0);
	VertexThree=cvPoint(0,0);
	Color=CV_RGB(0,255,0);
	Thickness=2;
	Shift=0;
	key=0;
	//設定視窗
	cvNamedWindow("Original Apple",0);
	cvNamedWindow("Modified Apple",0);
	cvSetMouseCallback("Modified Apple",onMouse,NULL);//設定滑鼠callback函式
	cvShowImage("Original Apple",Image);
	cvShowImage("Modified Apple",Image);
	while(true){
		key=cvWaitKey(0);
		if(key==27){
			break;
		}
	}
	cvDestroyWindow("Original Apple");
	cvDestroyWindow("Modified Apple");
	return EXIT_SUCCESS;
}
void onMouse(int event,int x,int y,int flag,void* param){
	printf("( %d, %d) ",x,y);
	printf("The Event is : %d ",event);
	printf("The flags is : %d ",flag);
	printf("The param is : %d\n",param);
	if(event==CV_EVENT_LBUTTONDOWN||event==CV_EVENT_RBUTTONDOWN){//得到左上角座標
		VertexOne=cvPoint(x,y);
	}
	if(event==CV_EVENT_LBUTTONUP||event==CV_EVENT_RBUTTONUP){//得到右下角座標
		VertexThree=cvPoint(x,y);
	}
	if(flag==CV_EVENT_FLAG_LBUTTON||flag==CV_EVENT_FLAG_RBUTTON){//拖曳滑鼠
		VertexThree=cvPoint(x,y);
		cvReleaseImage(&Image);//如果沒有的話,記憶體會暴漲
		Image = cvCloneImage(Imagex);//cvCopy(Imagex, Image, 0);
		cvRectangle(Image,VertexOne,VertexThree,Color,Thickness,CV_AA,Shift);
		cvShowImage("Modified Apple",Image);
	}
	printf("VertexOne( %d, %d) ",VertexOne.x,VertexOne.y);
	printf("VertexThree( %d, %d)\n",VertexThree.x,VertexThree.y);
}

程式執行後會出現三個視窗,一個是再熟悉不過得黑底視窗,上頭會有滑鼠動作的資訊,第二個(初始)第三個(修改)是影像視窗。

初始影像視窗

初始影像視窗

修改影像視窗

修改影像視窗

這裡要特別注意的是cvCloneImage(Imagex)是動態配置記憶體給影像,在此之前要記得cvReleaseImage(&Image)釋放記憶體,不然當你在修改影像視窗上揮舞綠色長方形的時候,你可以從工作管理員上看到行程的記憶體使用量不斷地攀升,最後就是記憶體不夠用而程式爆掉……我大概在近2G記憶體使用量(我裝4G)時程式爆掉。

以下是查詢到的資料:

當滑鼠在影像視窗點擊一下的時候,會有固定三個動作

  1. 點擊 (click)
  2. 放開 (down)
  3. 滑動 (move)

因此,滑鼠在點擊的時候,程式執行onMouse()連續三次,代表滑鼠在點擊的時候連續的三個動作

  • void onMouse(int event, int x, int y, int flag, void* param)

引數有四個為:

  1. 事件代號 (int event)
  2. 座標 (int x,int y)
  3. 旗標代號 (int flag)
  4. 滑鼠事件的代號名稱 (param)

event代表的是滑鼠回傳的事件號碼,每當滑鼠有動作,event就會回傳訊息到onMouse(),也順便回傳滑鼠移動的座標,flag代表的是拖曳事件,param則是自己定義onMouse()事件的ID,就跟GUI介面的視窗介面ID一樣(cvGetWindowHandle()),不過這邊是自己給的編號,而視窗介面的ID則是系統自動隨機分配的ID,而滑鼠事件的執行可以細分為:

  • 事件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         中鍵雙擊

  • 旗標flag:

#define CV_EVENT_FLAG_LBUTTON 1          左鍵拖曳
#define CV_EVENT_FLAG_RBUTTON 2          右鍵拖曳
#define CV_EVENT_FLAG_MBUTTON 4          中鍵拖曳
#define CV_EVENT_FLAG_CTRLKEY 8    (8~15)按Ctrl不放事件
#define CV_EVENT_FLAG_SHIFTKEY 16 (16~31)按Shift不放事件
#define CV_EVENT_FLAG_ALTKEY 32   (32~39)按Alt不放事件

上面的#define是OpenCV自行定義的參數,要做事件捕捉的時候,可以用參數,也可以用純數字表示。

  • cvSetMouseCallback(“視窗名稱", 自己定義副程式名稱, 自己定義副程式名稱的ID)

滑鼠事件呼叫函式,必須給它一個Handler,也就是事件驅動的副程式名稱,Handler必須要符合格式:
onMouse()為自己定義的滑鼠事件名稱,可以接受滑鼠訊息做相關控制。

  • void xxx(int event, int x, int y, int flag, void* param)
  • void xxx(點擊事件代號, 滑鼠x軸座標, 滑鼠y軸座標, 拖曳事件代號, 自行給予xxx這副程式的ID編號)

參考:OpenCV中響應鼠標消息

Comments on: "[OpenCV] 滑鼠事件 (Mouse Event)" (14)

  1. 谢谢您的分享,想用opencv做一个交互的程式,使用higui看起来会比较方便些

    Liked by 1 person

  2. Simply desire to say your article is as surprising.
    The clarity in your post is simply spectacular and i can assume you are an expert on this subject.
    Well with your permission allow me to grab your feed to keep up to date with forthcoming post.
    Thanks a million and please carry on the enjoyable work.

  3. 首先感謝大大無私的分享。
    小弟有一個問題要請教大大,
    請問有辦法偵測使用者關閉視窗的動作嗎?

  4. 感謝大大無私的分享
    目前還不太熟悉程式的寫法
    當我Load影片檔進來就卡關了

    我將我的程式碼寄至您的信箱
    您方便的話,希望能再次指點迷津
    非常感謝您

  5. 感謝您的分享
    我想請問一下
    在我把目標物框出來後,我要如何把它存成另一個圖片
    對標記內容作分析呢?
    很抱歉,我在這方面完全是新手,實在不知道該怎麼處理…
    非常的感謝您!!!

    • 嗨~你好,謝謝你的留言!

      使用這個函式來儲存影像:
      cvSaveImage(影像名稱,影像內容);
      prototype如下:
      int cvSaveImage( const char* filename, const CvArr* image );
      記得「影像名稱」需包含檔名與副檔名。
      至於對標記內容做分析,
      就看你想要對「影像內容」做怎樣的處理。

      如果我猜的沒有錯的話,你是師大的學生。

隨意留個言吧:)~

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google photo

您的留言將使用 Google 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

標籤雲

%d 位部落客按了讚: