EmguCV Image Process: Estimating Projective Relations in Images
參考OpenCV 2 Computer Vision Application Programming Cookbook第九章
介紹內容如下:
Calibrating a camera
Computing the fundamental matrix of an image pair
Matching images using random sample consensus
Computing a homography between two images
前一篇介紹透過chessboard來做影像的矯正(calibrate)
這裡要透過兩張不同角度,或是不同攝影機拍攝的兩張同主題的影像
透過數學的計算求出fundamental matrix
再利用fundamental matrix畫出epipolar line
這之間的原理相當複雜
有興趣的朋友可以參考這篇寫得非常詳細
簡單來說
就是利用一個fundamental matrix的運算
就可以把第一張影像的某個點,映射到第二張影像的對應點上
而影像上的特徵點在上一個章節有介紹過
這次一樣利用SURF擷取所要的特徵點
並將特徵點做一個轉換
Image<Gray, Byte> Image1 = new Image<Gray, byte>("image1.jpg"); Image<Gray, Byte> Image2 = new Image<Gray, byte>("image2.jpg"); //Construct the SURF feature detector object SURFDetector surf = new SURFDetector( 5000, //threshold false); //extended descriptors //Detect the SURF features VectorOfKeyPoint image1Keypoints = surf.DetectKeyPointsRaw(Image1, null); VectorOfKeyPoint image2Keypoints = surf.DetectKeyPointsRaw(Image2, null); //Convert keypoints into matrix int count = image2Keypoints.Size; Matrix<float> selPoints1 = ConvertToMatrix(image1Keypoints, count); Matrix<float> selPoints2 = ConvertToMatrix(image2Keypoints, count);取得的特徵點後
透過ConvertToMatrix這麼方法把VectorOfKeyPoint轉成Matrix<float>
方法如下:
Matrix<float> ConvertToMatrix(VectorOfKeyPoint keypoints, int count) { Matrix<float> result = new Matrix<float>(count, 2); for (int i = 0; i < count; i++) { float x = keypoints[i].Point.X; float y = keypoints[i].Point.Y; result[i, 0] = x; result[i, 1] = y; } return result; }這裡要注意的是
兩張影像取出的特徵點若是不一樣多
之後帶入求fundamental matrix會有問題
因此ConvertToMatrix方法帶入的count必須一致
所以先判斷是第一張影像的特徵點多,還是第二張的特徵點多
並以少的特徵點的數量作為基準
Matrix<float> fundamentalMatrix = new Matrix<float>(3, 3); IntPtr status = CvInvoke.cvCreateMat(1, count, MAT_DEPTH.CV_8U); //Compute F matrix from 7 matches CvInvoke.cvFindFundamentalMat( selPoints1, //points in first image selPoints2, //points in second image fundamentalMatrix, //fundamental matrix CV_FM.CV_FM_7POINT, //7-point method 3.0, //Use 3.0 for default. The parameter is used for RANSAC method only. 0.99, //Use 0.99 for default. The parameter is used for RANSAC or LMedS methods only. status);//The array is computed only in RANSAC and LMedS methods. //lines in right image Matrix<float> lines = new Matrix<float>(count, 3); CvInvoke.cvComputeCorrespondEpilines( selPoints1, //image points 1, //in image 1 fundamentalMatrix, //fundamental matrix lines); //epipolar lines帶入CvInvoke.cvFindFundamentalMat方法求出fundamental matrix
這裡注意是帶入第一張影像的特徵點
最後兩個參數就以預設值3.0以及0.99帶入
最後再透過CvInvoke.cvComputeCorrespondEpilines
取得epipolar line
這裡的lines是一個N*3的矩陣,N表示特徵點的數量
接著再把epipolar line畫在第二張的影像上
//draw the left points corresponding epipolar for all epipolar lines for (int i = 0; i < count; i++) { //draw the line between first and last column Point p1 = new Point(0, -(int)(lines[i,2]/lines[i,1])); Point p2 = new Point(Image2.Width, -(int)((lines[i,2]+lines[i,0]*Image2.Width)/lines[i,1])); LineSegment2D line = new LineSegment2D(p1, p2); Image2.Draw(line, new Gray(255), 1); }利用一個for迴圈把所有的line畫上去
這裡epipolar line的點的算法要注意一下
計算方式非常特別
畫完的結果如下:
epipolar lines
那其實計算出來的結果應該是不太準
因為這兩張影像本是同一張影像
所以還是要挑選一下兩張影像的狀況會比較適合
下一篇將介紹如何利用random sample consensus來做影像特徵點配對~!
沒有留言:
張貼留言