1、单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,#,SIFT,特征提取过程中,的核心函数,1,PART ONE.,物理架构,opencv_contrib-3.1.0,(,版本号,)/modules/xfeature2d/opencv_xfeature2d project/src/sift.cpp,cv namespace,xfeature2d namespace,Feature2D,父类,/,基类,SIFT,类,feature2d,的子类,父类,/,基类,SIFT_Impl,类,SIFT,的子类,2,2024/11/22 周五,PART TWO.,运行架构,
2、主函数,int main(),/,创建,SIFT_Impl,类指针,Ptr f2d=xfeatures2d:SIFT:create();,Mat img_1=imread(1.jpg);,/读入图片,vector keypoints_1;,/用于存放检测到的关键点的容器,f2d-detect(img_1,keypoints_1);,/,检测出关键点,Mat descriptors_1;,f2d-compute(img_1,keypoints_1,descriptors_1);,/计算描述子,waitKey(0);,/等待任意按键按下,3,2024/11/22 周五,Feature2D,:det
3、ect(InputArray image,CV_OUT std:vector&keypoints,InputArray mask=noArray(),SIFT_Impl:detectAndCompute(image,mask,keypoints,noArray(),false);,SIFT_Impl:,detectAndCompute(image,noArray(),keypoints,descriptors,true);,Feature2D:compute(InputArray image,std:vector&keypoints,OutputArray descriptors),调用了 检
4、测关键点函数,调用了 计算描述子函数,4,2024/11/22 周五,createInitialImage(),图像初始化函数,buildGaussianPyramid()构建高斯金字塔函数,buildDoGPyramid()构建,DOG,金字塔函数,SIFT_Impl:detectAndCompute(image,mask,keypoints,noArray(),false);,findScaleSpaceExtrema()检测尺度空间极值函数,adjustLocalExtrema(,),调整极值函数,calcOrientationHist,(),计算关键点主方向函数,函数功能:检测图片中的
5、关键点,参数,image,:输入图片,参数,mask,:无掩模,参数,keypoints,:关键点容器,参数,noArray(),:无描述子,参数,false:,不使用给定的关键点,PART TREE.,检测关键点部分,5,2024/11/22 周五,图像尺度空间的构建,1.1,图像初始化函数,函数功能:,将输入图像转化为灰度图,并设置图像初始尺度,c+:,static Mat createInitialImage(const Mat&img,bool double ImageSize,float sigma),入口参数:,参数,const Mat&img:输入图像,参数,bool doubl
6、e ImageSize:是否将初始图像扩大两倍,若值为,1,,则图像扩大为原来两倍,参数,float sigma:设定图像的初始尺度,返回值:无,说明:,一个图像的尺度空间,L(x,y,),,定义为原始图像,I(x,y),与一个可变尺度的,2,维高斯函数,G(x,y,),卷积产生:,其中:,lowe,把初始图像的尺度,I(x,y),设置为,0.5,即:,I(x,y)=I(x,y,0.5),,那么由,L(x,y,1),得到,L(x,y,2),,即由尺度为,1,的图像生成尺度为,2,的图像的公式为:,6,图像尺度空间的构建,1.2,构建图像金字塔函数:,函数功能:,将输入图像作为金字塔初始图像,通
7、过不断进行高斯模糊和降采样后的,图片存放在,Mat,类容器中,c+:,void SIFT_Impl:buildGaussianPyramid(const Mat&base,std:vector&pyr,int nOctaves)const,入口参数:,参数,const Mat&base:输入图像,参数,std:vector&pyr:用于存储金字塔图像的容器,参数,int nOctaves:金字塔的组数,返回值:无,7,图像尺度空间的构建,1.3,构建图像,DOG,金字塔函数:,函数功能:,将构建好的高斯金字塔相邻层相减后构成,DOG,金字塔存放在,Mat,类容器中,void SIFT_Impl
8、:buildDoGPyramid(const std:vector&gpyr,std:vector&dogpyr)const,入口参数:,参数:vector&gpyr:存放高斯金字塔图片的容器,参数:vector&dogpyr:存放,DOG,金字塔图片的容器,返回值:无,8,关键点定位,关键点定位并确定主方向函数,函数功能:,(,1,)在,DOG,空间检测极值点,(,2,)精确定位关键点位置和尺度并进行插值处理,(,3,)去除边缘不稳定的点,(,4,)为关键点分配主方向,void SIFT_Impl:findScaleSpaceExtrema(const std:vector&gauss_py
9、r,const std:vector&dog_pyr,std:vector&keypoints)const,入口参数:,参数const std:vector&gauss_pyr:高斯金字塔容器,参数,const std:vector&dog_pyr:,DOG,金字塔容器,参数std:vector&keypoints:存放关键点容器,返回值:无,9,调整局部极值函数,函数功能:,精确定位关键点位置和尺度并进行插值处理,去除边缘不稳定的点,static bool adjustLocalExtrema(const std:vector&dog_pyr,KeyPoint&kpt,int octv,in
10、t&layer,int&r,int&c,int nOctaveLayers,float contrastThreshold,float edgeThreshold,float sigma),入口参数:,参数const std:vector&dog_pyr:,DOG,尺度空间金字塔,参数KeyPoint&kpt:定义了一个,KeyPoint,类对象用来存放筛选通过的关键点,参数int octv:该像素点所在的组数,参数,int&layer:该像素点所在的层数,参数int&r:该像素点所在的行,参数int&c:,该像素点所在的列,参数int nOctaveLayers:金字塔每组的层数,S,参数f
11、loat contrastThreshold:对比度阈值,0.04,参数float edgeThreshold:边缘响应阈值,参数float sigma:此处的,sigma,为初始尺度,sigma0,返回值:,若极值调整成功返回,1,,调整失败返回,0,10,2024/11/22 周五,说明:,其中令 得:,令 解得 :,接下来判断偏移量在每个维度的偏差是否大于,0.5,,若不大于直接保留,若大于进行迭代插值处理。在设置的迭代次数内修正成功则保留,否则舍弃。,设,f,(,i,,,j,)是,y,轴为,i,、,x,轴为,j,的图像像素值,则在,(,i,,,j,)点处的一阶、二阶及二阶混合偏导为:,
12、再对 进行筛选去除对比度低的点,在,opencv,中,使用下面的公式来判断其是否为不稳定的极值:,11,2024/11/22 周五,去除边缘响应较强的点,具体在程序中的计算同上:,12,2024/11/22 周五,计算关键点主方向函数,函数功能:,为特征点分配主方向,static float calcOrientationHist(const Mat&img,Point pt,int radius,float sigma,float*hist,int n),入口参数:,参数const Mat&img:当前特征点所在的图像,参数Point pt:关键点位置,参数int radius:指统计在以关
13、键点为中心,以,radius=3*1.5sigma,为半径的区域为作为该关键点的邻域,以统计直方图的形式来确定主方向,参数float sigma:这里的,sigma,是指相对于当前组第一层图像的尺度来说的,参数float*hist:定义了,hist,指针用于存放直方图,参数int n:直方图的条数,返回值:,直方图的主峰值,说明:直方图平滑处理;,opencv,使用的平滑公式为:,由于直方图代表的只是一个角度范围,想要得到更精确的方向角度值,需要对离散的梯度方向直方图进行插值拟合处理,拟合公式为:,13,SIFT_Impl:,detectAndCompute,(image,noArray(),
14、keypoints,descriptors,true),函数功能:计算图片中的关键点描述子,参数,image,:输入图片,参数noArray():无掩模,参数,keypoints,:关键点容器,参数descriptors:描述子,参数,true:,使用给定的关键点,unpackOctave(),calcDescriptors(),计算关键点描述子函数,calcSIFTDescriptor,PART FOUR.,关键点描述子,createInitialImage(),图像初始化函数,buildGaussianPyramid()构建高斯金字塔函数,buildDoGPyramid()构建,DOG,金
15、字塔函数,14,2024/11/22 周五,unpackOctave(const KeyPoint&kpt,int&octave,int&layer,float&scale),计算,sift,特征描述子,入口参数:,参数,const KeyPoint&kpt,:关键点,参数,int&octave,:关键点所在层,参数,int&layer,:关键点所在组,参数,float&scale,:,关键点所在尺度的比例因子,返回值:无,函数功能:去除关键点所在高斯金字塔的层数,组数,以及尺度比例因子,以方便后面计算描述子,15,2024/11/22 周五,计算,sift,特征描述子,3.2,计算,sift
16、,特征描述子,函数功能:计算特征点描述符,calcDescriptors,函数,static void calcDescriptors(const std:vector&gpyr,const std:vector&keypoints,Mat&descriptors,int nOctaveLayers,int firstOctave),入口参数:,参数const std:vector&gpyr:,存放高斯金字塔图片的容器,参数const std:vector&keypoints:存放关键点的容器,参数Mat&descriptors:,描述子矩阵,参数int nOctaveLayers,:,高斯金
17、字塔层数,参数int firstOctave,:如果原图像扩大两倍,则为-1,如果没有,则为0,返回值:无,说明,:,计算,sift,特征描述子要用高斯金字塔,,dog,金字塔只用来求取极值点,int d=SIFT_DESCR_WIDTH=4,,,n=SIFT_DESCR_HIST_BINS=8,float size=kpt.size,*,scale,计算特征点的特征矢量,calcSIFTDescriptor,(img,ptf,angle,size*0.5f,d,n,descriptors.ptr(int)i),16,2024/11/22 周五,函数功能:计算,sift,特征描述子,stati
18、c void calcSIFTDescriptor(const Mat&img,Point2f ptf,float ori,float scl,int d,int n,float*dst),3.3,计算,sift,特征点的描述矢量:,入口参数:,参数const Mat&img:输入图像,参数,Point2f ptf:输入检测到的特征点,,float,型,参数,float ori:特征点的幅角,角度,,float,型,参数,float scl:输入特征点的尺度,参数,int d:特征点周围邻域的宽度,参数,int n:设定直方图的条目数,之前统计主方向时设,n=36,,现在计算特征矢量,n=8,
19、参数,float*dst:输出特征点的描述矢量,,float,型,返回值:无,17,2024/11/22 周五,关键点描述子,1.,首先要明确,我们前面的步骤分别得到了关键点的位置(层,组,所在图像的横纵坐标),尺度,主方向的信息,我们的特征描述子是回到了高斯金字塔上去做的。所以我们定位关键点在高斯金塔的那一张图片上。,2.,然后确定用描述周围多大的区域去描述这个关键点,首先我们把这块区域分成,d*d,个小区域,,sift,中,d=4,,如图中蓝色区域所示,每一格的宽度为,3,,这里的,是指相对于当前组第一层图片来说的。,注意:,opencv,中计算的区域是最外面的橘色的矩形区域,面积为,(2
20、Rradius+1)*(2Rradius+1),其中:,18,3.,根据公式,来计算橘色矩形内每个像素点的幅值和幅角。,4.,接下来将橘色矩形内的每个像素的幅角按照旋转关键点主方向的角度,使得关键点主方向为,0,(或统一为多少度),5.,建立三维直方图,如图所示,,三维直方图是由,(opencv,中,)(d+2)*(d+2)(n+2),个长宽高均为,1,的单位立方体组成的三维直方图,高对应邻域像素幅角的大小,把,360,度分成,8,等分,立方体的底就是特征点的邻域区域。该区域被分为,4,*,4,个子区域(,opencv,中划分了,(d+2)*(d+2),个区域),邻域内的像素根据坐标位置,把他
21、们归属到这,16,个子区域的一个,再根据邻域像素的幅角的大小,把他们归属到这,8,等分,(opencv,中为,n+2),中的一份,这样每个像素点都能对应到其中的一个立方体里,三维直方图建立起来了。,(,这里分别把每个像素的横纵坐标和幅角都进行了归一化处理,),。,19,横纵坐标,+d/2,横,纵,坐,标,减,0.5,6.,三线性插值的计算,-,坐标平移,20,2024/11/22 周五,6.,三线性插值的计算,x,y,正方体的中点,同时是立方体的顶点,显然,正方体的中心应该代表着该正方体,但落入正方体的邻域像素不可能都在中心,因此,根据它对中心点位置的贡献大小进行加权处理,即在正方体内,根据像
22、素点相对于正方体的距离,对梯度幅值做加权处理。,在实际应用中,我们需要经过坐标平移,把中心点平移到正方体的顶点上,这样只要计算出正方体内的点对正方体的,8,个顶点的贡献大小即可。,根据三线性插值法,对某点的贡献值是以该顶点和正方体内的点为对角线的两个顶点,所构成的立方体的体积。,21,6.,三线性插值的计算,-,程序实现,根据三线性插值法,对某点的贡献是以该顶点和正方体内的点为对角线的两个顶点,所构成的立方体的体积:,22,6.,描述子归一化处理,经过上述处理后我们得出,128,维描述子,在,opencv,中,一共对描述子进行了两次,归一化处理。,第一次使用一下公式对,描述子进行归一化处理,并对大于,0.2,的描述子,进行截断处理:,假设经过第一次归一化处理后描述子用 表示,第二次归一化操作是:,其中分母要大于,FLT_EPSILON,#define FLT_EPSILON 1.192092896e-07F,23,24,2024/11/22 周五,25,2024/11/22 周五,26,2024/11/22 周五,27,2024/11/22 周五,28,2024/11/22 周五,
©2010-2025 宁波自信网络信息技术有限公司 版权所有
客服电话:4008-655-100 投诉/维权电话:4009-655-100