图像特征检测各种方法简单介绍 更新ing

1.SIFT 

特点
图像的局部特征,对旋转、尺度缩放、亮度变化保持不变,对视角变化、仿射变换、噪声也保持一定程度的稳定性。

  • 独特性好,信息量丰富,适用于海量特征库进行快速、准确的匹配。
  • 多量性,即使是很少几个物体也可以产生大量的SIFT特征
  • 高速性,经优化的SIFT匹配算法甚至可以达到实时性
  • 扩招性,可以很方便的与其他的特征向量进行联合。

可以解决的问题
目标的自身状态、场景所处的环境和成像器材的成像特性等因素影响图像配准/目标识别跟踪的性能,SIFT算法在一定程度上可以解决:

  • 目标的旋转、缩放、平移
  • 图像仿射/投影变换
  • 光照影响
  • 目标遮挡
  • 杂物场景
  • 噪声
     

2.SURF

在积分图像上使用了高斯滤波器对二阶微分模板进行了简化,从而构建了Hessian矩阵元素值,进而缩短了特征提取的时间,提高了效率。

主要特点是快速性,同时也具有尺度不变的特性,对光照变化和仿射、透视变化也具有较强的鲁棒性(系统在其特性或参数发生摄动时仍可使品质指标保持不变的性能)

static void fastHessianDetector(const Mat& sum, const Mat& msum, vector<KeyPoint>& keypoints,
    int nOctaves, int nOctaveLayers, float hessianThreshold)
{
    /*first Octave图像采样的步长,第二组的时候加倍,以此内推
    增加这个值,将会加快特征点检测的速度,但是会让特征点的提取变得不稳定*/
    const int SAMPLE_STEP0 = 1;
 
    int nTotalLayers = (nOctaveLayers + 2)*nOctaves; // 尺度空间的总图像数
    int nMiddleLayers = nOctaveLayers*nOctaves; // 用于检测特征点的层的 总数,也就是中间层的总数
 
    vector<Mat> dets(nTotalLayers); // 每一层图像 对应的 Hessian行列式的值
    vector<Mat> traces(nTotalLayers); // 每一层图像 对应的 Hessian矩阵的迹的值
    vector<int> sizes(nTotalLayers); // 每一层用的 Harr模板的大小
    vector<int> sampleSteps(nTotalLayers); // 每一层用的采样步长 
    vector<int> middleIndices(nMiddleLayers); // 中间层的索引值
 
    keypoints.clear();
 
    // 为上面的对象分配空间,并赋予合适的值
    int index = 0, middleIndex = 0, step = SAMPLE_STEP0;
 
    for (int octave = 0; octave < nOctaves; octave++)
    {
        for (int layer = 0; layer < nOctaveLayers + 2; layer++)
        {
            /*这里sum.rows - 1是因为 sum是积分图,它的大小是原图像大小加1*/
            dets[index].create((sum.rows - 1) / step, (sum.cols - 1) / step, CV_32F); // 这里面有除以遍历图像用的步长
            traces[index].create((sum.rows - 1) / step, (sum.cols - 1) / step, CV_32F);
            sizes[index] = (SURF_HAAR_SIZE0 + SURF_HAAR_SIZE_INC*layer) << octave;
            sampleSteps[index] = step;
 
            if (0 < layer && layer <= nOctaveLayers)
                middleIndices[middleIndex++] = index;
            index++;
        }
        step *= 2;
    }
    // Calculate hessian determinant and trace samples in each layer
    for (int i = 0; i < nTotalLayers; i++)
    {
        calcLayerDetAndTrace(sum, sizes[i], sampleSteps[i], dets[i], traces[i]);
    }
 
    // Find maxima in the determinant of the hessian
    for (int i = 0; i < nMiddleLayers; i++)
    {
        int layer = middleIndices[i];
        int octave = i / nOctaveLayers;
        findMaximaInLayer(sum, msum, dets, traces, sizes, keypoints, octave, layer, hessianThreshold, sampleSteps[layer]);
    }
 
    std::sort(keypoints.begin(), keypoints.end(), KeypointGreater());
}

3.ORB  

使用FAST进行特征点检测,然后用BREIF进行特征点的特征描述,但是BRIEF并没有特征点方向的概念,所以ORB在BRIEF基础上引入了方向的计算方法,并在点对的挑选上使用贪婪搜索算法,挑出了一些区分性强的点对用来描述二进制串。 

对于SIFT SURF ORB

  • 三种方法在对特征点的描述的细致程度上 SIFT高于SURF 、SURF高于ORB。但是从运行的速度快慢来看,整个顺序恰好相反。
  • 在选择特征提取方法的时候要根据实际应用情况来选择,如进行离线的图像的拼接,3D建模等对时间要求不是很严格应用,可以选择SIFT。但是当应用场合是在线的实时检测,就要选择比较快速的 SURF或ORB

4.LoG   

因为拉普拉斯算子对噪声很敏感,所以首先利用高斯对图像进行降噪处理,再采用拉普拉斯算子进行边缘检测,就可以提高对噪声和离散点的鲁棒性

即利用二阶高斯导数(也叫拉普拉斯变换)与原始信号(图像)卷积,通过检测局部极值获得角点。

特别适用于以突出图像中的孤立点、孤立线或线端点为目的的场合

LoG的斑点检测(类似SIFT):

1.预定义一组方差值(因为不知道待检信号的尺度),对每个方差生成一个二阶高斯模板(待完善

2.对每个方差,将对应的高斯模板与原始信号做卷积(DOH需要将三个模板分别与原始图做卷积,然后计算其加权行列式),得到一组不同尺度的图像集

3.对每个空间位置,比较其在图像集里26(3*3*3-1)个位置(图1-4)的值,如果为极值,则认为在该点有一个斑点(高斯金字塔极值检测)

Mat Feat::getHOGKernel(Size& ksize, double sigma)
{
    Mat kernel(ksize, CV_64F);
    Point centPoint = Point((ksize.width -1)/2, ((ksize.height -1)/2));
    // first calculate Gaussian
    for (int i=0; i < kernel.rows; i++)
    {
        double* pData = kernel.ptr<double>(i);
        for (int j = 0; j < kernel.cols; j++)
        {
            double param = -((i - centPoint.y) * (i - centPoint.y) + (j - centPoint.x) * (j - centPoint.x)) / (2*sigma*sigma);
            pData[j] = exp(param);
        }
    }
    double maxValue;
    minMaxLoc(kernel, NULL, &maxValue);
    for (int i=0; i < kernel.rows; i++)
    {
        double* pData = kernel.ptr<double>(i);
        for (int j = 0; j < kernel.cols; j++)
        {
            if (pData[j] < EPS* maxValue)
            {
                pData[j] = 0;
            }
        }
    }

    double sumKernel = sum(kernel)[0];
    if (sumKernel != 0)
    {
        kernel = kernel / sumKernel;
    }
    // now calculate Laplacian
    for (int i=0; i < kernel.rows; i++)
    {
        double* pData = kernel.ptr<double>(i);
        for (int j = 0; j < kernel.cols; j++)
        {
            double addition = ((i - centPoint.y) * (i - centPoint.y) + (j - centPoint.x) * (j - centPoint.x) - 2*sigma*sigma)/(sigma*sigma*sigma*sigma);
            pData[j] *= addition;
        }
    }
    // make the filter sum to zero
    sumKernel = sum(kernel)[0];
    kernel -= (sumKernel/(ksize.width  * ksize.height));    

    return kernel;
}

5.DoH Determinant of Hessian

基本思路和LoG差不多,只不过使用了Hessian矩阵

一张图计算xx,yy,xy三个方向的卷积,然后计算其加权行列式:

理论上,与LOG相比,DOH对细长结构的斑点有较好的抑制作用。 

利用像素点Hessian矩阵(二阶微分)及其行列式值

无论是LoG还是DoH,它们对图像中的斑点进行检测,其步骤都可以分为以下两步:

1)使用不同的σ生成(∂2g∂x2+∂2g∂y2)(∂2g∂x2+∂2g∂y2)或∂2g∂x2,∂2g∂y2,∂2g∂x∂y∂2g∂x2,∂2g∂y2,∂2g∂x∂y模板,并对图像进行卷积运算;

2)在图像的位置空间与尺度空间中搜索LoG与DoH响应的峰值。

6.DoG

高斯差分法,SIFT的第一步。通过将目标图像与高斯函数进行卷积运算得到一幅目标图像的低通滤波结果

LoG比DoG明显需要更多的加法运算和乘法运算。虽然DoG需要在每层金字塔多做一次高斯操作,但通过减法取代LoG核的计算过程,显著减少了运算次数,大大节省了运算时间。

通过数学公式可以发现(待补充):可以用DoG 算子来近似 LoG算子

7.Harris 

基于图像灰度的一阶导数矩阵检测方法。检测器的主要思想是局部自相似性/自相关性,即在某个局部窗口内图像块与在各个方向微小移动后的窗口内图像块的相似性。

Harris 算子的优越性有:

  1. 计算简单:Harris 算子中只用到灰度的一阶差分以及滤波,操作简单。
  2. 提取的点特征均匀而且合理:Harris 算子对图像中的每个点都计算其兴趣值,然后在邻域中选择最优点。实验表明,在纹理信息丰富的区域,Harris 算子可以提取出大量有用的特征点,而在纹理信息少的区域,提取的特征点则较少。
  3. 稳定:Harris算子的计算公式中只涉及到一阶导数,因此对图像旋转、灰度变化、噪声影响和视点变换不敏感,它也是比较稳定的一种点特征提取算子。

Harris 算子的局限性有:

  1.       它对尺度很敏感,不具有尺度不变性。(不管原图尺度是多少,在包含了所有尺度的尺度空间下都能找到那些稳定的极值点,这样就做到了尺度不变)
  2.       提取的角点是像素级的。

8.FAST  

基于加速分割测试的FAST算法可以快速地提取出角点特征。

  1. 在图像中选取一个像素点,来判断它是否为关键点。表示像素点的灰度值。
  2. 选择适当的阈值。
  3. 在像素点的周围选择16个像素点进行测试。
  4. 如果在这16个像素点中存在个连续像素点的灰度值都高于,或者低于,那么像素点被认为是一个角点。
  5.  一种更加快的改进是首先检测像素点周围的四个点(1,5,9,12)中是否有三个点满足阈值要求。如果不满足,则直接跳过,如果满足,则继续使用前面的算法,全部判断16个点中是否有12个满足条件。

上述算法效率很高,但是缺点如下所示:

  1. 获得的候选点比较多。 
  2. 检测出来的角点不是最优的,因为它的效果取决于要解决的问题和角点的分布情况。
  3. 对于角点分析的结果被丢弃了。
  4. 检测到的很多角点都是连在一起的。

前3个问题可以通过机器学习的方法解决(待完善),最后一个问题可以使用非最大值抑制的方法解决。

非极大值抑制,如下所示:

  1. 对所有检测到的角点构建一个打分函数。就是像素点与周围16个像素点差值的绝对值之和。
  2. 考虑两个相邻的角点,并比较它们的值。
  3. 值较低的角点将会被删除

总体来说,FAST算子比其它角点检测算法都快,但是当图像中的噪点较多时,它的健壮性并不好,而且算法的效果还依赖于阈值。并且FAST算子不产生多尺度特征而且FAST角点没有方向信息,这样就会失去旋转不变性。

9.BRIEF 

BRIEF是对已检测到的特征点进行描述,它是一种二进制编码的描述子,摈弃了利用区域灰度直方图描述特征点的传统方法,大大的加快了特征描述符建立的速度,同时也极大的降低了特征匹配的时间,是一种非常快速,很有潜力的算法。 

BRIEF仅仅是特征描述子,所以事先要得到特征点的位置,可以利用FAST特征点检测算法Harris角点检测算法或SIFT、SURF等算法检测特征点的位置。接下来在特征点邻域利用BRIEF算法建立特征描述符。

特征点周围邻域内选取若干个像素点对,通过对这些点对的灰度值比较,将比较的结果组合成一个二进制串字符串用来描述特征点。最后,使用汉明距离来计算在特征描述子是否匹配。

算法步骤如下:

1、为减少噪声干扰,先对图像进行高斯滤波(方差为2,高斯窗口为9x9)。

2、以特征点为中心,取SxS的邻域窗口。在窗口内随机选取一对(两个)点,比较二者像素的大小,进行如下二进制赋值。


其中,p(x),p(y)分别是随机点x=(u1,v1),y=(u2,v2)的像素值。

3、在窗口中随机选取N对随机点,重复步骤2的二进制赋值,形成一个二进制编码,这个编码就是对特征点的描述,即特征描述子。(一般N=256)

关于一对随机点的选择方法,原作者测试了以下5种方法,其中方法(2)比较好。

10.BRISK  

具有较好的旋转不变性、尺度不变性,较好的鲁棒性等。在图像配准应用中,速度比较:SIFT<SURF<BRISK<FREAK<ORB,在对有较大模糊的图像配准时,BRISK算法在其中表现最为出色。

BRISK算法主要利用FAST9-16进行特征点检测(为什么是主要?因为用到一次FAST5-8)。要解决尺度不变性,就必须在尺度空间进行特征点检测,于是BRISK算法中构造了图像金字塔进行多尺度表达。

步骤:

特征点检测

  1. 建立尺度空间
  2. 特征点检测
  3. 非极大值抑制
  4. 亚像素插值

特征点描述

  1. 高斯滤波
  2. 局部梯度计算
  3. 特征描述符      

11.FREAK  Fast Retina Keypoint(待完善

可以看出来该算法的一个特点是快速,另外一个特点就是该算法是被人眼识别物体的原理上得到启发提出的。

BRIEF、ORB和BRISK都是特征点周围的邻域像素点对之间的比较形成的二进制串作为特征点的描述符,这种做法有着快速和占用内存低的优点,在如今的移动计算中有很大的优势,但是也遗留了一些问题。比如,如何确定特征点邻域中哪些像素点对进行比较,如何匹配它们呢?

特征点检测方法与BRISK中特征点检测方法相同

上图中每一个黑点代表一个采样点,每个圆圈代表一块感受野,具体在处理时时对该部分图像进行高斯模糊处理,以降低噪声的影响,而且每个圆圈的半径表示了高斯模糊的标准差。这种采样模式与BRISK算法的不同之处在于,每个感受野与感受野之间有重叠的部分。与ORB和BRIEF算法的不同之处在于,ORB和BRIEF算法中的高斯模糊半径都是相同的,而这里采用了这种不同大小的高斯模糊的核函数。作者提出,正是这些不同之处,导致最后的结果更加优秀。通过重叠的感受野,可以获得更多的信息,这些信息可以使最终的描述符更具有独特性。而不同大小的感受野在人体的视网膜中也有这样类似的结构。
最终FREAK算法的采样结构为6、6、6、6、6、6、6、1,这里的6代表每层中有6个采样点并且这6个采样点在一个同心圆中,一共有7个同心圆,最后的1代表的是特征点。

根据视网膜原理进行点对采样,中间密集一些,离中心越远越稀疏。并且由粗到精构建描述子,穷举贪婪搜索找相关性小的。

Canny、Sobel、Prewitt、LoG、Roberts

比Sobel、Prewitt等算子,Canny算法更为优异。Sobel、Prewitt等算子有如下缺点:

  1. 没有充分利用边缘的梯度方向。
  2. 最后得到的二值图,只是简单地利用单阈值进行处理。

而Canny算法基于这两点做了改进,提出了:

  1. 基于边缘梯度方向的非极大值抑制。
  2. 双阈值的滞后阈值处理
     

Robert算子定位比较精确,但由于不包括平滑,所以对于噪声比较敏感。Prewitt算子和Sobel算子都是一阶的微分算子,而前者是平均滤波,后者是加权平均滤波且检测的图像边缘可能大于2个像素。这两者对灰度渐变低噪声的图像有较好的检测效果,但是对于混合多复杂噪声的图像,处理效果就不理想了。LOG滤波器方法通过检测二阶导数过零点来判断边缘点。LOG滤波器中的a正比于低通滤波器的宽度,a越大,平滑作用越显著,去除噪声越好,但图像的细节也损失越大,边缘精度也就越低。所以在边缘定位精度和消除噪声级间存在着矛盾,应该根据具体问题对噪声水平和边缘点定位精度要求适当选取。

讨论和比较了几种常用的边缘检测算子。梯度算子计算简单,但精度不高,只能检测出图像大致的轮廓,而对于比较细的边缘可能会忽略。Prewitt 和Sobel 算子比Roberts 效果要好一些。LOG 滤波器和Canny 算子的检测效果优于梯度算子,能够检测出图像较细的边缘部分。不同的系统,针对不同的环境条件和要求,选择合适的算子来对图像进行边缘检测。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cc_sensii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值