OpenCV之图像特征提取与检测(五) 自定义角点检测器_harris

- 自定义角点检测器基于Harris与Shi-Tomasi角点检测
- 首先通过计算矩阵M得到 λ1 λ2 两个特征值根据他们得到角点响应值
- 然后自己设置阈值实现计算出阈值得到有效响应值的角点位置

void cornerEigenValsAndVecs( // harris时计算 λ1 λ2 ,参数与harris角点检测一致
    InputArray src, 
    OutputArray dst, 
    int blockSize, 
    int ksize, 
    int borderType = BORDER_DEFAULT 
);

代码

    #include "../common/common.hpp"

    static Mat src, gray, harris_dst, harrisRspImg;
    static const char title_harris[] = "corner_detect_harris";
    static int thresh_v_harris = 30;
    static int thresh_max_harris = 100;
    static RNG rng(12345);
    static double harris_min_rsp; // harris 角度响应最小值
    static double harris_max_rsp; // harris 角度响应最大值

    static void corner_detect_harris(int, void*);

    void main(int argc, char** argv)
    {
        src = imread(getCVImagesPath("images/home.jpg"), IMREAD_COLOR);
        imshow("src2-6", src);

        cvtColor(src, gray, CV_BGR2GRAY);
        // 计算特征值 eigon values λ1 λ2
        int blockSize = 3; // blockSize取2或取3,会导致计算出来的角度响应的最大最小值不一样,下面的阈值需要适当调整
        int ksize = 3;
        double k = 0.04;
        harris_dst = Mat::zeros(src.size(), CV_32FC(6)); // 深度为 CV_32F 通道数为6 ,通道数不一定要6 大于等于2就行
        harrisRspImg = Mat::zeros(src.size(), CV_32FC1);
        cornerEigenValsAndVecs(gray, harris_dst, blockSize, ksize, BORDER_DEFAULT); // 计算 λ1 λ2
        // 计算角度响应
        for (int row = 0; row < harris_dst.rows; row++)
        {
            for (int col = 0; col < harris_dst.cols; col++)
            {
                double lambda1 = harris_dst.at<Vec6f>(row, col)[0]; // λ1
                double lambda2 = harris_dst.at<Vec6f>(row, col)[1]; // λ2
                // harris角度响应计算,公式 R = det(M) - k*(trace(M))^2,  det(M)=λ1*λ2, trace(M)=λ1+λ2
                harrisRspImg.at<float>(row, col) = lambda1*lambda2 - k*pow((lambda1 + lambda2), 2);
            }
        }
        minMaxLoc(harrisRspImg, &harris_min_rsp, &harris_max_rsp, 0, 0, Mat());//寻找harrisRspImg中角度响应最大值,最小值,及它们所在的位置,位置参数传0表示不管
        printf("harris_min_rsp=%f, harris_max_rsp=%f\n", harris_min_rsp, harris_max_rsp); //harris_min_rsp = -0.003276, harris_max_rsp = 0.011325

        namedWindow(title_harris, CV_WINDOW_AUTOSIZE);
        createTrackbar("harris thresh:", title_harris, &thresh_v_harris, thresh_max_harris, corner_detect_harris);
        corner_detect_harris(0, 0);

        waitKey(0);
    }

    void corner_detect_harris(int, void*) // 自定义harris角点检测,与harris函数计算的结果差不多
    {
        if (thresh_v_harris < 10) thresh_v_harris = 10;
        Mat retImg = gray.clone();
        cvtColor(retImg, retImg, CV_GRAY2BGR); // 让原图灰度,角点彩色
        //定义阈值, 以 thresh_v_harris / thresh_max_harris 的比例显示角点
        float t = harris_min_rsp + ((double)thresh_v_harris / thresh_max_harris)*(harris_max_rsp - harris_min_rsp);
        for (int row = 0; row < retImg.rows; row++)
        {
            for (int col = 0; col < retImg.cols; col++)
            {
                float v = harrisRspImg.at<float>(row, col);
                if (v > t)
                {
                    // 角度响应大于阈值,在当前位置显示出来,当角度响应阈值设的很低时,因为绘制的多,所以绘制速度会很慢
                    circle(retImg, Point(col, row), 2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 2, 8, 0);
                }
            }
        }
        imshow(title_harris, retImg);
    }

效果图

这里写图片描述

猜你喜欢

转载自blog.csdn.net/huanghuangjin/article/details/81263320