opencv入门重映射 & SURF特征点检测合辑
Posted long-w
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了opencv入门重映射 & SURF特征点检测合辑相关的知识,希望对你有一定的参考价值。
一、OpenCV重映射
1、重映射的概念简析
重映射,就是把一幅图像中某位置的像素放置到另一个图片指定位置的过程。为了完成映射过程, 我们需要获得一些插值为非整数像素的坐标,因为源图像与目标图像的像素坐标不是一一对应的。一般情况下,我们通过重映射来表达每个像素的位置 (x,y),像这样 :
g(x,y) = f ( h(x,y) )
在这里, g() 是目标图像, f() 是源图像, 而h(x,y) 是作用于 (x,y) 的映射方法函数。
来看个例子。若有一幅图像 I ,想满足下面的条件作重映射:
h(x,y) = (I.cols - x, y )
这样的话,图像会按照 x 轴方向发生翻转。在OpenCV中,我们用函数remap( )来实现简单重映射。
2、remap( )函数解析
remap( )函数会根据我们指定的映射形式,将源图像进行重映射几何变换,基于的式子如下:
需要注意,此函数不支持就地(in-place)操作。看看其原型和参数。
C++: void remap(InputArray src, OutputArraydst, InputArray map1, InputArray map2, int interpolation, intborderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())
第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可,且需为单通道8位或者浮点型图像。
第二个参数,OutputArray类型的dst,函数调用后的运算结果存在这里,即这个参数用于存放函数调用后的输出结果,需和源图片有一样的尺寸和类型。
第三个参数,InputArray类型的map1,它有两种可能的表示对象。
表示点(x,y)的第一个映射。
表示CV_16SC2 , CV_32FC1 或CV_32FC2类型的X值。
第四个参数,InputArray类型的map2,同样,它也有两种可能的表示对象,而且他是根据map1来确定表示那种对象。
若map1表示点(x,y)时。这个参数不代表任何值。
表示CV_16UC1 , CV_32FC1类型的Y值(第二个值)。
第五个参数,int类型的interpolation,插值方式,之前的resize( )函数中有讲到,需要注意,resize( )函数中提到的INTER_AREA插值方式在这里是不支持的,
所以可选的插值方式如下:
INTER_NEAREST - 最近邻插值
INTER_LINEAR – 双线性插值(默认值)
INTER_CUBIC – 双三次样条插值(逾4×4像素邻域内的双三次插值)
INTER_LANCZOS4 -Lanczos插值(逾8×8像素邻域的Lanczos插值)
第六个参数,int类型的borderMode,边界模式,有默认值BORDER_CONSTANT,表示目标图像中“离群点(outliers)”的像素值不会被此函数修改。
第七个参数,const Scalar&类型的borderValue,当有常数边界时使用的值,其有默认值Scalar( ),即默认值为0。
3、重映射示例
1 //重映射
2 #include "opencv2/highgui/highgui.hpp"
3 #include "opencv2/imgproc/imgproc.hpp"
4 #include <iostream>
5
6 using namespace cv;
7
8 int main( )
9 {
10 //【0】变量定义
11 Mat srcImage, dstImage;
12 Mat map_x, map_y;
13
14 //【1】载入原始图
15 srcImage = imread( "1.jpg", 1 );
16
17 imshow("原始图",srcImage);
18
19 //【2】创建和原始图一样的效果图,x重映射图,y重映射图
20 dstImage.create( srcImage.size(), srcImage.type() );
21 map_x.create( srcImage.size(), CV_32FC1 );
22 map_y.create( srcImage.size(), CV_32FC1 );
23
24 //【3】双层循环,遍历每一个像素点,改变map_x & map_y的值
25 for( int j = 0; j < srcImage.rows;j++)
26 {
27 for( int i = 0; i < srcImage.cols;i++)
28 {
29 //改变map_x & map_y的值.
30 map_x.at<float>(j,i) = static_cast<float>(i);
31 map_y.at<float>(j,i) = static_cast<float>(srcImage.rows - j);
32 }
33 }
34
35 //【4】进行重映射操作
36 remap( srcImage, dstImage, map_x, map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0,0, 0) );
37
38 //【5】显示效果图
39 imshow( "【程序窗口】", dstImage );
40 imwrite("remap.jpg", dstImage);
41 waitKey();
42
43 return 0;
44 }
二.SURF特征点检测
1、SURF算法概览
SURF,英语全称为SpeededUp Robust Features,直译的话就是“加速版的具有鲁棒性的特征“算法,由Bay在2006年首次提出。SURF是尺度不变特征变换算法(SIFT算法)的加速版。一般来说,标准的SURF算子比SIFT算子快好几倍,并且在多幅图片下具有更好的稳定性。SURF最大的特征在于采用了harr特征以及积分图像的概念,这大大加快了程序的运行时间。SURF可以应用于计算机视觉的物体识别以及3D重构中。
下图展示了SUTF类相关的一些继承关系:
2、drawKeypoints函数详解
因为接下来的示例程序需要用到drawKeypoints函数,顾名思义,此函数用于绘制关键点。
C++: void drawKeypoints(const Mat&image, const vector<KeyPoint>& keypoints, Mat& outImage, constScalar& color=Scalar::all(-1), int flags=DrawMatchesFlags::DEFAULT )
第一个参数,const Mat&类型的src,输入图像。
第二个参数,const vector<KeyPoint>&类型的keypoints,根据源图像得到的特征点,它是一个输出参数。
第三个参数,Mat&类型的outImage,输出图像,其内容取决于第五个参数标识符falgs。
第四个参数,const Scalar&类型的color,关键点的颜色,有默认值Scalar::all(-1)。
第五个参数,int类型的flags,绘制关键点的特征标识符,有默认值DrawMatchesFlags::DEFAULT。可以在如下这个结构体中选取值。
1 struct DrawMatchesFlags
2 {
3 enum
4 {
5 DEFAULT = 0, // Output image matrix will be created (Mat::create),
6 // i.e. existing memory of output image may be reused.
7 // Two source images, matches, and single keypoints
8 // will be drawn.
9 // For each keypoint, only the center point will be
10 // drawn (without a circle around the keypoint with the
11 // keypoint size and orientation).
12 DRAW_OVER_OUTIMG = 1, // Output image matrix will not be
13 // created (using Mat::create). Matches will be drawn
14 // on existing content of output image.
15 NOT_DRAW_SINGLE_POINTS = 2, // Single keypoints will not be drawn.
16 DRAW_RICH_KEYPOINTS = 4 // For each keypoint, the circle around
17 // keypoint with keypoint size and orientation will
18 // be drawn.
19 };
20 };
三、综合示例
1、重映射综合示例
1 //重映射综合示例
2 #include "opencv2/highgui/highgui.hpp"
3 #include "opencv2/imgproc/imgproc.hpp"
4 #include <iostream>
5
6 using namespace cv;
7 using namespace std;
8
9 #define WINDOW_NAME "【程序窗口】" //为窗口标题定义的宏
10
11 Mat g_srcImage, g_dstImage;
12 Mat g_map_x, g_map_y;
13
14 int update_map( int key);
15 static void ShowHelpText( );//输出帮助文字
16
17 int main( int argc, char** argv )
18 {
19 //改变console字体颜色
20 system("color 2F");
21
22 //显示帮助文字
23 ShowHelpText();
24
25 //【1】载入原始图
26 g_srcImage = imread( "1.jpg", 1 );
27
28 imshow("原始图",g_srcImage);
29
30 //【2】创建和原始图一样的效果图,x重映射图,y重映射图
31 g_dstImage.create( g_srcImage.size(), g_srcImage.type() );
32 g_map_x.create( g_srcImage.size(), CV_32FC1 );
33 g_map_y.create( g_srcImage.size(), CV_32FC1 );
34
35 //【3】创建窗口并显示
36 namedWindow( WINDOW_NAME, CV_WINDOW_AUTOSIZE );
37 imshow(WINDOW_NAME,g_srcImage);
38
39 //【4】轮询按键,更新map_x和map_y的值,进行重映射操作并显示效果图
40 while( 1 )
41 {
42 //获取键盘按键
43 int key = waitKey(0);
44
45 //判断ESC是否按下,若按下便退出
46 if( (key & 255) == 27 )
47 {
48 cout << "程序退出...........
";
49 break;
50 }
51
52 //根据按下的键盘按键来更新 map_x & map_y的值. 然后调用remap( )进行重映射
53 update_map(key);
54 remap( g_srcImage, g_dstImage, g_map_x, g_map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0,0, 0) );
55
56 //显示效果图
57 imshow( WINDOW_NAME, g_dstImage );
58 }
59 return 0;
60 }
61
62 int update_map( int key )
63 {
64 //双层循环,遍历每一个像素点
65 for( int j = 0; j < g_srcImage.rows;j++)
66 {
67 for( int i = 0; i < g_srcImage.cols;i++)
68 {
69 switch(key)
70 {
71 case ‘