視窗程式若能對滑鼠事件 (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)時程式爆掉。
以下是查詢到的資料:
當滑鼠在影像視窗點擊一下的時候,會有固定三個動作:
- 點擊 (click)
- 放開 (down)
- 滑動 (move)
因此,滑鼠在點擊的時候,程式執行onMouse()連續三次,代表滑鼠在點擊的時候連續的三個動作。
- void onMouse(int event, int x, int y, int flag, void* param)
引數有四個為:
- 事件代號 (int event)
- 座標 (int x,int y)
- 旗標代號 (int flag)
- 滑鼠事件的代號名稱 (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)
谢谢您的分享,想用opencv做一个交互的程式,使用higui看起来会比较方便些
讚Liked by 1 person
不客氣!難得有大陸的朋友來訪,真令人高興! 😀
讚讚
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.
讚讚
Of course, you can grab my feed. Thanks for telling me. I will do better. 🙂
讚讚
首先感謝大大無私的分享。
小弟有一個問題要請教大大,
請問有辦法偵測使用者關閉視窗的動作嗎?
讚讚
嗨~Erix,謝謝你的讚賞!
「偵測視窗關閉」是個好問題,
我查了Stack Overflow的一篇文章,
也許可以給你一些想法:How to check if an opencv window is closed(點選可連結)。
讚讚
感謝大大無私的分享
目前還不太熟悉程式的寫法
當我Load影片檔進來就卡關了
我將我的程式碼寄至您的信箱
您方便的話,希望能再次指點迷津
非常感謝您
讚讚
嗨~不知道你的問題是哪邊?
若要存取影片檔的話你可以參考這篇:擷取視訊影像 (Extract Video Frames)
卡住的意思是指什麼問題?
若是程式碼不會寫的話,
你可能要花些時間練習喔~
若你的問題可以講得更仔細點,
這樣我也可以省去不少時間幫你解答,
其餘基礎的程式概念可能就要你自己尋找了:)
讚讚
後來用另一個方式解決了
程式會再多練習的,謝謝喔
讚讚
不客氣:)繼續加油吧!
讚讚
感謝您的分享
我想請問一下
在我把目標物框出來後,我要如何把它存成另一個圖片
對標記內容作分析呢?
很抱歉,我在這方面完全是新手,實在不知道該怎麼處理…
非常的感謝您!!!
讚讚
嗨~你好,謝謝你的留言!
使用這個函式來儲存影像:
cvSaveImage(影像名稱,影像內容);
prototype如下:
int cvSaveImage( const char* filename, const CvArr* image );
記得「影像名稱」需包含檔名與副檔名。
至於對標記內容做分析,
就看你想要對「影像內容」做怎樣的處理。
如果我猜的沒有錯的話,你是師大的學生。
讚讚
呵呵是的您猜對了 🙂
雖然收到了您的提示…
但我還是不知道"影像內容"的部分,我該怎麼把滑鼠框到的區域選出來
我想對影像作"建模"
在webcam上把目標物用滑鼠選出來,再對圈選的區域做直方圖擷取、分析
我把我的程式碼寄到您的信箱…(程式執行後有點小問題…還不好意思放上來…)
若您願意的話,希望您能幫我看一下
非常的感謝您!!
讚讚
圖形辨識期末專案—車輛顏色分類(Final Project – Car Color Classification)
(可點選連結)
一部分的功能似乎能在我那個專案中找到,再加上以下教學來擷取webcam影像,你就可以儲存該影像為檔案。我再把車輛顏色分類專案資料寄給你,其它相關教學可在我部落格上找到。
[OpenCV] 使用 Webcam
(可點選連結)
讚讚