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. tintin 的大頭貼

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

    Liked by 1 person

  2. adult sharing pron adult social network 的大頭貼

    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. Erix 的大頭貼

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

  4. 布丁 的大頭貼

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

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

  5. magie 的大頭貼

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

    • HappyMan 的大頭貼

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

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

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

隨意留個言吧:)~

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料

標籤雲