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 1‘: // 键盘【1】键按下,进行第一种重映射操作
 72                 if( i > g_srcImage.cols*0.25 && i < g_srcImage.cols*0.75 && j > g_srcImage.rows*0.25 && j < g_srcImage.rows*0.75)
 73                 {
 74                     g_map_x.at<float>(j,i) = static_cast<float>(2*( i - g_srcImage.cols*0.25 ) + 0.5);
 75                     g_map_y.at<float>(j,i) = static_cast<float>(2*( j - g_srcImage.rows*0.25 ) + 0.5);
 76                 }
 77                 else
 78                 {
 79                     g_map_x.at<float>(j,i) = 0;
 80                     g_map_y.at<float>(j,i) = 0;
 81                 }
 82                 break;
 83             case ‘2‘:// 键盘【2】键按下,进行第二种重映射操作
 84                 g_map_x.at<float>(j,i) = static_cast<float>(i);
 85                 g_map_y.at<float>(j,i) = static_cast<float>(g_srcImage.rows - j);
 86                 break;
 87             case ‘3‘:// 键盘【3】键按下,进行第三种重映射操作
 88                 g_map_x.at<float>(j,i) = static_cast<float>(g_srcImage.cols - i);
 89                 g_map_y.at<float>(j,i) = static_cast<float>(j);
 90                 break;
 91             case ‘4‘:// 键盘【4】键按下,进行第四种重映射操作
 92                 g_map_x.at<float>(j,i) = static_cast<float>(g_srcImage.cols - i);
 93                 g_map_y.at<float>(j,i) = static_cast<float>(g_srcImage.rows - j);
 94                 break;
 95             }
 96         }
 97     }
 98     return 1;
 99 }
100 
101 static void ShowHelpText()
102 {
103     //输出一些帮助信息
104     cout << "


	欢迎来到重映射示例程序~

";
105     cout << "	当前使用的OpenCV版本为 OpenCV "CV_VERSION;
106     cout <<  "

	按键操作说明: 

"
107         "		键盘按键【ESC】- 退出程序
"
108         "		键盘按键【1】-  第一种映射方式
"
109         "		键盘按键【2】- 第二种映射方式
"
110         "		键盘按键【3】- 第三种映射方式
"
111         "		键盘按键【4】- 第四种映射方式
"
112         "

								";
113 }

2、SURF特征点检测综合示例程序

这个示例程涉及到如下三个方面:

1 使用 FeatureDetector 接口来发现感兴趣点。
2 使用 SurfFeatureDetector 以及其函数 detect 来实现检测过程
3 使用函数 drawKeypoints 绘制检测到的关键点。
 1 //SURF特征点检测完整示例
 2 #include "opencv2/core/core.hpp"
 3 #include "opencv2/features2d/features2d.hpp"
 4 #include "opencv2/highgui/highgui.hpp"
 5 #include "opencv2/nonfree/nonfree.hpp"
 6 #include <iostream>
 7 
 8 using namespace std;
 9 using namespace cv;
10 
11 
12 static void ShowHelpText( );//输出帮助文字
13 
14 int main( int argc, char** argv )
15 {
16     //【0】改变console字体颜色
17     system("color 2F");
18 
19     //【0】显示帮助文字
20     ShowHelpText( );
21 
22     //【1】载入源图片并显示
23     Mat srcImage1 = imread("1.jpg", 1 );
24     Mat srcImage2 = imread("2.jpg", 1 );
25     if( !srcImage1.data || !srcImage2.data )//检测是否读取成功
26     {
27         cout << "读取图片错误,请确定目录下是否有imread函数指定名称的图片存在~! 
";
28         return false;
29     }
30     imshow("原始图1",srcImage1);
31     imshow("原始图2",srcImage2);
32 
33     //【2】定义需要用到的变量和类
34     int minHessian = 400;//定义SURF中的hessian阈值特征点检测算子
35     SurfFeatureDetector detector( minHessian );//定义一个SurfFeatureDetector(SURF) 特征检测类对象
36     std::vector<KeyPoint> keypoints_1, keypoints_2;//vector模板类是能够存放任意类型的动态数组,能够增加和压缩数据
37 
38     //【3】调用detect函数检测出SURF特征关键点,保存在vector容器中
39     detector.detect( srcImage1, keypoints_1 );
40     detector.detect( srcImage2, keypoints_2 );
41 
42     //【4】绘制特征关键点
43     Mat img_keypoints_1; Mat img_keypoints_2;
44     drawKeypoints( srcImage1, keypoints_1, img_keypoints_1, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
45     drawKeypoints( srcImage2, keypoints_2, img_keypoints_2, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
46 
47     //【5】显示效果图
48     imshow("特征点检测效果图1", img_keypoints_1 );
49     imshow("特征点检测效果图2", img_keypoints_2 );
50 
51     waitKey(0);
52     return 0;
53 }
54 
55 void ShowHelpText()
56 {
57     //输出一些帮助信息
58     cout << "


	欢迎来到【SURF特征点检测】示例程序~

";
59     cout <<  "

	按键操作说明: 

"
60                 "		键盘按键任意键- 退出程序

"
61                 "

								";
62 
63 }

效果展示:

原图:

技术分享图片  技术分享图片

 效果图:

技术分享图片  技术分享图片

 



以上是关于opencv入门重映射 & SURF特征点检测合辑的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV教程

OpenCV新手教程之十七OpenCV重映射 &amp; SURF特征点检測合辑

系列文章 -- OpenCV入门教程

OpenCV仿射变换 & SURF特征点描述合辑

OpenCV特征点检測------Surf(特征点篇)

opencv学习之路(35)SURF特征点提取与匹配