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
上一篇取出了兩張不同角度影像的特徵值
這次利用所取出的特徵值來做homography
中文在維基翻譯作:單應性
說實在的看到這個詞根本不知道到底是什麼意思
維基中解釋:
單應性是一個從實射影平面到射影平面的可逆變換,直線在該變換下仍映射為直線
而這裡的目的就是將兩張不同角度的影像
使其中一張的平面射影到另一張的平面
進而接合這兩張不同角度的影像
接續前一篇所寫的RobustMatcher
這裡的實作不需要進行RANSAC這個方法
因為這個方法會在homography中被實作
因此我們在RobustMatcher中新增一個方法Homography
所需的引數就跟RANSACTest的方法一樣
void Homography(Matrix<float> matches, VectorOfKeyPoint keyPoints1, VectorOfKeyPoint keyPoints2, int matchesNumber, Image<Gray, Byte> image1, Image<Gray, Byte> image2) { Matrix<float> selPoints1 = new Matrix<float>(matchesNumber, 2); Matrix<float> selPoints2 = new Matrix<float>(matchesNumber, 2); int selPointsIndex = 0; for (int i = 0; i < matches.Rows; i++) { if (matches[i, 0] == 0 && matches[i, 1] == 0) { continue; } //Get the position of left keypoints float x = keyPoints1[(int)matches[i, 0]].Point.X; float y = keyPoints1[(int)matches[i, 0]].Point.Y; selPoints1[selPointsIndex, 0] = x; selPoints1[selPointsIndex, 1] = y; //Get the position of right keypoints x = keyPoints2[(int)matches[i, 1]].Point.X; y = keyPoints2[(int)matches[i, 1]].Point.Y; selPoints2[selPointsIndex, 0] = x; selPoints2[selPointsIndex, 1] = y; selPointsIndex++; } ... }前面的程式與RANSACTest一樣
透過for loop把真正需要的key points取出,存到selPoints1、selPoints1中
這裡我們試著把selPoints1與selPoints2分別畫到兩張影像上
那由於之前是直拍影像
不適合用來此主題,因此這次使用兩張橫向影像如下所示:
一張影像偏左
一張影像偏右
因為桌面剛好有這兩瓶物件,就直接利用拍攝
打上key points的結果如下:
第一張(image1)影像的key points
第二張(image2)影像的key points
接著我們要找出這兩張影像的homography
Matrix<float> homography = new Matrix<float>(3, 3); //Find the homography between image 1 and image 2 CvInvoke.cvFindHomography( selPoints2, //corresponding selPoints1, //points homography, //homography HOMOGRAPHY_METHOD.RANSAC, //RANSAC method 1, // max distance to reprojection point IntPtr.Zero); //mask in null
使用的方法很簡單
先建立一個3X3的Matrix
然後把key points、homography matrix帶入、
方法設定為HOMOGRAPHY_METHOD.RANSAC、
不使用mask
結果就會回存到homography之中
這裡要注意一點就是key points帶入的順序
第一組key points是用來當作source
第二組kry points是用來當作destination
意思就是說:
將第一組key points的所屬平面影像投射到第二組key points的平面影像上
在這邊的實作也就是說
把第二張影像經過homography過後會得到與第一張影像同視角的影像
此時利用cvWarpPerspective方法
//Warp image 2 to image 1 Image<Gray, Byte> result = new Image<Gray, byte>(image1.Width*2, image1.Height); CvInvoke.cvWarpPerspective( image2, result, homography, (int)Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR, new MCvScalar());將第二張影像做homography投影後
並把結果存在result上
帶入homography matrix
設定其變形的方法為:INTER.CV_INTER_LINEAR
擴充的元素填入new MCvScalar()
(也就是黑色)
所得結果如下:
可以和原始的第二張影像對比一下
會發現視角的呈現略有不同
右側隔板被矯正拉直
由於這是利用第二張影像的key points去修正成第一張影像的視角
所以會發現這張處理後的影像的左邊留有一塊黑邊
而兩個物件的位置似乎與第一張影像雷同
因此在第一張影像套用在這張上
結果就會變成:
經過上下比對
你會發現物件的位置相當準確喔!!
只是因為視角的關係
在正中間的接縫中還是有些地方怪怪的
但你整體上看起來
在桌腳、隔板的角度等等
是不是很自然呢!?
當然你也可以手動嘗試兩張影像的接合
就會如下:
這樣比對的話,是不是就能看出其中的差異了呢!!
Homography完整程式:(result就是結果)
void Homography(Matrix<float> matches, VectorOfKeyPoint keyPoints1, VectorOfKeyPoint keyPoints2, int matchesNumber, Image<Gray, Byte> image1, Image<Gray, Byte> image2) { Matrix<float> selPoints1 = new Matrix<float>(matchesNumber, 2); Matrix<float> selPoints2 = new Matrix<float>(matchesNumber, 2); int selPointsIndex = 0; for (int i = 0; i < matches.Rows; i++) { if (matches[i, 0] == 0 && matches[i, 1] == 0) { continue; } //Get the position of left keypoints float x = keyPoints1[(int)matches[i, 0]].Point.X; float y = keyPoints1[(int)matches[i, 0]].Point.Y; selPoints1[selPointsIndex, 0] = x; selPoints1[selPointsIndex, 1] = y; //Get the position of right keypoints x = keyPoints2[(int)matches[i, 1]].Point.X; y = keyPoints2[(int)matches[i, 1]].Point.Y; selPoints2[selPointsIndex, 0] = x; selPoints2[selPointsIndex, 1] = y; selPointsIndex++; } Matrixhomography = new Matrix (3, 3); //Find the homography between image 1 and image 2 CvInvoke.cvFindHomography( selPoints2, //corresponding selPoints1, //points homography, //homography HOMOGRAPHY_METHOD.RANSAC, //RANSAC method 1, // max distance to reprojection point IntPtr.Zero); //mask in null //Warp image 2 to image 1 Image result = new Image (image1.Width*2, image1.Height); CvInvoke.cvWarpPerspective( image2, result, homography, (int)Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR, new MCvScalar()); }
將上一節的RobustMatcher類別中Match的方法,最後一行
Matrix<float> fundementalMatrix = RANSACTest(symMatches, keypoints1, keypoints2, symNumber, image1, image2);
換成Homography的方法即可
Homography(symMatches, keypoints1, keypoints2, symNumber, image1, image2);
Homography方法裡面最後的Image
沒有留言:
張貼留言