图像拼接技术

图像拼接:

图像拼接的步骤

  • 对每幅图进行特征点提取
  • 对对特征点进行匹配
  • 进行图像配准
  • 把图像拷贝到另一幅图像的特定位置
  • 对重叠边界进行特殊处理
     图像拼接的每个步骤详解
  • 特征点提取(图像的特征包括点,线,块特征)

1.1 灰度图转换

//灰度图转换
Mat image1, image2;
cvtColor(image01, image1, CV_RGB2GRAY);

1.2 提取特征点

  • 涉及的数据结构
    SurfFeatureDetector 特征检测器是一个类,里面有用到的方法detect()
    vector
    KeyPoint( Point2f _pt, float _size, float _angle=-1, float _response=0, int _octave=0, int_class_id=-1 )
    1. pt是关键点的坐标
    2. size是关键点的邻域直径
    3. angle是关键点的方向,在[0,360]度之间,方向与图像坐标系有关,例 如顺时针
    4. response是最强特征点被选择的响应,可用来进行更近一步的排序或子 采样
    5. octave是关键点提取所在的金字塔层数
    6. class_id 若关键点被聚类的话,class_id是关键点所在聚类的id
      特征点也有方向?

1.SIFT学习–确定特征点的方向 - CSDN博客 https://blog.csdn.net/ro9er/article/details/7405036
为了保证特征点的方向不变性,就要确定特征点的方向,那么特征点的方向可以用下面的公式:
其中 为(x,y)处的梯度大小而 为该点的梯度方向
每个特征点都有自己的位置,所在方向,尺度的属性。只有确定了关键点的方向和大小才能保证旋转不变性和伸缩不变性。
2.opencv中SiftDescriptorExtractor所做的SIFT特征向量提取工作简单分析 - CSDN博客 https://blog.csdn.net/u012556077/article/details/47128439
(对于一个关键点找到方向,计算他周围的16个像素,旋转,每个像素映射到8个方向,都映射过去根据梯度计算方向,可以得到每一行就是128个特征向量。)
 detect(image1, keyPoint1) 提取第一张图片的特征点,存放在一个向量里面
 detect( const Mat& image, vector& keypoints, const Mat&mask=Mat() ) const 最后一个参数代表roi,是非0的。
SurfFeatureDetector surfDetector(800);
// 海塞矩阵阈值,在这里调整精度,值越大点越少,越精准
vector keyPoint1, keyPoint2;
surfDetector.detect(image1, keyPoint1);
surfDetector.detect(image2, keyPoint2);
Ptr FeatureDetector::create( const string& detectorType ) detectorType可以用下面的代替
10种特征检测方法
FastFeatureDetector(特征检测器)点
“STAR” – StarFeatureDetector
“SIFT” – SIFT (nonfree module)块,尺度不变特征
“SURF” – SURF (nonfree module)块
“ORB” – ORB
“MSER” – MSER
“GFTT” – GoodFeaturesToTrackDetector角点
“HARRIS” – GoodFeaturesToTrackDetector with Harris detector enabled角点
“Dense” – DenseFeatureDetector
SimpleBlob” – SimpleBlobDetector块
 drawKeypoints
drawKeypoints( const Mat& image, const vector& keypoints, Mat& outImage, constScalar& color=Scalar::all(-1), int flags=DrawMatchesFlags::DEFAULT )最后一个是默认值

1.3 特征点描述

涉及的数据结构

 DescriptorExtractor描述子提取器
 COMPUTE( CONST MAT& IMAGE, VECTOR& KEYPOINTS, MAT& DE-SCRIPTORS ) CONST(根据关键点来计算描述算子)
 DescriptorExtractor
 DescriptorExtractor是提取关键点的描述向量类抽象基类,其具体类有:
 class SiftDescriptorExtractor
 class SurfDescriptorExtractor
 class CalonderDescriptorExtractor
 class BriefDescriptorExtractor
 class OpponentColorDescriptorExtractor
 要使用某一种描述向量,可以调用DescriptorExtractor的工厂来创建,静态方法如下:
 static Ptr create( const string& descriptorExtractorType );
 也可以像我的示例代码中那样显式的创建,如下:
 DescriptorExtractor *pExtractor = new SurfDescriptorExtractor;
 可以用swich实现在多种方法中切换。
 DescriptorMatcher描述子匹配器用于特征关键点描述子匹配的抽象基类. 有两类匹配任务:匹配两个图像之间的特征描述子,或者匹配一个图像与另外一个图像集的特征描述子.
 DescriptorMatcher是匹配器的抽象基类,其具体类有:
 class BruteForceMatcher
 class FlannBasedMatcher
 匹配器可以由静态工厂方法直接创建,如下:
 static Ptr create( const string& descriptorMatcherType );
 也可以像我的示例代码中那样显式的创建,如下:
 DescriptorMatcher *pMatcher = new FlannBasedMatcher;
 可以用swich实现在多种方法中切换
 Read 从文件点钟读取特征描述子提取的对象
 write写入特征描述子的提取的对象到文件.
 Create根据名字创建特征描述算子
SIFT特征提取分析 - CSDN博客 HTTPS://BLOG.CSDN.NET/ABCJENNIFER/ARTICLE/DETAILS/7639681

每个点都有自己的尺度,位置,方向
梯度直方图方向是0-360,每45度就是一个柱,这样就有8个柱,直方图的峰值代表关键点邻域梯度的主方向,即为关键点的方向。

由梯度方向直方图确定主梯度方向

该步中将建立所有scale中特征点的描述子(128维)
首先将坐标轴旋转为关键点的方向,以确保旋转不变性。以关键点为中心取8×8的窗口。所以描述算子是64个反向和大小

所以关键点的描述算子是64个
图左部分的中央为当前关键点的位置,每个小格代表关键点邻域所在尺度空间的一个像素,利用公式求得每个像素的梯度幅值与梯度方向,箭头方向代表该像素的梯度方向,箭头长度代表梯度模值,然后用高斯窗口对其进行加权运算。
此图中一个关键点由2×2共4个种子点组成,每个种子点有8个方向向量信息。这种邻域方向性信息联合的思想增强了算法抗噪声的能力,同时对于含有定位误差的特征匹配也提供了较好的容错性。

这样就可以对每个feature形成一个4*4*8=128维的描述子,每一维都可以表示4*4个格子中一个的scale/orientation. 将这个向量归一化之后,就进一步去除了光照的影响。

2 特征点匹配

2.1 涉及的数据结构

 FlannBasedMatcher matcher;
 vector

2.2 获取图像1到图像2的投影映射矩阵 尺寸为3*3

Mat findHomography(InputArray srcPoints, InputArray dstPoints, int method=0, double ransacReprojThreshold=3, OutputArray mask=noArray() )
• srcPoints – Coordinates of the points in the original plane, a matrix of the type CV_32FC2 or vector .
• dstPoints – Coordinates of the points in the target plane, a matrix of the type CV_32FC2 or a vector .
• method –
Method used to computed a homography matrix. The following methods are possible:

2.3 在这个函数参数中,

输入的m1和m2是两个对应的序列,这两组序列的每一对数据一一匹配,其中既有正确的匹配,也有错误的匹配,正确的可以称为内点,错误的称为外点,RANSAC方法就是从这些包含错误匹配的数据中,分离出正确的匹配,并且求得单应矩阵。model就是我们需要求解的单应矩阵,mask我们可以称为标记矩阵,他和m1,m2的长度一样,当一个m1和m2中的点为内点时,mask相应的标记为1,反之为0,说白了,通过mask我们最终可以知道序列中哪些是内点,哪些是外点。reprojThreshold为阈值,当某一个匹配与估计的假设小于阈值时,则被认为是一个内点,这个阈值,openCV默认给的是3,后期使用的时候自己也可以修改。confidence为置信度,其实也就是人为的规定了一个数值,这个数值可以大致表示RANSAC结果的准确性,这个具体有啥用后面咱们再说。这个值初始时被设置为0.995. maxIters为初始迭代次数,RANSAC算法核心就是不断的迭代,这个值就是迭代的次数,默认设为了2000

3 图像配准

3.1 Image registration 是指同一目标的两幅或者两幅以上的图像在空间位置的对准。图像配准技术的过程,称为图像匹配或者图像相关(image matching or image correlation)。

3.2 这样子我们就可以得到了两幅待拼接图的匹配点集,接下来我们进行图像的配准,即将两张图像转换为同一坐标下,这里我们需要使用findHomography函数来求得变换矩阵。图像的点映射findHomography

要得到两张图片的H,就必须至少知道4个相同对应位置的点,opencv中可以利用findHomography正确得到

3.3 对图像进行透视变换,就是变形 */

warpPerspective(firstImage, imageTransform1, homo, Size(MAX(corners.right_top.x, corners.right_bottom.x), secondImage.rows));
nputArray src:输入的图像
OutputArray dst:输出的图像
InputArray M:透视变换的矩阵
Size dsize:输出图像的大小
int flags=INTER_LINEAR:输出图像的插值方法,
函数原理

透视变换(Perspective Transformation)是将图片投影到一个新的视平面(Viewing Plane),也称作投影映射(Projective Mapping)。通用的变换公式为:

u,v是原始图片左边,对应得到变换后的图片坐标x,y,其中 。
变换矩阵 可以拆成4部分, 表示线性变换,比如scaling,shearing和ratotion。 用于平移, 产生透视变换。所以可以理解成仿射等是透视变换的特殊形式。经过透视变换之后的图片通常不是平行四边形(除非映射视平面和原来平面平行的情况)。
重写之前的变换公式可以得到:
所以,已知变换对应的几个点就可以求取变换公式。反之,特定的变换公式也能新的变换的图片。简单的看一个正方形到四边形的变换:变换的4组对应点可以表示成:

4.图像融合:OptimizeSeam

从上图可以看出,两图的拼接并不自然,原因就在于拼接图的交界处,两图因为光照色泽的原因使得两图交界处的过渡很糟糕,所以需要特定的处理解决这种不自然。这里的处理思路是加权融合,在重叠部分由前一幅图像慢慢过渡到第二幅图像,即将图像的重叠区域的像素值按一定的权值相加合成新的图像。
5.
 图像拼接的其他算法
 SIFT算法:

从这里
STATIC// DEFS.H
EXTERN CONST STD::STRING KSTR;
EXTERN CONST STUDENT KSTU;
// DEFS.CPP
CONST STD::STRING KSTR = “STRING”;
CONST STUDENT KSTU(“NAME”);
像素的连通性——m连通
对于具有值V的像素p和q,如果:
I. q在集合N4(p)中,或
II. q在集合ND(p)中,并且N4(p)与N4(q)的交集为空(没有值V的像素),则称两个像素是m连通的,即4连通和D连通的混合连通。
数字图像处理入门(二)-邻域、连通性dzh漫漫修行路_新浪博客 http://blog.sina.com.cn/s/blog_a98e39a201010six.html

猜你喜欢

转载自blog.csdn.net/yychentracy/article/details/82261192