仿射变换和SURF特征点匹配
来源:互联网 发布:angularjs.js 2.0下载 编辑:程序博客网 时间:2024/05/16 06:31
一、仿射变换
1.1、仿射变换简介
仿射变换(Affine Transformation)是空间直角坐标系的变换,从一个二维坐标变换到另一个二维坐标,仿射变换是一个线性变换,他保持了图像的“平行性”和“平直性”,即图像中原来的直线和平行线,变换后仍然保持原来的直线和平行线,仿射变换比较常用的特殊变换有平移(Translation)、缩放(Scale)、翻转(Flip)、旋转(Rotation)和剪切(Shear)。一个任意的仿射变换都能表示为乘以一个矩阵(线性变换)接着再加上一个向量(平移)的形式。
在进行仿射变换的关键在于求解放射矩阵M,通过其对原图像进行变换得到最后的目标图像。在OpenCV中,与仿射变换相关的函数一般涉及到warpAffine( )和getRotationMatrix2D( )这两个。下面对这两个函数进行解析。
1.2、warpAffine( )函数解析
在OpenCV中,函数warpAffine( )是来实现一些简单的重映射。它是依据下式对图像做仿射变换。
void warpAffine(InputArray src, OutputArray dst, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())
参数解析:
第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。
第二个参数,OutputArray类型的dst,函数调用后的运算结果存在这里,需和源图片有一样的尺寸和类型。
第三个参数,InputArray类型的M,2×3的变换矩阵。
第四个参数,Size类型的dsize,表示输出图像的尺寸。
第五个参数,int类型的flags,插值方法的标识符。此参数有默认值INTER_LINEAR(线性插值),可选的插值方式如下:
INTER_NEAREST - 最近邻插值
INTER_LINEAR - 线性插值(默认值)
INTER_AREA - 区域插值
INTER_CUBIC –三次样条插值
INTER_LANCZOS4 -Lanczos插值
CV_WARP_FILL_OUTLIERS - 填充所有输出图像的象素。如果部分象素落在输入图像的边界外,那么它们的值设定为 fillval。
CV_WARP_INVERSE_MAP –表示M为输出图像到输入图像的反变换,即 。因此可以直接用来做象素插值。否则, warpAffine函数从M矩阵得到反变换。
第六个参数,int类型的borderMode,边界像素模式,默认值为BORDER_CONSTANT。
第七个参数,const Scalar&类型的borderValue,在恒定的边界情况下取的值,默认值为Scalar(),即0。
1.3、getRotationMatrix2D( )函数
getRotationMatrix2D( )函数是用来计算二维旋转的变换矩阵。
Mat getRotationMatrix2D(Point2fcenter, double angle, double scale)
第一个参数,Point2f类型的center,表示源图像的旋转中心。
第二个参数,double类型的angle,旋转角度。角度为正值表示向逆时针旋转(坐标原点是左上角)。
第三个参数,double类型的scale,缩放系数。
1.4、仿射变换实例
1、代码
#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> using namespace cv;using namespace std;#define WINDOW_NAME1 "【原始图窗口】" //为窗口标题定义的宏 #define WINDOW_NAME2 "【经过Warp后的图像】" //为窗口标题定义的宏 #define WINDOW_NAME3 "【经过Warp和Rotate后的图像】" //为窗口标题定义的宏 int main(){ //【0】改变console字体颜色 system("color 1A"); //【1】参数准备 //定义两组点,代表两个三角形 Point2f srcTriangle[3]; Point2f dstTriangle[3]; //定义一些Mat变量 Mat rotMat(2, 3, CV_32FC1); Mat warpMat(2, 3, CV_32FC1); Mat srcImage, dstImage_warp, dstImage_warp_rotate; //【2】加载源图像并作一些初始化 srcImage = imread("1.jpg", 1); if (!srcImage.data) { printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! \n"); return false; } // 设置目标图像的大小和类型与源图像一致 dstImage_warp = Mat::zeros(srcImage.rows, srcImage.cols, srcImage.type()); //【3】设置源图像和目标图像上的三组点以计算仿射变换 srcTriangle[0] = Point2f(0, 0); srcTriangle[1] = Point2f(static_cast<float>(srcImage.cols - 1), 0); srcTriangle[2] = Point2f(0, static_cast<float>(srcImage.rows - 1)); dstTriangle[0] = Point2f(static_cast<float>(srcImage.cols*0.0), static_cast<float>(srcImage.rows*0.33)); dstTriangle[1] = Point2f(static_cast<float>(srcImage.cols*0.65), static_cast<float>(srcImage.rows*0.35)); dstTriangle[2] = Point2f(static_cast<float>(srcImage.cols*0.15), static_cast<float>(srcImage.rows*0.6)); //【4】求得仿射变换 warpMat = getAffineTransform(srcTriangle, dstTriangle); //【5】对源图像应用刚刚求得的仿射变换 warpAffine(srcImage, dstImage_warp, warpMat, dstImage_warp.size()); //【6】对图像进行缩放后再旋转 // 计算绕图像中点顺时针旋转50度缩放因子为0.6的旋转矩阵 Point center = Point(dstImage_warp.cols / 2, dstImage_warp.rows / 2); double angle = -30.0; double scale = 0.8; // 通过上面的旋转细节信息求得旋转矩阵 rotMat = getRotationMatrix2D(center, angle, scale); // 旋转已缩放后的图像 warpAffine(dstImage_warp, dstImage_warp_rotate, rotMat, dstImage_warp.size()); //【7】显示结果 imshow(WINDOW_NAME1, srcImage); imshow(WINDOW_NAME2, dstImage_warp); imshow(WINDOW_NAME3, dstImage_warp_rotate); // 等待用户按任意按键退出程序 waitKey(0); return 0;}
2、运行结果
(1)原图片
void drawMatches(const Mat& img1, constvector<KeyPoint>& keypoints1, const Mat& img2, constvector<KeyPoint>& keypoints2, constvector<DMatch>& matches1to2, Mat& outImg, const Scalar&matchColor=Scalar::all(-1), const Scalar&singlePointColor=Scalar::all(-1), const vector<char>&matchesMask=vector<char>(), intflags=DrawMatchesFlags::DEFAULT )
第一个参数,const Mat&类型的img1,第一幅源图像。
第二个参数,const vector&类型的keypoints1,根据第一幅源图像得到的特征点,它是一个输出参数。
第三个参数,const Mat&类型的img2,第二幅源图像。
第四个参数,const vector&类型的keypoints2,根据第二幅源图像得到的特征点,它是一个输出参数。
第五个参数,matches1to2,第一幅图像到第二幅图像的匹配点,即表示每一个图1中的特征点都在图2中有一一对应的点、
第六个参数,Mat&类型的outImg,输出图像,其内容取决于第五个参数标识符falgs。
第七个参数,const Scalar&类型的matchColor,匹配的输出颜色,即线和关键点的颜色。它有默认值Scalar::all(-1),表示颜色是随机生成的。
第八个参数,const Scalar&类型的singlePointColor,单一特征点的颜色,它也有表示随机生成颜色的默认值Scalar::all(-1)。
第九个参数,matchesMask,确定哪些匹配是会绘制出来的掩膜,如果掩膜为空,表示所有匹配都进行绘制。
第十个参数,int类型的flags,特征绘制的标识符,有默认值DrawMatchesFlags::DEFAULT。
3.2、图像特征匹配实例
1、实现图像特征匹配的步骤如下:
(1)使用 DescriptorExtractor 接口来寻找关键点对应的特征向量。
(2)使用 SurfDescriptorExtractor 以及它的函数 compute( )来完成特定的计算。
(3)使用 BruteForceMatcher 来匹配特征向量。
(4)使用函数 drawMatches 来绘制检测到的匹配点。
2、代码
#include "opencv2/core/core.hpp" #include "opencv2/features2d/features2d.hpp" #include "opencv2/highgui/highgui.hpp" #include <opencv2/nonfree/nonfree.hpp> #include<opencv2/legacy/legacy.hpp> #include <iostream> using namespace cv;using namespace std;int main(){ //【0】改变console字体颜色 system("color 1A"); //【1】载入素材图 Mat srcImage1 = imread("1.jpg", 1); Mat srcImage2 = imread("2.jpg", 1); if (!srcImage1.data || !srcImage2.data) { printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! \n"); return false; } //【2】使用SURF算子检测关键点 int minHessian = 2000;//SURF算法中的hessian阈值 SurfFeatureDetector detector(minHessian);//定义一个SurfFeatureDetector(SURF) 特征检测类对象 std::vector<KeyPoint> keyPoint1, keyPoints2;//vector模板类,存放任意类型的动态数组 //【3】调用detect函数检测出SURF特征关键点,保存在vector容器中 detector.detect(srcImage1, keyPoint1); detector.detect(srcImage2, keyPoints2); //【4】计算描述符(特征向量) SurfDescriptorExtractor extractor; Mat descriptors1, descriptors2; extractor.compute(srcImage1, keyPoint1, descriptors1); extractor.compute(srcImage2, keyPoints2, descriptors2); //【5】使用BruteForce进行匹配 // 实例化一个匹配器 BruteForceMatcher< L2<float> > matcher; std::vector< DMatch > matches; //匹配两幅图中的描述子(descriptors) matcher.match(descriptors1, descriptors2, matches); //【6】绘制从两个图像中匹配出的关键点 Mat imgMatches; drawMatches(srcImage1, keyPoint1, srcImage2, keyPoints2, matches, imgMatches);//进行绘制 //【7】显示效果图 imshow("匹配图", imgMatches); waitKey(0); return 0;}
3、运行效果
(1)原图
(2)特征匹配效果图
- 仿射变换和SURF特征点匹配
- opencv仿设变换和surf特征点描述
- OpenCV 仿射变换 & SURF特征点描述合辑
- OpenCV仿射变换 & SURF特征点描述合辑
- OpenCV仿射变换 & SURF特征点描述
- 【OpenCV入门教程之十八】OpenCV仿射变换 & SURF特征点描述合辑
- 【OpenCV入门教程之十八】OpenCV仿射变换 & SURF特征点描述合辑
- OpenCV之十八 OpenCV仿射变换 & SURF特征点描述合辑
- 【OpenCV入门教程之十八】OpenCV仿射变换 & SURF特征点描述合辑
- 【OpenCV入门教程之十八】OpenCV仿射变换 & SURF特征点描述合辑
- 【OpenCV入门教程之十八】OpenCV仿射变换 & SURF特征点描述合辑
- 【OpenCV入门教程之十八】OpenCV仿射变换 & SURF特征点描述合辑
- [转]【OpenCV入门教程之十八】OpenCV仿射变换 & SURF特征点描述合辑
- 【OpenCV入门教程之十八】OpenCV仿射变换 & SURF特征点描述合辑
- Surf特征匹配点提纯
- Emgucv SURF特征点的寻找和匹配
- OpenCV3中的SURF特征点的寻找和匹配
- 【OpenCV】OpenCV3中的SURF特征点的寻找和匹配
- Anguar.js介绍
- Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例
- BZOJ 3676 回文串
- foreach循环
- 运算符、表达式和语句
- 仿射变换和SURF特征点匹配
- Wins系统带选项复制命令robocopy的操作方法介绍
- c# 发送qq邮箱本地正常 布置到服务器上后出现的异常
- 求最长上升子序列
- 【分析】Ceph系统架构
- “盛大游戏杯”第15届上海大学程序设计联赛夏季赛暨上海高校金马五校赛
- 关于表达式中除数为0的容错机制的处理
- 把数组排成最小的数
- 剑指Offer----跳台阶