Harris角点检测及代码分析

角点是图像亮度发生剧烈变化和图像边缘曲线上曲率极大值点,是目前很多图像关键点提取算法的基础,也是研究物体移动时可选取的参考点。本文主要记录Harris角点检测步骤,并对OpenCV1.0的代码进行分析。

一、理论知识

Harris角点的理论请参考【Harris角点】,这里只总结一下:

  1. 自相关函数由一阶泰勒展开后可近似成一个二次项函数, [Δx,Δy]M(x,y)[ΔxΔy]
  2. 研究 M(x,y) 决定的椭圆,发现角点的短轴和长轴值都比较大,且相互接近,可形式化为 detMα(traceM)2>Rt

Harris的一些性质

  1. 对亮度和对比度的变化不敏感;
  2. 具有旋转不变性;
  3. 不具有尺度不变性;
二、算法流程

Harris角点提取为以下步骤:

  1. Ix Iy ,OpenCV中使用了sobel算子求梯度,其中 x 方向Gx=121000121 y 方向为GxT,其中 M 的形式为[ABBC]

  2. Ix2 Iy2 Ixy 进行高斯加权,OpenCV使用了均值权

  3. 计算 R=detMα(traceM)2>Rt Rt 一般为了自适应图像对比度,会选择 βmaxR
  4. 在一定窗口内进行非极大值抑制,局部最大值点即为图像中的角点。
三、代码分析

完整的代码可以参见Ronny写的【Harris角点检测的C++实现代码】,这里我们分析OpenCV1.0的代码。OpenCV1.0没有提供完整的函数提取Harris角点,cvCornerHarris()函数仅计算出每个像素单元的 R <script type="math/tex" id="MathJax-Element-18">R</script>值,如下:
文件:./cv/src/cvcorner.cpp

void cvCornerHarris(...)
{
    // 一些参数检查
    icvCornerEigenValsVecs(...);
}
void icvCornerEigenValsVecs()
{
    CvBoxFilter blur_filter;    // 窗口均值滤波器,./cv/include/cv.hpp中有声明
    // 一些参数检查和预处理
    ipp_sobel_vert(...);        // 计算水平梯度
    ipp_sobel_horiz(...);       // 计算垂直梯度
    // 将M矩形做成w*h*3的结构,第一通道放I_x^2,第二通道放I_yx,第三通道为I_y^2
    blur_filter.process(...)    // 窗口均值加权处理
    icvCalcHarris(...)          // 计算R值
}

Ronny的代码中非极大值抑制时用图像膨胀&&原图的方法,有缺陷,容易出现块状现象,以下是我的完整代码。

int HarrisCorner(IplImage *imgSrc, std::vector<CvPoint> &corners)
{
    assert(imgSrc->nChannels == 3);

    corners.clear();

    CvSize imgSz = cvGetSize(imgSrc);
    IplImage *gray = cvCreateImage(imgSz, 8, 1);
    cvCvtColor(imgSrc, gray, CV_BGR2GRAY);

    IplImage *response = cvCreateImage(imgSz, 32, 1);
    cvCornerHarris(gray, response, 3);

    double minValue, maxValue;
    cvMinMaxLoc(response, &minValue, &maxValue);

    double thr = 0.001 * maxValue;
    IplImage *binary = cvCreateImage(imgSz, 8, 1);
    cvThreshold(response, binary, thr, 255, CV_THRESH_BINARY);

    // 非极大值抑制
    for(int i = 1; i < imgSz.height - 1; i ++)
    {
        uchar *pre = (uchar*)(binary->imageData + binary->widthStep * (i - 1));
        uchar *ptr = (uchar*)(binary->imageData + binary->widthStep * i);
        uchar *nex = (uchar*)(binary->imageData + binary->widthStep * (i + 1));
        for(int j = 1; j < imgSz.width - 1; j ++)
        {
            // / 0 0 0 \
            // | 0 1 0 |
            // \ 0 0 0 /
            if(ptr[j] > pre[j-1] && ptr[j] > pre[j] && ptr[j] > pre[j+1] &&
               ptr[j] > ptr[j-1] && ptr[j] > ptr[j+1] &&
               ptr[j] > nex[j-1] && ptr[j] > nex[j] && ptr[j] > nex[j+1])
            {
                corners.push_back(cvPoint(j, i));
            }
        }
    }

    cvReleaseImage(&gray);
    cvReleaseImage(&response);
    cvReleaseImage(&binary);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值