使用者通過滑鼠對圖像視窗最常見的操作有:
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,識别号
);
OnMouseAction()響應函數
滑鼠事件回調函數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;
}
}
左鍵單擊按下之後拖動滑鼠到某一個位置之後松開: