Upload
others
View
21
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。