用戶通過鼠標對圖像視窗最常見的操作有:
1. 左鍵單擊按下
2. 左鍵單擊擡起
3. 左鍵按下拖動
4. 鼠標指針位置移動
單次單擊操作響應事件及順序
Opencv中setMouseCallback()創建了一個鼠標回調函數,每次在圖像上單擊鼠標左鍵再擡起的過程,都會分3次調用鼠標響應函數,並且響應順序是:
1.左鍵單擊按下;
2.左鍵單擊擡起;
3.鼠標指針位置移動(即使原地單擊,鼠標位置並沒有移動);
可以編碼驗證一下回調函數的這個調用機制:
#include "core/core.hpp"
#include "highgui/highgui.hpp"
#include "imgproc/imgproc.hpp"
#include<iostream>
using namespace cv;
using namespace std;
void OnMouseAction(int event,int x,int y,int flags,void *ustc); //鼠標回調事件函數
int static times; //記錄調用次數
int main(int argc,char*argv[])
{
Mat image=imread(argv[1]);
imshow("image",image);
setMouseCallback("image",OnMouseAction);
waitKey();
system("pause");
}
//*******************************************************************//
//鼠標回調函數
void OnMouseAction(int event,int x,int y,int flags,void *ustc)
{
times++;
cout<<"第 "<<times<<" 次回調鼠標事件"<<endl;
if(event==CV_EVENT_MOUSEMOVE)
{
cout<<"觸發鼠標移動事件"<<endl;
}
if(event==CV_EVENT_LBUTTONDOWN)
{
cout<<"觸發左鍵按下事件"<<endl;
}
if(event==CV_EVENT_LBUTTONUP)
{
cout<<"觸發左鍵擡起事件"<<endl;
}
if(event==CV_EVENT_RBUTTONDOWN)
{
cout<<"觸發右鍵按下事件"<<endl;
}
if(event==CV_EVENT_RBUTTONUP)
{
cout<<"觸發右鍵擡起事件"<<endl;
}
if(event==CV_EVENT_LBUTTONDBLCLK)
{
cout<<"觸發左鍵雙擊事件"<<endl;
}
if(event==CV_EVENT_RBUTTONDBLCLK)
{
cout<<"觸發右鍵雙擊事件"<<endl;
}
}
前3次調用是在左鍵單擊前鼠標指針在圖像窗口移動造成的。不移動位置,單擊左鍵,觸發了第4次調用,紅色框框內的就是一個完整的鼠標按下再擡起的調用過程:
第一次傳入的event事件是左鍵單擊“CV_EVENT_LBUTTONDOWN”;
第二次傳入的event事件是左鍵擡起“CV_EVENT_LBUTTONUP”;
第三次傳入的event事件是鼠標移動“CV_EVENT_MOUSEMOVE”,這時候鼠標物理位置其實並沒有移動;
setMouseCallback()函數
瞭解了鼠標回調函數的調用機制後再來看一下創建回調函數的函數setMouseCallback();
原型:
void setMouseCallback(const string& winname, //圖像視窗名稱
MouseCallback onMouse, //鼠標響應函數,監視到鼠標操作後調用並處理相應動作
void* userdata = 0 //鼠標響應處理函數的ID,識別號
);
鼠標事件回調函數onMouse按照固定格式創建響應函數:
void OnMouseAction(int event,int x,int y,int flags,void *ustc)
event事件代表了鼠標的各種操作,詳細看一下各個event事件:
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 //中鍵雙擊
int x,int y,代表鼠標位於窗口的(x,y)座標位置,即Point(x,y);
int flags,代表鼠標的拖拽事件,以及鍵盤鼠標聯合事件,共有32種事件:
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 //(8~15)按Ctrl不放事件
#define CV_EVENT_FLAG_SHIFTKEY 16 //(16~31)按Shift不放事件
#define CV_EVENT_FLAG_ALTKEY 32 //(32~39)按Alt不放事件
函數指針 void *ustc標識了所響應的事件函數,相當於自定義了一個OnMouseAction()函數的ID。
簡單應用:記錄鼠標按下時座標和鼠標擡起時座標,分別做Line、Rectangle、Circle
#include "core/core.hpp"
#include "highgui/highgui.hpp"
#include "imgproc/imgproc.hpp"
#include<iostream>
using namespace cv;
using namespace std;
void OnMouseAction(int event,int x,int y,int flags,void *ustc); //鼠標回調事件函數
int static times; //記錄調用次數
int rowsBegin,rowsEnd;
int colsBegin,colsEnd;
Mat image;
int main(int argc,char*argv[])
{
image=imread(argv[1]);
imshow("image",image);
setMouseCallback("image",OnMouseAction);
}
//*******************************************************************//
//鼠標回調函數
void OnMouseAction(int event,int x,int y,int flags,void *ustc)
{
if(event==CV_EVENT_MOUSEMOVE)
{
cout<<"觸發鼠標移動事件"<<endl;
}
if(event==CV_EVENT_LBUTTONDOWN)
{
rowsBegin=y;
colsBegin=x;
cout<<"觸發左鍵按下事件"<<endl;
}
if(event==CV_EVENT_LBUTTONUP)
{
rowsEnd=y;
colsEnd=x;
line(image,Point(colsBegin,rowsBegin),Point(colsEnd,rowsEnd),Scalar(255,0,0),2,8,0);
rectangle(image,Rect(colsBegin,rowsBegin,colsEnd-colsBegin,rowsEnd-rowsBegin),Scalar(0,255,0),2,8,0);
circle(image,Point((colsEnd+colsBegin)/2,(rowsEnd+rowsBegin)/2),rowsEnd-rowsBegin,Scalar(0,0,255),2,8,0);
imshow("image",image);
cout<<"觸發左鍵擡起事件"<<endl;
}
if(event==CV_EVENT_RBUTTONDOWN)
{
cout<<"觸發右鍵按下事件"<<endl;
}
if(event==CV_EVENT_RBUTTONUP)
{
cout<<"觸發右鍵擡起事件"<<endl;
}
if(event==CV_EVENT_LBUTTONDBLCLK)
{
cout<<"觸發左鍵雙擊事件"<<endl;
}
if(event==CV_EVENT_RBUTTONDBLCLK)
{
cout<<"觸發右鍵雙擊事件"<<endl;
}
}