18
OpenCV DIY 自學手冊 by NCKU CSIE VISION SYSTEM LAB - 1 - OpenCV DIY 自學手冊 版本 更新日期 更新者 主要更新內容 1.0 2006/3/13 陳彥廷 1.1 2006/7/21-8/2 蔡翰進 1.2 2006/8/17 陳彥廷 1.3 2007/3/6 蔡翰進 - 加入主要更新內容 - 修正 6.6 解說的筆誤 - 加入 6.7 1.4 2007/3/11 蔡翰進 - 加入 OpenCV trap bug Document maintained by NCKU CSIE VISION SYSTEM LAB Editor Personal Website 陳彥廷 http://www.tintinpiano.com/ 蔡翰進 http://euler-amon.blogspot.com/

OpenCV DIY 自學手冊 - pudn.comread.pudn.com/downloads168/doc/772861/openCVDIY.pdf · 2009-05-22 · opencv diy 自學手冊 by ncku csie vision system lab - 1 - opencv diy 自學手冊

  • Upload
    others

  • View
    16

  • Download
    0

Embed Size (px)

Citation preview

OpenCV DIY 自學手冊 by NCKU CSIE VISION SYSTEM LAB

- 1 -

OpenCV DIY 自學手冊

版本 更新日期 更新者 主要更新內容

1.0 2006/3/13 陳彥廷

1.1 2006/7/21-8/2 蔡翰進

1.2 2006/8/17 陳彥廷

1.3 2007/3/6 蔡翰進 - 加入主要更新內容 - 修正 6.6 解說的筆誤 - 加入 6.7

1.4 2007/3/11 蔡翰進 - 加入 OpenCV 的 trap 及

bug

Document maintained by NCKU CSIE VISION SYSTEM LAB

Editor Personal Website 陳彥廷 http://www.tintinpiano.com/ 蔡翰進 http://euler-amon.blogspot.com/

OpenCV DIY 自學手冊 by NCKU CSIE VISION SYSTEM LAB

- 2 -

目錄

1 OpenCV 介紹 ................................................................................................................................................ 3

2 OpenCV libray Download && Install 下載與安裝 .................................................................................. 3

3 在 VC 6.0 下使用 OpenCV 編寫程式 .......................................................................................................... 4

3.1 Environment configuration 環境變數設定: ........................................................................................ 4

3.2 將 OpenCV 的動態連結 DLL 檔放進系統資料夾: ............................................................................. 6

3.3 在程式碼中引入.h 檔: ............................................................................................................................ 6

4 在 .Net 2005 VC++下使用 OpenCV 編寫程式 .......................................................................................... 7

4.1 Environment configuration 環境變數設定: ........................................................................................ 7

4.2 將 OpenCV 的動態連結 DLL 檔放進系統資料夾: ............................................................................. 9

4.3 在程式碼中引入.h 檔: ............................................................................................................................ 9

5 其他可用資源 .............................................................................................................................................. 10

5.1 如何用 openCV 實作出 Optical Flow ................................................................................................... 10

5.2 OpenCV Reference Manual ................................................................................................................... 10

5.3 OpenCV 的範例執行檔 .......................................................................................................................... 10

6 實用程式碼範例展示 ...................................................................................................................................11

6.1 讀取影像(BMP、JPEG)、:詳見 LoadImage 資料夾 .......................................................................11

6.2 使用 Gaussian Blur 濾鏡: .....................................................................................................................11

6.3 讀取及存取影像 Pixel 值: .....................................................................................................................11

6.4 讀取 AVI 檔案:詳見 CaptureAVI 資料夾 ...........................................................................................11

6.5 如何將 IplImage 型態的 image 轉換為 unsigned char 的形式供後續處理?..................................... 13

6.6 解 AX=B 的線性代數問題(SVD 分解)(使用 Stack 變數) .................................................................... 13

6.7 解 AX=B 的線性代數問題(SVD 分解)(使用 Heap 變數) ..................................................................... 14

6.8 解 EigenValue,EigenVector ................................................................................................................. 16

7 不要以為 OpenCV 是萬能的!-OpenCV 的 Trap 及 Bug ................................................................... 18

7.1 cvSolve 的陷阱 ......................................................................................................................................... 18

7.2 cvThreshold 的錯誤 ................................................................................................................................ 18

OpenCV DIY 自學手冊 by NCKU CSIE VISION SYSTEM LAB

- 3 -

1 OpenCV 介紹

OpenCV 是 Intel 開發的影像函式庫,裡面提供了許多影像處理有關的函式,有些函式都是根據一些

paper 去實做出來的。建議如果想要的功能 OpenCV 已經提供的,而且實作的方式都是一樣的話,直接

拿來用,可以不用再自己寫,這樣可以節省掉很多的時間 ! 而且 OpenCV 的 Code 有最佳化過,處理速

度非常的快。 第六章的實用範例程式碼包含了一些矩陣運算(矩陣相乘、反矩陣、Eigen Value…等)、矩陣統計運

算(Mean、Median、Variance、最小平方法……等),相信有些人會需要這方面的功能。OpenCV 函式庫由

於相當大,有些功能必需自己試過才知道怎麼用,歡迎大家把自己的心得加入這份文件檔裡面,讓這份

文件檔更加的完整,日後有人要使用的話也就更加的方便了。

2 OpenCV libray Download && Install 下載與安裝 http://sourceforge.net/project/showfiles.php?group_id=22870 請下載網頁最下面的最新版本,然後安裝

安裝後會有 OpenCV 函式庫、程式範例及說明文件。

opencv-win beta5

OpenCV DIY 自學手冊 by NCKU CSIE VISION SYSTEM LAB

- 4 -

3 在 VC 6.0 下使用 OpenCV 編寫程式

3.1 Environment configuration 環境變數設定:

I. ALT + F7 打開 LINK 加入 cv.lib highgui.lib cxcore.lib

II. ToolsoptionDirectories 分頁的 Include files 加入 C:\Program Files\openCV\otherlibs\highgui C:\Program Files\openCV\cv\include C:\Program Files\openCV\cvaux\include C:\Program Files\openCV\cxcore\include C:\Program Files\openCV\bin

OpenCV DIY 自學手冊 by NCKU CSIE VISION SYSTEM LAB

- 5 -

III. ToolsoptionDirectories 分頁的 Lib 加入 C:\Program Files\openCV\lib C:\Program Files\openCV\bin

參考自:http://www.site.uottawa.ca/~laganier/tutorial/opencv+directshow/cvision.htm

OpenCV DIY 自學手冊 by NCKU CSIE VISION SYSTEM LAB

- 6 -

3.2 將 OpenCV 的動態連結 DLL 檔放進系統資料夾:

灌完 OpenCV 後,可以在 C:\Program Files\OpenCV\bin 找到執行 OpenCV 所需的動態連結函

式庫的 DLL 檔。將它全部複製到系統資料夾下 C:\WINDOWS\system32。

3.3 在程式碼中引入.h 檔: 若要在你的程式碼中使用 OpenCV 的 library,就在你程式碼的.h 或.cpp 檔引入下面的.h 檔: #include <cv.h> #include <highgui.h> #include <cxcore.h> 接下來編譯程式看會不會通過,如果通過了,恭禧你,你已經能在你的程式上使用 OpenCV囉!

OpenCV DIY 自學手冊 by NCKU CSIE VISION SYSTEM LAB

- 7 -

4 在 .Net 2005 VC++下使用 OpenCV 編寫程式 4.1 Environment configuration 環境變數設定:

I. Link lib 設定: 進入 menu 中的[Project]Property,展開 Linker 選單,進入 Input 選項,接著在 Additional Dependencies 填入加進的 lib-cv.lib highgui.lib cxcore.lib [註]:請注意左上角看你是使用 Debug 模式還是 Release 模式編譯,需各別設定。

II. Include 資料夾路徑加入專案設定:

進入 menu 中的[Tools]Options,展開 Projects and Solutions 選單,點選 VC++ Directories項目,然後看到標題為「Show directories for」的下拉式選單,選擇 Include files,加入

C:\Program Files\openCV\otherlibs\highgui C:\Program Files\openCV\cv\include C:\Program Files\openCV\cvaux\include C:\Program Files\openCV\cxcore\include

OpenCV DIY 自學手冊 by NCKU CSIE VISION SYSTEM LAB

- 8 -

C:\Program Files\openCV\bin

III. Lib 資料夾路徑加入專案設定:

進入 menu 中的[Tools]Options,展開 Projects and Solutions 選單,點選 VC++ Directories項目,然後看到標題為「Show directories for」的下拉式選單,選擇 Library files,加入

C:\Program Files\openCV\lib C:\Program Files\openCV\bin

OpenCV DIY 自學手冊 by NCKU CSIE VISION SYSTEM LAB

- 9 -

4.2 將 OpenCV 的動態連結 DLL 檔放進系統資料夾:

灌完 OpenCV 後,可以在 C:\Program Files\OpenCV\bin 找到執行 OpenCV 所需的動態連結函

式庫的 DLL 檔。將它全部複製到系統資料夾下 C:\WINDOWS\system32。

4.3 在程式碼中引入.h 檔: 若要在你的程式碼中使用 OpenCV 的 library,就在你程式碼的.h 或.cpp 檔引入下面的.h 檔: #include <cv.h> #include <highgui.h> #include <cxcore.h> 接下來編譯程式看會不會通過,如果通過了,恭禧你,你已經能在你的程式上使用 OpenCV囉!

OpenCV DIY 自學手冊 by NCKU CSIE VISION SYSTEM LAB

- 10 -

5 其他可用資源

5.1 如何用 openCV 實作出 Optical Flow http://ai.stanford.edu/~dstavens/cs223b/stavens_opencv_optical_flow.pdf

5.2 OpenCV Reference Manual http://cs.uccs.edu/~jhhollan/JHH/JHH_Spring04/CS584/OpenCV_References.html

5.3 OpenCV 的範例執行檔 在 C:\Program Files\OpenCV\samples\c 裡面有很多 OpenCV 的使用範例,示範各種常見的影像

處理函式,每個程式碼 (.c 檔案)都有對應的執行檔(.exe)。舉例來說,contour.c 對應到的執行檔

是 contour.exe 執行結果如下,這個程式碼展示的是各個程式對應的功能描述,以及執行的結果: • contour.c 從影像上抓取輪廓的功能。

• Camshift.c 把 RGB 轉換到 HSV 空間,在 HSV 空間上面追蹤物體

OpenCV DIY 自學手冊 by NCKU CSIE VISION SYSTEM LAB

- 11 -

注意 ! 要執行這些執行檔,如果沒有將動態連結 DLL 複製到作業系統的系統資料夾下,在這裡就需要

把 cv097.dll cxcore097.dll highgui097.dll 檔案放在和執行檔相同的目錄裡面。他們可以在 C:\Program Files\OpenCV\bin 裡面找到。

6 實用程式碼範例展示 6.1 讀取影像(BMP、JPEG)、:詳見 LoadImage 資料夾

6.2 使用 Gaussian Blur 濾鏡: 在所給的範例程式中,會有一個 Gaussian 效果的 button,下面為此 button 的函式內容。

void COpenCVView::OnBUTTONGaussianSmooth() { if(ifLoadFile) { // IPL_DEPTH_8U 是unsigned char 的意思, 3 是3 個channel 的意思 // cv_smoothed_image 的size 和cv_color_image一樣 IplImage* cv_smoothed_image = cvCreateImage( cvGetSize(cv_color_image), IPL_DEPTH_8U , 3 ); // 執行Guassian Smooth, Window Size 為5 cvSmooth(cv_color_image, cv_smoothed_image, CV_GAUSSIAN, 5 , 5); // 用一個window顯示出cv_smoothed_image 裡面的內容 cvNamedWindow("Smoothed Image", 1 ); cvShowImage("Smoothed Image", cv_smoothed_image); // 釋放cv_gray_image 的記憶體 cvReleaseImage(&cv_smoothed_image); } else MessageBox("Load Image File First!"); }

6.3 讀取及存取影像 Pixel 值: // 將影像二值化 (Threshold Image) for( int i=0; i<imgHeight; i++) for( int j=0; j<imgWidth; j++) { // 取得img座標的影像灰階值 intensity = cvRound(cvGetReal2D(img, i, j); if(intensity > 255) cvSetReal2D(cv_gray, i, j, 255); else if(intensity < 0) cvSetReal2D(cv_gray, i, j, 0); else cvSetReal2D(cv_gray, i, j, intensity); }

6.4 讀取 AVI 檔案:詳見 CaptureAVI 資料夾 參考網頁

OpenCV DIY 自學手冊 by NCKU CSIE VISION SYSTEM LAB

- 12 -

擷取影像資訊

• CvCapture* capture = cvCaptureFromAVI("infile.avi");

• IplImage* image = 0; • if(!cvGrabFrame(capture)){ // capture a frame

• printf("Could not grab a frame\n\7");

• exit(0);

• }

• image = cvRetrieveFrame(capture);

得到影片的資訊

frameH 是影片的長(Height)

frameW 是影片的寬(Width)

fps 是影片的 FrameRate

numFrames 是影片的 frame 總數

• int frameH = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

• int frameW = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);

• int fps = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FPS);

• int numFrames = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_COUNT);

如何擷取 第 frame number X 的 frame?

numFrames 由以上粗體的式子求得,表示這個 video 所有 frame 的總數

• cvSetCaptureProperty(capture, CV_CAP_PROP_POS_AVI_RATIO, (double) X / numFrames);

//接下來 Grab Frame

• if(!cvGrabFrame(capture)){ // capture a frame

• printf("Could not grab a frame\n\7");

• exit(0);

• }

• img = cvRetrieveFrame(capture);

OpenCV DIY 自學手冊 by NCKU CSIE VISION SYSTEM LAB

- 13 -

6.5 如何將 IplImage 型態的 image 轉換為 unsigned char 的形式供後續處

理? // 求得 image 的影像大小資訊 imgSize = cvGetSize(image); // 將 IplImage 型態的 image 轉換為 BYTE 的 image_rawdata BYTE *image_rawdata; cvGetImageRawData( image, ( BYTE** )&image_rawdata, 0, &imgSize ); // image 是 3 個 channel (RGB) image_rawdata 的大小為 Height * Width * 3 for(j = 0; j < imgSize.height ; j ++) for(i = 0; i < imgSize.width ; i ++)

{ // 取得第(i,j) pixel 的 R、G、B 值

B = image_rawdata[ (j * imgSize.width + i) * 3 + 2]; G = image_rawdata[(j * imgSize.width + i) * 3 + 1]; R = image_rawdata[(j * imgSize.width + i) * 3 + 0];

}

6.6 解 AX=B 的線性代數問題(SVD 分解)(使用 Stack 變數) 參考網頁 Matrix/vector operations

問題 :

123A=456

789

3B=2

1

如何用 OpenCV 求得 AX=B 的 X 解?

double va[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, }; double vb[] = {3, 2, 1}; double vx[3]; CvMat cvA, cvB, cvX;

OpenCV DIY 自學手冊 by NCKU CSIE VISION SYSTEM LAB

- 14 -

//利用 va 陣列 Initialize cvA 這個 3 x 3 的矩陣 cvInitMatHeader(&cvA, 3, 3, CV_64FC1, va);

//利用 vb 陣列 Initialize cvB 這個 3 x 1 的矩陣 cvInitMatHeader(&cvB, 3, 1, CV_64FC1, vb); //利用 vx 陣列 Initialize cvX 這個 3 x 1 的矩陣 cvInitMatHeader(&cvX, 3, 1, CV_64FC1, vx); //求得 cvX (cvA 乘以 cvX = cvB) //CV_SVD 表示用 SVD 分解來求,可置換為 CV_LU 用 LU 分解來求 cvSolve(&cvA, &cvB, &cvX, CV_SVD); //取得 cvX 裡面的值 //cvX 是 3 X 1 的矩陣 //cvGetReal2D(&cvX, row, column); 取得的是 cvX 裡面 (row,column)的 element double x[3]; x[0] = cvGetReal2D(&cvX, 0, 0); x[1] = cvGetReal2D(&cvX, 1, 0); x[2] = cvGetReal2D(&cvX, 2, 0);

6.7 解 AX=B 的線性代數問題(SVD 分解)(使用 Heap 變數) 此範列基本上跟 6.7 一樣,只是這次是用 Heap 變數再舉例一次,因為實際上遇到解線性代數的問題

常常會一開始不知道矩陣是幾乘幾,而常要用 Heap 變數配制記憶體(Stack 變數不能在初始化時宣告變數

長度的陣列,只能宣告常數長度的陣列;但 Heap 變數就可以。),下面是一個.net windows form 的範例,

由兩個函式組成 pictureBox1_MouseDown及 button1_Click前一個函式讓使用者在圖片 pictureBox1 上依序用

滑鼠畫幾個點,接下來一按 button1 後,會用一個近似圓 fit 所有這些點並且秀出來,讀者需注意 cvSolve代入變數的寫法跟前一個範例不同之處,關鍵在於Heap變數使用的是指標。(此方程解參考線代課本Least Square 部分): ArrayList^ testPoints; // testPoints = gcnew ArrayList();已經在建構子處配制記憶體

private: System::Void pictureBox1_MouseDown(System::Object^ sender, System::Windows::Forms::MouseEventArgs^

e) {

Graphics^ g = Graphics::FromImage(pictureBox1->Image);

Point tempPoint;

int x,y;

SolidBrush^ mySolidBrush2 = gcnew SolidBrush(Color::Lime);

int circleR = 2;

x = e->X;

OpenCV DIY 自學手冊 by NCKU CSIE VISION SYSTEM LAB

- 15 -

y = e->Y;

tempPoint = Point(x,y);

testPoints->Add(tempPoint);

g->FillEllipse(mySolidBrush2, x - circleR, y - circleR, circleR * 2, circleR * 2);

pictureBox1->Refresh();

}

private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {

int n = testPoints->Count;

CvMat* cvA = cvCreateMat( n, 3, CV_32FC1 );

CvMat* cvB = cvCreateMat( n, 1, CV_32FC1 );

CvMat* cvX = cvCreateMat( 3, 1, CV_32FC1 );

for(int i=0; i<n; i++)

{

cvSetReal2D(cvA, i, 0, 2.0*(float)((Point)testPoints[i]).X);

cvSetReal2D(cvA, i, 1, 2.0*(float)((Point)testPoints[i]).Y);

cvSetReal2D(cvA, i, 2, 1);

}

for(int i=0; i<n; i++)

cvSetReal2D(cvB, i, 0, pow((float)((Point)testPoints[i]).X, 2) +

pow((float)((Point)testPoints[i]).Y, 2));

cvSolve(cvA, cvB, cvX, CV_SVD);

double c1 = cvGetReal2D(cvX, 0, 0);

double c2 = cvGetReal2D(cvX, 1, 0);

double c3 = cvGetReal2D(cvX, 2, 0);

//Drawing the fitting circle

Graphics^ g = Graphics::FromImage(pictureBox1->Image);

int x,y;

Pen ^skyBluePen = gcnew Pen(Brushes::DeepSkyBlue);

int circleR = sqrt(c3 + pow(c1, 2) + pow(c2, 2));

x = c1;

y = c2;

g->DrawEllipse(skyBluePen, x - circleR, y - circleR, circleR * 2, circleR * 2);

pictureBox1->Refresh();

cvReleaseMat(&cvA);

cvReleaseMat(&cvB);

cvReleaseMat(&cvX);

}

OpenCV DIY 自學手冊 by NCKU CSIE VISION SYSTEM LAB

- 16 -

6.8 解 EigenValue,EigenVector 參考網頁 Matrix/vector operations

• Eigen analysis (of a symmetric matrix): • CvMat* A = cvCreateMat(3,3,CV_32FC1);

• CvMat* E = cvCreateMat(3,3,CV_32FC1);

• CvMat* l = cvCreateMat(3,1,CV_32FC1);

• cvEigenVV(&A, &E, &l); // l = eigenvalues of A (descending order)

• // E = corresponding eigenvectors (rows)

範例 CODE:

double va[] = { 1, 2, 3 4, 5, 6 7, 8, 9 }; double ve[9] ; double vl[3]; CvMat cvA, cvE, cvl; //利用 va 陣列 Initialize cvA 這個 3 x 3 的矩陣 cvInitMatHeader(&cvA, 3, 3, CV_64FC1, va);

//利用 ve 陣列 Initialize cvE 這個 3 x 3 的矩陣 cvInitMatHeader(&cvB, 3, 3, CV_64FC1, ve); //利用 vl 陣列 Initialize cvl 這個 3 x 1 的矩陣 cvInitMatHeader(&cvl, 3, 1, CV_64FC1, vx); //1. 求得 cvA 的 EigenVlue 存在 cvl 裡面 //2. 求得 cvA 的 Eigenvector 存在 cvE 裡面 (每個 row) cvEigenVV(&cvA, &cvE, &cvl); //************ 以下為取值 ************** //取得 第 1 大的 EigenValue 裡面的值 double first_eigenvalue = cvGetReal2D(&cvX, 0, 0); //取得 第 1 大的 EigenValue 對應之 EigenVector

OpenCV DIY 自學手冊 by NCKU CSIE VISION SYSTEM LAB

- 17 -

double first_eigenvector[3]; eigenvector [0] = cvGetReal2D(&cvE, 0, 0); eigenvector [1] = cvGetReal2D(&cvE, 0, 1); eigenvector [2] = cvGetReal2D(&cvE, 0, 2); //同理 如果要取得 第 2 大的 EigenValue 裡面的值 double second_eigenvalue = cvGetReal2D(&cvX, 1 ,0); //取得 第 2 大的 EigenValue 對應之 EigenVector double second_eigenvector[3]; second_eigenvector [0] = cvGetReal2D(&cvE, 1, 0); second_eigenvector [1] = cvGetReal2D(&cvE, 1, 1); second_eigenvector [2] = cvGetReal2D(&cvE, 1, 2);

OpenCV DIY 自學手冊 by NCKU CSIE VISION SYSTEM LAB

- 18 -

7 不要以為 OpenCV 是萬能的!-OpenCV 的 Trap 及 Bug

7.1 cvSolve 的陷阱 當使用者想用 cvSolve 去解 Least Square 的問題時,需特別注意解出來的 Matrix 中的 element 是否在理

論上會產生正負無窮大或無解的情形,如果會發生,則必需自己在設定方程式時讓解不致於產生正負

無窮大或無解的值,因為 OpenCV 不會為你做防範,它會預設給你一個錯誤的解,也不會通知你,讓

你怎麼被耍都不知道!

7.2 cvThreshold 的錯誤 前一陣子我發現,在 cvThreshold 的地方,它最後一個參數如果是代入 CV_THRESH_BINARY 跟 CV_THRESH_BINARY_INV 都是無效的,其他三種都還有效。我檢查很久,判斷這應該也是 OpenCV的 Bug。