旋转、仿射变换和SURF特征点检测
一、弯曲变换函数warpAffine ()
1.1 warpAffine ()各参数详解
voidwarpAffine(InputArray src,OutputArray dst,InputArray M,Size dsize, int flags =INTER_LINEAR, intborderMode =BORDER_CONSTANT,constScalar& 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。
另外提一点,我们的WarpAffine函数与一个叫做cvGetQuadrangleSubPix( )的函数类似,但是不完全相同。WarpAffine要求输入和输出图像具有同样的数据类型,有更大的资源开销(因此对小图像不太合适)而且输出图像的部分可以保留不变。而cvGetQuadrangleSubPix 可以精确地从8位图像中提取四边形到浮点数缓存区中,具有比较小的系统开销,而且总是全部改变输出图像的内容。
1.2调用示例
二、旋转变换函数
2.1 getRotationMatrix2D()各参数详解
MatgetRotationMatrix2D(Point2fcenter,double angle,double scale)
Ø 第一个参数,Point2f类型的center,表示源图像的旋转中心。
Ø 第二个参数,double类型的angle,旋转角度。角度为正值表示向逆时针旋转(坐标原点是左上角)。
Ø 第三个参数,double类型的scale,缩放系数。
此函数计算以下矩阵:
其中:
2.2调用示例
三、 SURF特征点检测
在OpenCV中,使用SURF进行特征点描述主要是drawMatches方法和BruteForceMatcher类的运用。
3.1 drawMatches()函数各参数详解
drawMatches()函数用于绘制出相匹配的两个图像的关键点
voiddrawMatches(constMat& img1, constvector<KeyPoint>&keypoints1,constMat& img2, constvector<KeyPoint>&keypoints2, constvector<DMatch>& matches1to2,Mat&outImg,constScalar&matchColor =Scalar::all(-1),constScalar&singlePointColor =Scalar::all(-1),constvector<char>&matchesMask =vector<char>(),intflags = DrawMatchesFlags::DEFAULT)
voiddrawMatches(constMat& img1, constvector<KeyPoint>&keypoints1,constMat& img2, constvector<KeyPoint>&keypoints2,constvector<vector<DMatch>>&matches1to2,Mat&outImg,constScalar&matchColor =Scalar::all(-1),constScalar&singlePointColor =Scalar::all(-1),constvector<vector<char>>& matchesMask =vector<vector<char>>(), intflags = DrawMatchesFlags::DEFAULT)
除了第五个参数matches1to2和第九个参数matchesMask有细微的差别以外,两个版本的基本上相同。
Ø 第一个参数,const Mat&类型的img1,第一幅源图像。
Ø 第二个参数,const vector
Ø 第三个参数,const Mat&类型的img2,第二幅源图像。
Ø 第四个参数,const vector
Ø 第五个参数,matches1to2,第一幅图像到第二幅图像的匹配点,即表示每一个图1中的特征点都在图2中有一一对应的点、
Ø 第六个参数,Mat&类型的outImg,输出图像,其内容取决于第五个参数标识符falgs。
Ø 第七个参数,const Scalar&类型的matchColor,匹配的输出颜色,即线和关键点的颜色。它有默认值Scalar::all(-1),表示颜色是随机生成的。
Ø 第八个参数,const Scalar&类型的singlePointColor,单一特征点的颜色,它也有表示随机生成颜色的默认值Scalar::all(-1)。
Ø 第九个参数,matchesMask,确定哪些匹配是会绘制出来的掩膜,如果掩膜为空,表示所有匹配都进行绘制。
Ø 第十个参数,int类型的flags,特征绘制的标识符,有默认值DrawMatchesFlags::DEFAULT。可以在如下这个DrawMatchesFlags结构体中选取值:
struct DrawMatchesFlags
{
enum
{
DEFAULT = 0, //Output image matrix will be created (Mat::create),
// i.e. existing memory ofoutput image may bereused.
// Two source images,matches, and singlekeypoints
// will be drawn.
// For each keypoint, only the center pointwillbe
// drawn (without a circlearound the keypoint withthe
// keypoint size andorientation).
DRAW_OVER_OUTIMG = 1, //Output image matrix will not be
// created (usingMat::create). Matches will bedrawn
// on existing contentof output image.
NOT_DRAW_SINGLE_POINTS = 2, //Single keypoints will not be drawn.
DRAW_RICH_KEYPOINTS = 4 // Foreach keypoint, the circle around
// keypoint withkeypoint size and orientationwill
// be drawn.
};
};
四、BruteForceMatcher类
完整程序核心算法:
Ø 使用 DescriptorExtractor 接口来寻找关键点对应的特征向量
Ø 使用 SurfDescriptorExtractor 以及它的函数 compute 来完成特定的计算
Ø 使用 BruteForceMatcher 来匹配特征向量
Ø 使用函数 drawMatches 来绘制检测到的匹配点
4.1 BruteForceMatcher类详解
template<classDistance>
class CV_EXPORTS BruteForceMatcher : publicBFMatcher
{
public:
BruteForceMatcher(Distanced = Distance()) : BFMatcher(Distance::normType, false) { (void)d; }
virtual~BruteForceMatcher() {}
};
五、完整程序(仿射变换)
// ********************仿射变换程序**************************
// ********************仿射变换程序**************************
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include
//-----------------------------------【命名空间声明部分】--------------------------------------
// 描述:包含程序所使用的命名空间
//-----------------------------------------------------------------------------------------------
using namespacecv;
using namespacestd;
//-----------------------------------【宏定义部分】--------------------------------------------
// 描述:定义一些辅助宏
//------------------------------------------------------------------------------------------------
#define WINDOW_NAME1"【原始图窗口】" //为窗口标题定义的宏
#define WINDOW_NAME2"【经过Warp后的图像】" //为窗口标题定义的宏
#define WINDOW_NAME3"【经过Warp和Rotate后的图像】" //为窗口标题定义的宏
//-----------------------------------【全局函数声明部分】--------------------------------------
// 描述:全局函数的声明
//-----------------------------------------------------------------------------------------------
static void ShowHelpText();
//-----------------------------------【main( )函数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//-----------------------------------------------------------------------------------------------
int main()
{
//【0】改变console字体颜色
system("color 1A");
//【0】显示欢迎和帮助文字
ShowHelpText();
//【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("E:\\1TJQ\\Opencv\\Images\\image1.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;
}
//-----------------------------------【ShowHelpText( )函数】----------------------------------
// 描述:输出一些帮助信息
//----------------------------------------------------------------------------------------------
static void ShowHelpText()
{
//输出一些帮助信息
printf("\n\n\n\t欢迎来到【仿射变换】示例程序~\n\n");
printf("\t当前使用的OpenCV版本为 OpenCV "CV_VERSION);
printf("\n\n\t\t\t\t\t\t\t\t by浅墨\n\n\n"
);
}
六、完整程序(SURF特征点检测)
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include
#include
#include
//-----------------------------------【命名空间声明部分】--------------------------------------
// 描述:包含程序所使用的命名空间
//-----------------------------------------------------------------------------------------------
using namespacecv;
using namespacestd;
//-----------------------------------【全局函数声明部分】--------------------------------------
// 描述:全局函数的声明
//-----------------------------------------------------------------------------------------------
static voidShowHelpText();//输出帮助文字
//-----------------------------------【main( )函数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//-----------------------------------------------------------------------------------------------
int main()
{
//【0】改变console字体颜色
system("color 1A");
//【0】显示欢迎和帮助文字
ShowHelpText();
//【1】载入素材图
Mat srcImage1 = imread("1.jpg",1);
Mat srcImage2 = imread("2.jpg",1);
if(!srcImage1.data || !srcImage2.data)
{
printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~!\n");returnfalse;
}
//【2】使用SURF算子检测关键点
intminHessian = 700;//SURF算法中的hessian阈值
SurfFeatureDetectordetector(minHessian);//定义一个SurfFeatureDetector(SURF)特征检测类对象
std::vector<KeyPoint> keyPoint1, keyPoints2;//vector模板类,存放任意类型的动态数组
//【3】调用detect函数检测出SURF特征关键点,保存在vector容器中
detector.detect(srcImage1,keyPoint1);
detector.detect(srcImage2,keyPoints2);
//【4】计算描述符(特征向量)
SurfDescriptorExtractorextractor;
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;
}
//-----------------------------------【ShowHelpText( )函数】----------------------------------
// 描述:输出一些帮助信息
//----------------------------------------------------------------------------------------------
static voidShowHelpText()
{
//输出一些帮助信息
printf("\n\n\n\t欢迎来到【SURF特征描述】示例程序~\n\n");
printf("\t当前使用的OpenCV版本为 OpenCV "CV_VERSION
"\n\n\t\t\t\t\t\t\t\t by浅墨\n\n\n");
}
参考内容:
http://www.cnblogs.com/mq0036/p/5902104.html