对象形变与位置变换
待检测图像样本一般与检测样本中的实际状态在形态学上会有不同,例如一本书会发生扭曲。可以通过以下函数进行校正对应
- findHomography 发现两个平面的透视变换,生成变换矩阵
- perspectiveTransform 透视变换
代码演示
#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <iostream>
#include <math.h>
using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;
#define PIC_PATH "/work/opencv_pic/"
#define PIC_NAME "main.jpeg"
#define PIC_PATH1 "/work/opencv_pic/"
#define PIC_NAME1 "sub.jpeg"
int main(void)
{
Mat src,src1;
//获取完整的图片路径及名称
string pic = string(PIC_PATH1)+string(PIC_NAME1);
string pic1 = string(PIC_PATH)+string(PIC_NAME);
//打印图片路径
cout << "pic path is :"<<pic<<endl;
cout << "pic1 path is :"<<pic1<<endl;
//读取图片
src = imread(pic,IMREAD_GRAYSCALE);
src1 = imread(pic1,IMREAD_GRAYSCALE);
//判断图片是否存在
if(src.empty() || src1.empty())
{
cout<<"pic is not exist!!!!"<<endl;
return -1;
}
//显示图片
namedWindow("src pic",WINDOW_AUTOSIZE);
imshow("src pic",src);
namedWindow("src1 pic",WINDOW_AUTOSIZE);
imshow("src1 pic",src1);
int minHessian = 400;
vector<KeyPoint> keypoint1,keypoint2; //描述子
Mat descriptor1,descriptor2; //描述图像
Ptr<SURF> detector = SURF::create(minHessian); //创建SURF对象
//计算特征值
detector->detectAndCompute(src,Mat(),keypoint1,descriptor1);
detector->detectAndCompute(src1,Mat(),keypoint2,descriptor2);
//BFMatcher matcher;
FlannBasedMatcher matcher; //Flann匹配器
vector<DMatch> matches; //匹配数据
matcher.match(descriptor1,descriptor2,matches); //描述匹配 将匹配结果存放至matches
//flann匹配基于距离匹配 进行最优距离查找
float maxdist = 3;
float mindist = 100;
//通过逐步收敛的办法查找到最大值最小值
for(int i=0;i<descriptor1.rows;i++)
{
float distance = matches[i].distance;
distance*=100;
cout<<"distance: "<<distance<<endl;
if(distance>maxdist)
maxdist = distance;
if(distance<mindist)
mindist = distance;
}
//将最大值 最小值打印出来
cout<<"maxdist: "<<maxdist<<endl;
cout<<"mindist: "<<mindist<<endl;
vector<DMatch> goodmatches; //定义最优的距离点集合
for(int i=0;i<descriptor1.rows;i++)
{
float distance = matches[i].distance;
if(distance*100<=2*mindist)
{
//将查找到的最小距离添加到goodmatches中
goodmatches.push_back(matches[i]);
}
}
Mat matchimages;
//绘制匹配点 点数大大减少
drawMatches(src,keypoint1,src1,keypoint2,goodmatches,matchimages);
//获取坐标点
vector<Point2f> sub,main;
for(size_t i=0;i<goodmatches.size();i++)
{
//通过goodmatches的queryIdx索引值获取 对应子图像keypoint点的坐标
sub.push_back(keypoint1[goodmatches[i].queryIdx].pt);
//通过goodmatches的queryIdx索引值获取 对应目标图像trainIdx点的坐标
main.push_back(keypoint2[goodmatches[i].trainIdx].pt);
}
//通过两者坐标对应关系获得目标变换矩阵
Mat H =findHomography(sub,main,RANSAC);
//定义方框轮廓
vector<Point2f> sub_corners(4);
vector<Point2f> main_corners(4);
//待检测图像轮廓已知
sub_corners[0] = Point(0,0);
sub_corners[1] = Point(src.cols,0);
sub_corners[2] = Point(src.cols,src.rows);
sub_corners[3] = Point(0,src.rows);
//通过待检测图像的轮廓以及透视变换矩阵 计算 待检测图像中目标矩形位置
perspectiveTransform(sub_corners,main_corners,H);
//绘制矩形框 这里加Point2f(src.cols,0) 主要是matchimages显示图像为两者叠加图片宽度有变化
line(matchimages,main_corners[0]+Point2f(src.cols,0),main_corners[1]+Point2f(src.cols,0),Scalar(0,0,255),3);
line(matchimages,main_corners[1]+Point2f(src.cols,0),main_corners[2]+Point2f(src.cols,0),Scalar(0,0,255),3);
line(matchimages,main_corners[2]+Point2f(src.cols,0),main_corners[3]+Point2f(src.cols,0),Scalar(0,0,255),3);
line(matchimages,main_corners[3]+Point2f(src.cols,0),main_corners[0]+Point2f(src.cols,0),Scalar(0,0,255),3);
//显示图片
imshow("matchImages",matchimages);
waitKey(0);
destroyAllWindows();
return 0;
}
代码演示效果
由于图片是截取出来的,并没有明显效果