<图像处理> Kitchen-Rosenfeld角点检测

Kitchen-Rosenfeld角点检测原理

Kitchen和Rosenfeld认为角点是那些边缘曲线曲率和梯度幅值都很大的点,因此他们提出了使用曲率k与梯度幅值g的乘积来计算角点响应函数C的方法:
C = k g = k ( I x 2 − I y 2 ) 1 / 2 = I x x I y 2 + I y y I x 2 − 2 I x y I x I y I x 2 + I y 2 ( 1 ) C=kg=k(I_x^2-I_y^2)^{1/2} = \frac {I_{xx}I_y^2+I_{yy}I_x^2-2I_{xy}I_xI_y}{I_x^2+I_y^2}(1) C=kg=k(Ix2Iy2)1/2=Ix2+Iy2IxxIy2+IyyIx22IxyIxIy1
C的极值点所对应的像素即为角点。 I x , I y I_x,I_y IxIy为图像I的一阶导数,即:
I x = ∂ I ∂ x , I y = ∂ I ∂ y I_x=\frac{\partial I}{\partial x},I_y=\frac{\partial I}{\partial y} Ix=xIIy=yI
I x x , I y y , I x y I_{xx},I_{yy},I_{xy} IxxIyyIxy为图像I的二阶导数,即:
I x x = ∂ 2 I ∂ x 2 , I y y = ∂ 2 I ∂ y 2 , I x y = ∂ 2 I ∂ x y I_{xx}=\frac{\partial^2 I}{\partial x^2},I_{yy}=\frac{\partial^2 I}{\partial y^2},I_{xy}=\frac{\partial^2 I}{\partial xy} Ixx=x22IIyy=y22IIxy=xy2I
由于(1)式的分母恒大于0,它不改变角点响应函数的相对值,因此在实际应用中,只计算分子部分。

检测步骤

  1. 计算图像一阶、二阶导数;
  2. 利用(1)式分子,计算角点响应函数;
  3. 对角点响应函数进行非极大值抑制,并设定阈值,得到角点。

该方法对噪声比较敏感,因为使用了基于灰度的二阶偏导。

OpenCV函数

void cv::preCornerDetect(InputArray src, OutputArray dst, int ksize, int borderType = BORDER_DEFAULT)	

Parameters
src				输入图像,单通道8位整型或者32位浮点型;
dst				输出32位图像;
ksize			Sobel算子核尺寸;
borderType		边缘填充方法,但BORDER_WRAP不支持;

OpenCV源码分析

void cv::preCornerDetect( InputArray _src, OutputArray _dst, int ksize, int borderType )
{
    CV_INSTRUMENT_REGION();

    int type = _src.type();
    CV_Assert( type == CV_8UC1 || type == CV_32FC1 );

    CV_OCL_RUN( _src.dims() <= 2 && _dst.isUMat(),
                ocl_preCornerDetect(_src, _dst, ksize, borderType, CV_MAT_DEPTH(type)))

    Mat Dx, Dy, D2x, D2y, Dxy, src = _src.getMat();
    _dst.create( src.size(), CV_32FC1 );
    Mat dst = _dst.getMat();

	//Sobel算子计算一阶导数、二阶偏导
    Sobel( src, Dx, CV_32F, 1, 0, ksize, 1, 0, borderType );
    Sobel( src, Dy, CV_32F, 0, 1, ksize, 1, 0, borderType );
    Sobel( src, D2x, CV_32F, 2, 0, ksize, 1, 0, borderType );
    Sobel( src, D2y, CV_32F, 0, 2, ksize, 1, 0, borderType );
    Sobel( src, Dxy, CV_32F, 1, 1, ksize, 1, 0, borderType );

    double factor = 1 << (ksize - 1);
    if( src.depth() == CV_8U )
        factor *= 255;
    factor = 1./(factor * factor * factor);
#if CV_SIMD128
    float factor_f = (float)factor;
    v_float32x4 v_factor = v_setall_f32(factor_f), v_m2 = v_setall_f32(-2.0f);
#endif

    Size size = src.size();
    int i, j;
    for( i = 0; i < size.height; i++ )
    {
        float* dstdata = dst.ptr(i);
        const float* dxdata = Dx.ptr(i);
        const float* dydata = Dy.ptr(i);
        const float* d2xdata = D2x.ptr(i);
        const float* d2ydata = D2y.ptr(i);
        const float* dxydata = Dxy.ptr(i);

        j = 0;

//指令集加速
#if CV_SIMD128
        {
            for( ; j <= size.width - v_float32x4::nlanes; j += v_float32x4::nlanes )
            {
                v_float32x4 v_dx = v_load(dxdata + j);
                v_float32x4 v_dy = v_load(dydata + j);

                v_float32x4 v_s1 = (v_dx * v_dx) * v_load(d2ydata + j);
                v_float32x4 v_s2 = v_muladd((v_dy * v_dy),  v_load(d2xdata + j), v_s1);
                v_float32x4 v_s3 = v_muladd((v_dy * v_dx) * v_load(dxydata + j), v_m2, v_s2);

                v_store(dstdata + j, v_s3 * v_factor);
            }
        }
#endif

		//计算每个像素的响应函数
        for( ; j < size.width; j++ )
        {
            float dx = dxdata[j];
            float dy = dydata[j];
            dstdata[j] = (float)(factor*(dx*dx*d2ydata[j] + dy*dy*d2xdata[j] - 2*dx*dy*dxydata[j]));
        }
    }
}

参考

  1. 《图像局部特征检测与描述》

你可能感兴趣的:(图像处理,#,OpenCV,图像处理)