在通過SIFT、SURF或者ORB進行特徵點檢測,生成了特徵點和特徵點描述子的vector後,如何進一步的進行對於圖像的矯正。這個時候就用到了opencv的另外兩個函數findHomography和perspectiveTransform。
findHomography是用來計算兩張圖像的單應性矩陣的。opencv的官方文檔中有詳細的使用說明:
前兩個參數分別是通過之前的特徵檢測找到的特徵點,第三個參數爲計算單應性矩陣的方法,默認爲使用所有的點。第四個參數僅在第三個參數爲CV_RANSAC時使用,爲最大允許的特徵點對間二次投影的誤差。
perspectiveTransform函數爲通過單應性矩陣生成校正之後的圖像。
前兩個參數爲原始圖像和矯正之後的圖像的點的集合。只能爲2維或3維的向量。這裏的點的集合指的是圖像的位置排布,和像素值沒有任何關係。第三個參數即爲之前求出的單應性矩陣。
注意:生成的矯正圖像爲點的集合,即爲vector向量,並不是圖像,生成的只是原始圖像與校正圖像的位置對應關係,圖像的生成在下面的例子中會說明。
示例:
int main()
{
Mat img_1 = imread("00068.jpg");
Mat img_2 = imread("00069.jpg");
if (!img_1.data || !img_2.data)
{
cout << "error reading images " << endl;
return -1;
}
ORB orb;
vector<KeyPoint> keyPoints_1, keyPoints_2;
Mat descriptors_1, descriptors_2;
orb(img_1, Mat(), keyPoints_1, descriptors_1);
orb(img_2, Mat(), keyPoints_2, descriptors_2);
BruteForceMatcher<HammingLUT> matcher;
vector<DMatch> matches;
matcher.match(descriptors_1, descriptors_2, matches);
double max_dist = 0; double min_dist = 100;
//-- Quick calculation of max and min distances between keypoints
for( int i = 0; i < descriptors_1.rows; i++ )
{
double dist = matches[i].distance;
if( dist < min_dist ) min_dist = dist;
if( dist > max_dist ) max_dist = dist;
}
printf("-- Max dist : %f \n", max_dist );
printf("-- Min dist : %f \n", min_dist );
//-- Draw only "good" matches (i.e. whose distance is less than 0.6*max_dist )
//-- PS.- radiusMatch can also be used here.
std::vector< DMatch > good_matches;
vector<Point2f> leftPoint,rightPoint;
for( int i = 0; i < descriptors_1.rows; i++ )
{
if( matches[i].distance < 0.6*max_dist )
{
good_matches.push_back( matches[i]);
leftPoint.push_back(keyPoints_1[matches[i].queryIdx].pt);//保存左圖像的關鍵點
rightPoint.push_back(keyPoints_2[matches[i].trainIdx].pt);//保存右圖像的關鍵點
}
}
Mat Homography = findHomography(leftPoint,rightPoint,CV_RANSAC,3);//生成單應性矩陣
cout<<Homography<<endl;
vector<Point2f> CorrectImg;//根據單應性矩陣校正之後的點
vector<Point2f> ponits;//保存圖像的所有的點
for(int i=0;i<img_1.rows;i++)
{
for(int j=0;j<img_2.cols;j++)
{
ponits.push_back(Point2f(j,i));
}
}
perspectiveTransform(ponits,CorrectImg,Homography);//生成對應關係
imshow("left",img_1);
imshow("right",img_2);
Mat img_trans = Mat::zeros(img_1.rows,img_1.cols,CV_8UC3); //矯正後的圖像
int count = 0;
for(int i=0;i<img_1.rows;i++)
{
uchar* p = img_1.ptr<uchar>(i);
for(int j=0;j<img_1.cols;j++)
{
int y = CorrectImg[count].y;
int x = CorrectImg[count].x;
if (y < 0 || x < 0 || x >= img_1.cols || y >= img_1.rows)
{
count++;
continue;
}
uchar* t = img_trans.ptr<uchar>(y);
t[x*3] = p[j*3];
t[x*3+1] = p[j*3+1];
t[x*3+2] = p[j*3+2];
count++;
}
}
imshow("CorrectImg",img_trans);
waitKey();
return 0;
}