基于ORB的图像矫正

单应性矩阵

在二维平面上,平面的单应性被定义为从一个平面到另一个平面的投影映射,就像我们拍一张照片时,从我们眼前的点一一映射到摄像机内部一样。英文学名叫做homography(单应性,ps:下面的鲁棒性就是稳定性。

下即为一个简单的3x3homo矩阵

\left[ \begin{matrix} h00 & h01 & h02 \ h10 & h11 & h12 \ h20 & h21 & h22 \end{matrix} \right ] \tag{1}

其平面坐标变换对应为(原坐标为(x1,y1),其变换为(x2,y2)):

[x1 y1 1]=H[x2 y2 1]=[h00h01h02 h10h11h12 h20h21h22][x2 y2 1]\left[ \begin{array}{c} x_1 \ y_1 \ 1 \end{array} \right] = H \left[ \begin{array}{c} x_2 \ y_2 \ 1 \end{array} \right] = \left[ \begin{array}{ccc} h{00} & h{01} & h{02} \ h{10} & h{11} & h{12} \ h{20} & h{21} & h_{22} \end{array} \right] \left[ \begin{array}{c} x_2 \ y_2 \ 1 \end{array} \right]

下图为变换的例子

alt

在OpenCV里面,单应矩阵的计算函数为 :

Mat findHomography(inputArray points1,inputArray points2,int method)

. 参数一为输入的x1,y1 点集

. 参数二为输入的 x2,y2 点集

. 参数三为计算方法:0 - 使用所有点的常规方法 RANSAC - 基于RANSAC的鲁棒方法 LMEDS - 最小中值稳健方法 RHO - 基于PROSAC的鲁棒方法

#关键点检测

上篇里有介绍基于ORB的关键点检测,舒服的是这个算法是至今最好最快的算法,其他的检测算法还有SURF,SIFT,etc….算法,效率而讲,500点一下还是差不多的,但是点越多的话ORB绝对胜出。

#关键点匹配
上篇的文章依然用着老的api,但是编译了最新的3.4之后api又发生了变化(mmp),这次能直接detect 和compute一起用了。

其用到头文件 xfeatures2d/nonfree.hpp

命名空间 cv::xfeatures2d

检测器创建如下,只能处理灰度图像

1
Ptr<Feature2D> orb = ORB::create(MAX_FEATURES);//智能指针传参为最大检测点数

图像矫正如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d/nonfree.hpp>
#include <opencv2/features2d.hpp>


using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;


const int MAX_FEATURES = 500;
const float GOOD_MATCH_PERCENT = 0.15f;

void alignImage(Mat& img1, Mat& img2, Mat& dst, Mat h)
{
Mat img1Gray, img2Gray;//灰度图
cvtColor(img1, img1Gray, COLOR_BGR2GRAY);
cvtColor(img2, img2Gray, COLOR_BGR2GRAY);//灰度处理

vector<KeyPoint> keypoints1, keypoints2;//图1 关键点 图2 关键点
Mat descriptors1, descriptors2;
Ptr<Feature2D> orb = ORB::create(MAX_FEATURES);

orb->detectAndCompute(img1Gray, Mat(), keypoints1, descriptors1);//检测匹配

orb->detectAndCompute(img2Gray, Mat(), keypoints2, descriptors2);//检测匹配

vector<DMatch> matches;
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");

matcher->match(descriptors1, descriptors2, matches, Mat());//匹配描线

sort(matches.begin(), matches.end());//排序筛选优好的点

const int numGoodMatches = matches.size()*GOOD_MATCH_PERCENT;

matches.erase(matches.begin() + numGoodMatches, matches.end());

Mat imMatches;

drawMatches(img1, keypoints1, img2, keypoints2, matches, imMatches);
imshow("match", imMatches);
imwrite("F:\\match.jpg", imMatches);
vector<Point2f> points1, points2;
for (auto x : matches)
{
points1.push_back(keypoints1[x.queryIdx].pt);
points2.push_back(keypoints2[x.trainIdx].pt);
}

h = findHomography(points1, points2, RANSAC);
warpPerspective(img1, dst, h, img2.size());//旋转矫正

}


int main()
{
string refFilename="F:\\picture\\src.jpg";//原图路径

Mat src = imread(refFilename);
string scanFilename = "F:\\picture\\scanned.jpg";//扫描的或者电子版的图
Mat scan_src = imread(scanFilename);

Mat imageRege, homo;//完成图像 和 homo矩阵
alignImage(src, scan_src, imageRege, homo);
cout << homo << endl;
imshow("dst", imageRege);
imwrite("F:\\change.jpg", imageRege);
waitKey();

}