平面对象的匹配与识别:
在日常生活中,我们接触的照片经常会因为角度或者方向的问题,而导致图像中的文字倾斜或者角度偏转。
透视变换(Perspective Transformation)可以将图片进行校正。也可以通过透视变换进行图像的平面识别;
主要是两个API:
代码演示:
1 #include <opencv2/opencv.hpp> 2 #include <opencv2/xfeatures2d.hpp> 3 #include <iostream> 4 #include <math.h> 5 6 using namespace cv; 7 using namespace std; 8 using namespace cv::xfeatures2d; 9 10 int main(int argc, char** argv) { 11 Mat img1 = imread("L:/opencv_picture/book1.jpg", IMREAD_GRAYSCALE); 12 Mat img2 = imread("L:/opencv_picture/book2.jpg", IMREAD_GRAYSCALE); 13 if (!img1.data || !img2.data) { 14 return -1; 15 } 16 imshow("object image", img1); 17 imshow("object in scene", img2); 18 19 // surf featurs extraction 20 int minHessian = 400; 21 Ptr<SURF> detector = SURF::create(minHessian); 22 vector<KeyPoint> keypoints_obj; 23 vector<KeyPoint> keypoints_scene; 24 Mat descriptor_obj, descriptor_scene; 25 detector->detectAndCompute(img1, Mat(), keypoints_obj, descriptor_obj); 26 detector->detectAndCompute(img2, Mat(), keypoints_scene, descriptor_scene); 27 28 // matching 29 FlannBasedMatcher matcher; 30 vector<DMatch> matches; 31 matcher.match(descriptor_obj, descriptor_scene, matches); 32 33 // find good matched points 34 double minDist = 1000; 35 double maxDist = 0; 36 for (int i = 0; i < descriptor_obj.rows; i++) { 37 double dist = matches[i].distance; 38 if (dist > maxDist) { 39 maxDist = dist; 40 } 41 if (dist < minDist) { 42 minDist = dist; 43 } 44 } 45 printf("max distance : %f\n", maxDist); 46 printf("min distance : %f\n", minDist); 47 vector<DMatch> goodMatches; 48 for (int i = 0; i < descriptor_obj.rows; i++) { 49 double dist = matches[i].distance; 50 if (dist < max(3 * minDist, 0.02)) { 51 goodMatches.push_back(matches[i]); 52 } 53 } 54 55 Mat matchesImg; 56 drawMatches(img1, keypoints_obj, img2, keypoints_scene, goodMatches, matchesImg, Scalar::all(-1), 57 Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS 58 ); 59 //以上代码参考上一节内容:FLANN特征点匹配 60 vector<Point2f> obj; 61 vector<Point2f> objInScene; 62 for (size_t t = 0; t < goodMatches.size(); t++) { 63 obj.push_back(keypoints_obj[goodMatches[t].queryIdx].pt); 64 //将keypoints_obj中goodMatches[t]中的queryIdx参数(左图索引)用指针.pt分别压入堆栈obj中 65 objInScene.push_back(keypoints_scene[goodMatches[t].trainIdx].pt); 66 //将keypoints_scene中goodMatches[t]中的trainIdx参数(右图索引)用指针.pt分别压入堆栈objScene中 67 } 68 Mat H = findHomography(obj, objInScene, RANSAC); 69 //findHomography函数:计算多个二维点对之间的最优单映射变换矩阵 H 70 //第三个参数:0 - 利用所有点的常规方法 RANSAC - 基于RANSAC的鲁棒算法 71 // LMEDS - 最小中值鲁棒算法 RHO - 基于PROSAC的鲁棒算法 72 73 vector<Point2f> obj_corners(4); //图一矩形四个顶点 74 vector<Point2f> scene_corners(4); //在图二中经过变换后的图一的四个顶点 75 obj_corners[0] = Point(0, 0); 76 obj_corners[1] = Point(img1.cols, 0); 77 obj_corners[2] = Point(img1.cols, img1.rows); 78 obj_corners[3] = Point(0, img1.rows); 79 perspectiveTransform(obj_corners, scene_corners, H); //开始变换 80 //perspectiveTransform函数采用H变换,将图一的四个顶点变换到图2中也就是scene_corners 81 82 // draw line (每个点都要加上图1的横坐标,以为两张图一起显示) 83 line(matchesImg, scene_corners[0] + Point2f(img1.cols, 0), scene_corners[1] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0); 84 line(matchesImg, scene_corners[1] + Point2f(img1.cols, 0), scene_corners[2] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0); 85 line(matchesImg, scene_corners[2] + Point2f(img1.cols, 0), scene_corners[3] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0); 86 line(matchesImg, scene_corners[3] + Point2f(img1.cols, 0), scene_corners[0] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0); 87 88 //仅在dst原图(图二)上画出目标图像 89 Mat dst; 90 cvtColor(img2, dst, COLOR_GRAY2BGR); 91 line(dst, scene_corners[0], scene_corners[1], Scalar(0, 0, 255), 2, 8, 0); 92 line(dst, scene_corners[1], scene_corners[2], Scalar(0, 0, 255), 2, 8, 0); 93 line(dst, scene_corners[2], scene_corners[3], Scalar(0, 0, 255), 2, 8, 0); 94 line(dst, scene_corners[3], scene_corners[0], Scalar(0, 0, 255), 2, 8, 0); 95 96 imshow("find known object demo", matchesImg); 97 imshow("Draw object", dst); 98 99 waitKey(0); 100 return 0; 101 }
效果图: