OpenCV
學習筆記
March 12, 2010
1.
??????
關(guān)于數(shù)據(jù)基本類型的學習
參見代碼:
//2010 年 3 月 12 日, Demo 1?? OpenCV 的第一個例子 //author : liuchang #include <cv.h> #include <iostream> using namespace std; int main() { ???????? CvPoint p = cvPoint(1,3);// 針對整型的類型 CvPoint ,對應(yīng)有構(gòu)造函數(shù) cvPoint ,注意大小寫 ???????? cout << p.x << " " << p.y << endl; ???????? CvPoint2D32f p2 = cvPoint2D32f(12.34,43.45); ???????? cout << p2.x << " " << p2.y <<endl; ???????? CvPoint3D32f p3 = cvPoint3D32f(12.34,23.45,56.43); ???????? cout << p3.x << " " << p3.y << " " << p3.z << endl; //============================================================================= ??? CvSize r = cvSize(3,4);??????????????????????????????????????????? // 長方形維數(shù)類型 ???????? cout << r.width << " " <<r.height << endl; ???????? CvSize2D32f r2 = cvSize2D32f(23.45,34.56); ???????? cout << r2.width << " " << r2.height << endl; //============================================================================= ???????? CvRect x = cvRect(3,4,12.34,45.56); ???????? cout << x.x << " " << x.y << " " << x.width << " " << x.height << endl;
???????? return 0; } |
總結(jié):學習到集中基本的數(shù)據(jù)類型
1. ?????? 點的類型。包括二維和三維,而每一個坐標又可以分為整型和浮點型。其中對于二維,用 2D 來表示,對于三維,用 3D 來表示。具體的見代碼上,默認的 CvPoint 類型是一個二維的,整型參數(shù)的點。其他的見上。
2. ?????? 長方形維數(shù)類型。長方形已經(jīng)固定時二維的類型,于是,形參就只用兩個,但是類型可以是整型和浮點型,于是又多了 CvSize2D32f 這種類型了。
3. ?????? 有偏移量的長方形維數(shù)類型。此時前面兩個形參就是偏移量的坐標,分別為 x 和 y 。后面的就是寬和高了。注意,形參的類型都是整型,所以,如果像上面的代碼那樣,就會發(fā)生截斷處理,取整數(shù)部分,于是輸出結(jié)果就會有所不同。
4. ?????? 注意類型和構(gòu)造函數(shù)的區(qū)別。看看,定義一個變量的時候,用的是類型,即: CvPoint,CvSize,CvRect 等等,而對這個類型的變量初始化的時候用的是對應(yīng)的構(gòu)造函數(shù),于是是 cvPoint,cvSize,cvRect, 看到規(guī)律了嗎?類型的第一個首字母大寫,而構(gòu)造函數(shù)則是對應(yīng)的類型名的第一個字母小寫就可以了。因此, OpneCV 的這種命名方法還是很科學易記的。
附注: OpenCV 的安裝過程以及 Visual C++ 的配置方法:
1. ?????? 下載 OpenCV 并安裝。由于之前已經(jīng)下載了 1.0 的版本,所以這里安裝的是 1.0 ,默認路徑安裝,并選擇注冊環(huán)境變量。
2. ?????? 檢查系統(tǒng)變量是否更改,盡管上面的選項可能會起作用,不過在我的系統(tǒng)中( Windows 7 ),環(huán)境變量還是沒有更改,于是,選擇高級系統(tǒng)設(shè)置 --- 環(huán)境變量 — 系統(tǒng)變量 —path— 編輯,就是在最后添加路徑 ”; C:\Program Files\OpenCV\bin”, 然后點擊確定退出。
3. ?????? 安裝完成后,并不意味著工作就結(jié)束了,還需要設(shè)定我們的編程環(huán)境。具體來說就是 Visual C++ 6.0 的設(shè)置。
Visual C++ 6.0 中設(shè)置 OpenCV 的步驟:
1. ?????? 選擇 tools---option, 在彈出的對話框中點擊 Directories 標簽,在 Show directories for 下拉選擇 Include files ,在 Directories 中添加路徑:
?? C:\Program Files\OpenCV\cxcore\include
?? C:\Program Files\OpenCV\cv\include
?? C:\Program Files\OpnCV\cvaux\include
?? C:\Program Files\OpenCV\otherlibs\highgui
?? C:\Program Files\OpenCV\otherlibs\cvcam\include
2. ?????? 在 Show directories for 下拉列表框中選擇 Libarary files ,在 Directories 中添加路徑:
?? C:\Program Files\OpenCV\lib
3. ?????? 在 Show directories for 下拉列表框中選擇 Executable files ,在 Directories 中添加路徑:
? C:\Program Files\OpenCV\bin
4. ?????? 配置完畢,退出。
配置完畢之后的測試程序( Demo1 ),就是前面的測試程序,編譯,運行, OK ,完全沒有問題,證明配置完畢!
GUI
命令
1. ?????? 使用到圖片處理,顯示,創(chuàng)建窗口等命令的時候,必須要在 Project—Setting 選項中設(shè)定相應(yīng)的參數(shù),否則可能會發(fā)生連接錯誤!這個不同于上面的 Demo1 ,因為 1 中僅僅是用到了一個數(shù)據(jù)類型,而沒有使用 CV 庫函數(shù)的功能,比如顯示,打開一個圖片,運用到第三方庫的話,肯定要調(diào)用 API 來實現(xiàn)功能,所以,鏈接庫的話,必須要加入,為此,可根據(jù)提示信息設(shè)置,一般的,進行圖像處理,都需要使用到這個。
2. ?????? 路徑的問題。先看看 Demo2 程序 :
#include <cv.h> #include <highgui.h> #include <stdio.h>
int main() { ???????? IplImage* image = cvLoadImage("C:\\Users\\liuchang\\test1.bmp"); ???????? if(!image){????????????????? // 如果加載失敗 ?????????????????? printf("error: 導入圖片出錯,很可能是路徑出錯 !\n"); ?????????????????? return 0; ???????? } ???????? cvNamedWindow("win1",CV_WINDOW_AUTOSIZE);??? // 創(chuàng)建一個窗口 ???????? cvMoveWindow("win1",100,100);?????????? // 定位一個窗口 ???????? cvShowImage("win1",image);??????????????????????????? // 在創(chuàng)建的窗口中顯示一個圖片 //????? cvWaitKey(0);?????????????????????????????????????? ???????? // 等待用戶輸入,否則一閃而過 , 看不到圖片 ???????? cvReleaseImage(&image);????????????????????????????????? // 注意使用完后一定要釋放 ???????? return 0; } |
此段程序中,功能很簡單,就是幫助用戶顯示一副圖片,運行程序,可以顯示出來一幅已經(jīng)存在的圖片,而不需要任何的其他 API 來實現(xiàn)。在 OpenCV 中,處理圖像的函數(shù)很多,此處只是簡單的圖像顯示命令!
另外,上面的注釋很清楚的顯示了程序的各段代碼的功能,這里不再說明。對于具體的說明,后面還會繼續(xù)!需要注意的一點就是,路徑,需要兩個斜線,此處很重要,因為對于一個字符串,在作為路徑打開的時候,需要
”\\”
才能夠被解釋為一個斜線,所以如果像上面直接給出路徑的話,需要指定是兩個斜線,否則會出錯!
OK ,下面試試從客戶端來輸入數(shù)據(jù),即利用 main 函數(shù)可以從用戶輸入數(shù)據(jù)來編寫:
#include <cv.h> #include <highgui.h> #include <stdio.h> #include <string.h>
int main(int argc, char **argv) { ???????? char num[20]; ???????? char getup[20]; ???????? int i ; ???????? itoa(argc,num,10); ???????? puts(num); ???????? puts(argv[0]); ???????? puts(argv[1]); ???????? strcpy(getup,argv[1]); ??? for(i = 0; i < strlen(getup); i++) ?????????????????? putchar(getup[i]); ???????? putchar('\\');?????? // 輸出時一個斜線,而如果僅僅一個斜線的話,會報錯! ? ?????? IplImage* image = cvLoadImage(argv[1]); ???????? if(!image){????????????????? // 如果加載失敗 ?????????????????? printf("error: 導入圖片出錯,很可能是路徑出錯 !\n"); ?????????????????? return 0; ???????? } ???????? cvNamedWindow("win1",CV_WINDOW_AUTOSIZE);??? // 創(chuàng)建一個窗口 ???????? cvMoveWindow("win1",100,100);?????????? // 定位一個窗口 ???????? cvShowImage("win1",image);??????????????????????????? // 在創(chuàng)建的窗口中顯示一個圖片 ???????? cvWaitKey(0);???????????????????????????????????????????????? // 等待用戶輸入,否則一閃而過 , 看不到圖片 ???????? cvReleaseImage(&image);????????????????????????????????? // 注意使用完后一定要釋放 ???????? return 0; } |
關(guān)于 main 函數(shù)參數(shù)的問題,在前面的說明中很清楚,不過這里需要再次說明:
首先,
argc
讀入的是輸入?yún)?shù)的個數(shù),比如這里輸入:
test2? H:\ray.jpg
,那么讀取的
argc
的個數(shù)就是
2
,而
argv
是一個數(shù)組,用來存放你輸入的參數(shù),既然參數(shù)為
2
,那么該數(shù)組就有兩個參數(shù),一個
argv[0]
,即前面的那個程序名
test2
,而后面的那個參數(shù)就是你讀入的那個路徑。注意的一點是:讀取后存放的路徑和你輸入的數(shù)據(jù)可能不同,具體來說就是,你輸入的是
:H:\ray.jpg
,而在機內(nèi)存儲的這個字符串的內(nèi)容是:
H:\\ray.jpg
,也就是說,這個字符串是按照能夠正常顯示那個斜線符來設(shè)計的,也就是轉(zhuǎn)義字符設(shè)計的,讀入的數(shù)據(jù)將被轉(zhuǎn)換成正確的能夠表示的數(shù)據(jù)。從上面的驗證代碼中可以看到。
同時,計算
strlen(argv[1])
也會發(fā)現(xiàn),兩個斜線
’\\’
被解釋成一個字符!
對于, putchar(‘\\’) ,如果僅僅是一個斜線的話,會報錯誤,但是兩個的話就正常顯示一個 ’\’ 了。注意是表示的字符,用的單引號,所以,兩個斜線被解釋為一個字符。
Tips :如果輸入?yún)?shù)是: test2 H:\\ray.jpg ,還是可以正常運行的。
注記:和 C 庫函數(shù)不同,例如 open 函數(shù),路徑是 open(“C:\test.c”,O_RDONLY); 這樣的話,里面就是一個斜線哦。所以 OpenCV 是不同的路徑寫法,一定要注意,還有上面解釋的那個輸入?yún)?shù)的問題,就 OK 了。
如果路徑不對,則會有下面提示信息:
H:\OPENCV\test4\test4.cpp(15) : warning C4129: 'O' : unrecognized character escape sequence
H:\OPENCV\test4\test4.cpp(15) : warning C4129: 'l' : unrecognized character escape sequence
所以,一定要加雙下劃線!
3. ?????? 輸入處理:
OpenCV 中如何響應(yīng)鼠標事件呢?比如,如何響應(yīng)點擊鼠標,如何響應(yīng)鼠標被按下呢?
其實,只需要你實現(xiàn)下面 mouseHandler 這個方法就可以了:
void mouseHandler(int event,int x,int y,int flags, void *param) { ???????? switch (event) ???????? { ???????? case CV_EVENT_LBUTTONDOWN: ?????????????????? if(flags & CV_EVENT_FLAG_CTRLKEY) ??????????????????????????? printf("Left button down with CTRL pressed!\n"); ?????????????????? break; ???????? case CV_EVENT_LBUTTONUP: ?????????????????? printf("Left button up!\n"); ?????????????????? break; ???????? } } |
那么,如何注冊鼠標監(jiān)聽呢?看下面這段代碼:
???????? int mouserParam = 5;
???????? cvSetMouseCallback("win1",mouseHandler,&mouserParam);
也就是說,具體的實現(xiàn)監(jiān)聽函數(shù)由 mouseHandler 來完成,而要注冊,也就是讓它何時監(jiān)聽,監(jiān)聽哪一個窗口,則需要用 cvSetMouseCallback 函數(shù)來實現(xiàn),具體的參數(shù),可查閱 API 文檔,當然,也可以由上面應(yīng)用猜測出來。
上面的代碼很容易就實現(xiàn)了鼠標被點擊并且同時按下 CTRL 鍵的監(jiān)聽動作和鼠標釋放的動作,當然,你還可以實現(xiàn)更多的功能,具體的就是使用 event 的判斷,以及和 flags 聯(lián)合實現(xiàn)的復合鍵判斷!
4. ?????? 前面講到了如何實現(xiàn)監(jiān)聽鼠標事件,那么這里講下如何監(jiān)聽鍵盤事件:
看看下面的代碼:
???????? int key ;
???????? key = cvWaitKey(0);????????????????????????????
???????? if(key == 'q'){
?????????????????? printf("quit\n");
?????????????????? return 0;
???????? }
上面這段代碼的意思就是不斷的等待輸入,如果輸入時 q 的話就退出程序,實驗之,發(fā)現(xiàn)有用。從這里引申下幾點:
(1) ?????? 對于 cvWaitKey 函數(shù)的參數(shù),就是等待的毫秒數(shù),如果是 0 ,則表示不斷的等待輸入,進入一個循環(huán)。而它的返回值,就是你按下的按鈕的鍵值。當然,如果要等待一定的時間,如果沒有輸入還是退出的話,可以采用 cvWaitKey(1000) 這樣的具體參數(shù),這樣在等待的過程沒有輸入的話,還是可以正常退出,而不是想前面的循環(huán)在那里。
(2) ?????? 如果要實現(xiàn)不斷循環(huán)的話,可以采用下面的這個形式:
while(1){
?? key = cvWaitKey(10);
?? if(key == 27)
??????????? break;
?? switch(key){
?? case 'h':
??????????? break;
?? case 'i':
??????????? break;
?? }
}
這種方式也很好的實現(xiàn)了循環(huán)等待多重輸入的形式。
5. ?????? 如何處理拖動條事件:
上圖即拖動條,如何創(chuàng)建并響應(yīng)該事件呢?
1. ?????? 創(chuàng)建:
int trackbarVal = 25;
int maxVal = 100;
cvCreateTrackbar("bar1","win1",&trackbarVal,maxVal,trackbarHandler);
這樣就設(shè)置了一個名稱為 bar1 的拖動條。
2. ?????? 響應(yīng)事件:利用函數(shù) trackbarHandler 來實現(xiàn)
void trackbarHandler(int pos)
{
printf("Trackbar position: %d\n",pos);
}
注意這個監(jiān)聽是自動的。也就是說不需要自己進行任何的注冊,只要創(chuàng)建了,并且寫了這個函數(shù),就可以實現(xiàn)自動的監(jiān)聽,因為,在創(chuàng)建的函數(shù)中,最后的一個參數(shù)就是一個監(jiān)聽的函數(shù)。
附記:完整的代碼如下:
#include <cv.h> #include <highgui.h> #include <stdio.h> #include <string.h>
void mouseHandler(int event,int x,int y,int flags, void *param) { ???????? switch (event) ???????? { ???????? case CV_EVENT_LBUTTONDOWN: ?????????????????? if(flags & CV_EVENT_FLAG_CTRLKEY) ??????????????????????????? printf("Left button down with CTRL pressed!\n"); ?????????????????? break; ???????? case CV_EVENT_LBUTTONUP: ?????????????????? printf("Left button up!\n"); ?????????????????? break; ???????? } }
void trackbarHandler(int pos) { ???????? printf("Trackbar position: %d\n",pos); }
int main(int argc, char **argv) { // ??? char num[20]; // ??? char getup[20]; // ??? int i ; // ??? itoa(argc,num,10); // ??? puts(num); // ??? puts(argv[0]); // ??? puts(argv[1]); // ??? strcpy(getup,argv[1]); //???? for(i = 0; i < strlen(getup); i++) // ???????????? putchar(getup[i]); // ??? putchar('\\'); ? ?????? IplImage* image = cvLoadImage(argv[1]); ???????? if(!image){????????????????? // 如果加載失敗 ?????????????????? printf("error: 導入圖片出錯,很可能是路徑出錯 !\n"); ?????????????????? return 0; ???????? } ???????? cvNamedWindow("win1",CV_WINDOW_AUTOSIZE);??? // 創(chuàng)建一個窗口 ???????? cvMoveWindow("win1",100,100);?????????? // 定位一個窗口 ???????? cvShowImage("win1",image);??????????????????????????? // 在創(chuàng)建的窗口中顯示一個圖片 // ??? int mouserParam = 5; // ??? cvSetMouseCallback("win1",mouseHandler,&mouserParam); // ??? int key ; // ??? key = cvWaitKey(0);???????????????????????????? // 等待輸入,等待時間為 1000ms // ??? if(key == 'q'){ // ???????????? printf("quit\n"); // ???????????? return 0; // ??? } ???????? int trackbarVal = 25; ???????? int maxVal = 100; ???????? cvCreateTrackbar("bar1","win1",&trackbarVal,maxVal,trackbarHandler); //????? int pos = cvGetTrackbarPos("bar1","win1"); //? int pos = cvGetTrackbarPos("bar1","win1"); //????? cvSetTrackbarPos("bar1","win1",25);
???????? cvWaitKey(0);???????????????????????????????????????????????? // 等待用戶輸入,否則一閃而過 , 看不到圖片 ???????? cvReleaseImage(&image);????????????????????????????????? // 注意使用完后一定要釋放 ???????? return 0; }
|