opencv3編程入門——學習筆記(3)鼠標的交互式使用

       今天明白看一件事情,在編程的學習過程中,每一行的代碼最好都是自己敲,遇見一個不懂的地方就去查一下。怪不得那些大牛都說想學編程,總是複製粘貼是絕對不行的。因爲你在敲每一個函數,每一個變量的時候都能發現新的問題。學習的其實不是某一個具體的函數,學的是在敲代碼的過程中找到很多新的東西。

       好了那先說一下這次想要完成的任務:在一個窗口中,點擊鼠標左鍵,確定一個起始位置;拖動鼠標到適當的位置;釋放鼠標,隨之畫出一個隨機顏色的矩形框。

       先把結果和代碼貼出來吧。


#include <opencv2/opencv.hpp>
using namespace cv;

#define WINDOW_NAME "【程序窗口】"

//-------------------全局函數聲明部分-------------------

void on_MouseHandle(int event, int x, int y, int flags, void* param);//這就是鼠標操作的回調函數
void DrawRectangle(Mat& img, Rect box);//自定義的用來話矩形,並且顏色隨機的函數
void ShowHelpText();//額。。。這個暫時沒用到,後續會說到的

//-------------------全局變量聲明部分-------------------

Rect g_rectangle;//Rect類和Mat類相似,是opencv定義好的類
bool g_bDrawingBox = false;//是否進行繪製
RNG g_rng(12345);//一個僞隨機序列產生器(種子是12345),這個隨機序列產生器的名字是g_rng

//-------------------main()函數--------------------------
int main(int argc, char*argv)
{
	//【1】準備參數
	g_rectangle = Rect(-1, -1, 0, 0);
	Mat srcImage(600, 800, CV_8UC3), tempImage;
	srcImage.copyTo(tempImage);
	g_rectangle = Rect(-1, -1, 0, 0);
	srcImage = Scalar::all(0);
	
	//【2】設置鼠標操作回調函數
	namedWindow(WINDOW_NAME);
	setMouseCallback(WINDOW_NAME, on_MouseHandle, (void*)&srcImage);
	
	//【3】程序主循環,當繪製的標識符爲真時,進行繪製
	while (1)
	{
		srcImage.copyTo(tempImage);//複製源圖到臨時變量
		if (g_bDrawingBox)
			DrawRectangle(tempImage, g_rectangle);//當進行繪製的標識符爲真時進行繪製
		imshow(WINDOW_NAME, tempImage);
		if (waitKey(10) == 27)
			break;//按下ESC鍵,程序退出
	}
	return 0;
}

//------------------------【on_MouseHandle()函數】-----------------------
//           描述:鼠標回調函數,根據不同的鼠標事件進行不同的操作
//-----------------------------------------------------------------------
void on_MouseHandle(int event, int x, int y, int flags, void* param)
{
	Mat& image = *(cv::Mat*) param;
	switch (event)
	{
		//左鍵按下消息
	case EVENT_LBUTTONDOWN:
	{
							  g_bDrawingBox = true;
							  g_rectangle = Rect(x, y, 0, 0);//記錄起始點
	}
		break;
		//鼠標移動消息
	case EVENT_MOUSEMOVE:
	{
							if (g_bDrawingBox)//如果是否進行繪製的標識符爲真,則記錄下長和寬到RECT型變量中
							{
								g_rectangle.width = x - g_rectangle.x;
								g_rectangle.height = y - g_rectangle.y;
							}
	}
		break;
	case EVENT_LBUTTONUP:
	{
							g_bDrawingBox = false;
							//對寬和高小於0的處理
							if (g_rectangle.width < 0)
							{
								g_rectangle.x += g_rectangle.width;
								g_rectangle.width *= -1;
							}
							
							if (g_rectangle.height < 0)
							{
								g_rectangle.y += g_rectangle.height;
								g_rectangle.height *= -1;
							}
							//調用函數進行繪製
							DrawRectangle(image, g_rectangle);
	}
		break;
	}
}

//-------------------------【DrawRectangle()函數】-----------------------
//         描述:自定義的矩形繪製函數
//-----------------------------------------------------------------------
void DrawRectangle(cv::Mat& img, cv::Rect box)
{
	rectangle(img, box.tl(), box.br(), Scalar(g_rng.uniform(0,255), g_rng.uniform(0,255), g_rng.uniform(0,255)));
}

       然後說一下自己在“敲代碼”的過程中學到的東西吧。

首先,鼠標的交互式使用和上一篇講過的軌跡條一樣,它們的使用都是藉助一個“中介”函數創建,然後再“中介”函數的參數裏提供一個回調函數,用來說明創建一個軌跡條或者一個鼠標交互操作是想具體幹什麼。

在上一篇軌跡條的使用那篇文字裏說了,想要“搞”一個軌跡條需要先用一個createTrackbar()函數來創建滑動條並指定回調函數。而指定鼠標操作消息的回調函數的“中介”函數是SetMouseCallback()。

SetMouseCallback()函數的原型如下:

void setMouseCallback(conststring$ winname, MouseCallback onMouse, void *userdata=0)

第一個參數,const string&類型的winname,窗口的名字。

第二個參數,MouseCallback類型的onMouse,指定窗口裏每次鼠標事件發生時,被調用的(回調函數)函數的指針。這個回調函數的原型大概形式爲void(int event,int x,int y, int flags, void* param )。其中event是EVENT_+變量之一,x,和y是鼠標指針在圖像座標系(不是窗口座標系)中的座標值。flags,是EVENT_FLAG的組合(沒用到),param是用戶定義的傳遞到SetMouseCallback()函數調用的參數。

第三個參數,void*類型的userdata,用戶定義的傳遞到回調函數的參數,默認值爲0。

上面這就是這次學到的最核心的東西了。剩下的就是我個人在敲代碼的過程中遇見的一些自己不熟悉的知識內容。

 這次實戰練習實際上是第一個接觸到的涉及座標系問題的代碼。那麼就需要簡單的瞭解一下opencv中的座標系的關係。如果有興趣可以看一下tornadomeet大神寫的opencv座標系的初步認識點擊打開鏈接。我的收穫就是明白了opencv的座標系原點是建在左上角的,然後最上面的橫着的線是x軸,貼着左邊的豎線是y軸。另外,大牛還寫了很多細節的地方,大家可以看一下。

除了座標系問題還有就是Rect類。我個人理解這個和Mat類相似,Mat類是用來存矩陣(圖片)的。那Rect類就是用來存一個矩形的。裏面包含了一個矩形幾乎所有的元素。而且最有趣的是這樣的Rect類型的變量還可以進行運算(交、並運算)。這個類的資料可以參考CAUC康輝寫的OpenCV的Rect矩形類用法點擊打開鏈接

補充:忘記了一個知識點:RNG。千萬不要望文生義,這個可不是Royal Never Giveup。這個是隨機序列生成器。(實際上是僞隨機序列)。它的作用說的簡單點就是由軟件開發者給出一些“種子”(別想歪)。然後把這些種子給到計算機,計算機由一個固定的算法產生一些隨機數。如果“種子”是固定的那麼在同一個平臺下產生的隨機數也是一樣的(所以說它是僞隨機嘛!)。在這個程序裏就是用給的種子(12345)來生成0-255之間的一些隨機數,用來表徵一些不同的顏色。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章