计算机视觉攻略 笔记5 (检测图像中的角点)

检测图像中的角点

参考博客

文献1
文献2

代码程序

#include <iostream>
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

class HarrisDetector{
    
    
private:
    // 32位浮点数型的角点强度图像
    cv::Mat cornerStrength;
    // 32位浮点数型的阈值化角点图像
    cv::Mat cornerTh;
    // 局部最大值图像(内部)
    cv::Mat localMax;
    // 平滑导数的领域尺寸
    int neighborhood;
    // 梯度计算的口径
    int aperture;
    // Harris 参数
    double k;
    // 阈值计算的最大强度
    double maxStrength;
    // 计算得到的阈值(内部)
    double threshold;
    // 非最大抑制的领域尺寸
    int nonMaxSize;
    // 非最大值抑制的内核
    cv::Mat kernel;

public:
    HarrisDetector():neighborhood(3),aperture(3),
                    k(0.01), maxStrength(0.0),
                    threshold(0.01), nonMaxSize(3){
    
    
    }
    // 创建用于非最大值抑制的内核
    void setLocalMaxWindowsize(int nonMaxSize){
    
    
        this->nonMaxSize = nonMaxSize;
    };
    // 检测Harris角点需要两个步骤。首先是计算每个像素的Harris值
    void detect(const cv::Mat& image){
    
    
        // 计算Harris
        cv::cornerHarris(image, cornerStrength,
                         neighborhood,
                         aperture,
                         k);
        // 计算内部阈值
        cv::minMaxLoc(cornerStrength,0,&maxStrength);
        // 检测局部最大值
        cv::Mat dilated;      // 临时图像
        cv::dilate(cornerStrength,dilated, cv::Mat());
        cv::compare(cornerStrength,dilated,localMax,cv::CMP_EQ);
    }
    // 然后,用指定的阈值获得特征点。因为Harris值的可选范围取决于选择的参数,所以阈值被作为质量等级,用最大Harris值的一个比例表示
    // 用Harris值得到角点分布图
    cv::Mat getCornerMap(double qualityLevel){
    
    
        cv::Mat cornerMap;
        // 对角点强度阈值化
        threshold = qualityLevel * maxStrength;
        cv::threshold(cornerStrength, cornerTh, threshold,255, cv::THRESH_BINARY);
        // 转换成8位图像
        cornerTh.convertTo(cornerMap, CV_8U);
        // 非最大值抑制
        cv::bitwise_and(cornerMap,localMax,cornerMap);
        return cornerMap;
    }
    // 用角点分布得到特征点
    void getCorners(std::vector<cv::Point> &points,
                    const cv::Mat& cornerMap){
    
    
        // 迭代遍历像素,得到所有特征点
        for (int y = 0; y < cornerMap.rows; y++){
    
    
            const uchar* rowPty = cornerMap.ptr<uchar>(y);
            for (int x = 0; x < cornerMap.cols; x++){
    
    
                // 如果它是一个特征点
                if (rowPty[x]){
    
    
                    points.push_back(cv::Point(x, y));
                }
            }
        }
    }
    // 用Harris值得到特征点
    void getCorners(std::vector<cv::Point> &points, double qualityLevel){
    
    
        // 获得角点分布图
        cv::Mat cornerMap = getCornerMap(qualityLevel);
        // 获得角点
        getCorners(points, cornerMap);
    }

    // 这个类通过增加非最大值抑制步骤,也改进了Harris角点的检测过程
    // 现在使用cv::circle函数画出检测到的特征点
    // 在特征点的位置画圆形
    void drawOnImage(cv::Mat &image,
                     const std::vector<cv::Point> &points,
                     cv::Scalar color = cv::Scalar(255, 255, 255),
                     int radius = 3, int thickness = 1){
    
    
        std::vector<cv::Point>::const_iterator it = points.begin();
        // 针对所有角点
        while(it != points.end()){
    
    
            // 在每个角点位置画一个园
            cv::circle(image, *it, radius, color, thickness);
            ++it;
        }
    }
};

int main(int argc, char** argv) {
    
    
    if(argc != 2)
    {
    
    
        std::cerr << "don't get the image" << std::endl;
        return -1;
    }
    cv::Mat image = cv::imread(argv[1],cv::IMREAD_GRAYSCALE);
    if(image.empty())
    {
    
    
        std::cout << "don't get the data of image" << std::endl;
        return -1;
    }
    cv::imshow("Original", image);
//     检测Harris角点
//    cv::Mat cornerStrength;
//    cv::cornerHarris(image,                 //input image   单通道8位
//                     cornerStrength,        // output image
//                     3,            // 邻域尺寸
//                     3,                // 口径尺寸
//                     0.01);             // Harris 参数
//    // 对角点强度阈值化
//    cv::Mat harrisCorners;
//    double threshold = 0.0001;
//    cv::threshold(cornerStrength, harrisCorners,
//                  threshold, 255, cv::THRESH_BINARY_INV);
//    cv::imshow("Harris", harrisCorners);
//    cv::waitKey(0);
//    return 0;
    // 创建Harris检测器实力
    HarrisDetector harris;
    // 计算Harris值
    harris.detect(image);
    // 检测Harris角点
    std::vector<cv::Point> pts;
    harris.getCorners(pts, 0.02);
    // 画出Harris角点
    harris.drawOnImage(image, pts);
    cv::imshow("Corners", image);
    cv::waitKey(0);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jlm7689235/article/details/107742478