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