OpenCV联合C++/Qt 学习笔记(二十)----Harri角点检测、Shi-Tomas角点检测及亚像素级别角点位置优化

一、Harri角点检测

1、Harri角点介绍

**角点:**图像中存在物体边缘角落上的点或者是一些其他特殊位置的点。

**Harri角点:**定义一个矩形区域,将这个矩形区域放置在图像中,求取这个区域内所有的像素值之和,之后移动这个区域再次计算像素值之和,如果移动前和移动后两者之间的差值比较小,那么就不是Harri角点,如果两者之间的差值比较大,那么就认定为移动之前所覆盖的区域内存在一个角点。

Harris 判定公式:

​​​​​​​ ​​​​​​​

存在问题:

  • 参数 kkk 需要人工调整
  • 不同图像效果差异较大

2、相关函数

cpp 复制代码
/* 用途:用于检测图像中的Harris角点,
       即图像中"两个方向灰度变化都非常明显"的位置 */
void cv::cornerHarris( InputArray src, OutputArray dst, int blockSize,
                                int ksize, double k,
                                int borderType = BORDER_DEFAULT );
/*
src:待检测Harris角点的输入图像,图像必须是CV_8U或者CV_32F的单通道灰度图像
dst:存放Harris评价系数的R矩阵,数据类型为CV_32F的单通道图像,与输入图像具有相同的尺寸
blockSize:邻域大小,一般取值为2
ksize:Sobel算子的半径,用于得到梯度信息
k:计算Harris评价系数R的权重系数,一般取值范围为0.02 ~ 0.04
borderType:像素外推算法标志
*/
cpp 复制代码
/* 用途:用于将检测到的特征点绘制到图像上,
       方便观察和分析特征点位置、
       尺寸以及方向信息 */
void cv::drawKeypoints( InputArray image, const std::vector<KeyPoint>& keypoints,
                     InputOutputArray outImage,
                     const Scalar& color=Scalar::all(-1),         
                     DrawMatchesFlags flags=DrawMatchesFlags::DEFAULT );
/*
image:输入原始图像
keypoints:特征点集合,通常由SIFT、SURF、ORB、FAST、Harris等特征检测算法得到
outImage:输出绘制后的图像
color:绘制特征点的颜色,默认值Scalar::all(-1)表示随机颜色
flags:特征点绘制方式标志,用于控制是否绘制方向、尺寸信息等
*/

3、示例代码

cpp 复制代码
    QString imgPath = QApplication::applicationDirPath() + "/Images";
    cv::String s_imgPath = imgPath.toLocal8Bit().data();
    Mat img = imread(s_imgPath + "/lena.jpg", IMREAD_COLOR);
    if (img.empty())
    {
        qDebug() << "图片加载失败, 请确认图像文件名称是否正确";
        return;
    }
    /*转成灰度图*/
    Mat gray;
    cvtColor(img, gray, COLOR_BGR2GRAY);
    /*计算Harris系数*/
    Mat harris;
    int blockSize = 2;/*邻域半径*/
    int apertureSize = 3;
    cornerHarris(gray, harris, blockSize, apertureSize, 0.04);

    /*归一化便于进行数值比较和结果显示*/
    Mat harrisn;
    normalize(harris, harrisn, 0, 255, NORM_MINMAX);
    /*将图像的数据类型变为CV_8U*/
    convertScaleAbs(harrisn, harrisn);

    /*寻找Harris角点*/
    vector<KeyPoint> keyPoints;
    for (int row = 0; row < harrisn.rows; row++)
    {
        for (int col = 0; col < harrisn.cols; col++)
        {
            int R = harrisn.at<uchar>(row,col);
            if (R > 125)
            {
                /*将角点存入KeyPoint中*/
                KeyPoint keyPoint;
                keyPoint.pt.y = row;
                keyPoint.pt.x = col;
                keyPoints.push_back(keyPoint);
            }
        }
    }
    drawKeypoints(img, keyPoints, img);
    imshow("harrisn", harrisn);
    imshow("img", img);
    waitKey(0);
    destroyAllWindows();

二、Shi-Tomas角点检测

1、Shi-Tomas角点介绍

Shi-Tomasi 判定公式:

​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​

  • 取两个特征值中的较小值
  • 如果最小特征值仍然很大,说明两个方向变化都明显,则认为是角点

2、相关函数

cpp 复制代码
/* 用途:用于检测图像中"质量较好"的角点,
       自动筛选出稳定且明显的特征点。
       默认使用Shi-Tomasi角点检测算法,
       相比Harris角点,对跟踪任务通常更加稳定 */
void cv::goodFeaturesToTrack( InputArray image, OutputArray corners,
                        int maxCorners, double qualityLevel, double minDistance,
                        InputArray mask = noArray(), int blockSize = 3,
                        bool useHarrisDetector = false, double k = 0.04 );
/*
image:输入图像,必须为8位或32位单通道灰度图像
corners:输出检测到的角点坐标集合
maxCorners:要寻找的角点数目
qualityLevel:角点阈值与最佳角点的关系,又称质量等级,当参数为0.01,表示焦点阈值时最佳角点的0.01倍
minDistance:两个角点之间允许的最小距离,用于避免角点过于密集
mask:掩码矩阵,表示检测角点的区域
blockSize:计算梯度协方差矩阵的尺寸
useHarrisDetector:是否使用Harris角点检测,false表示使用Shi-Tomasi算法
k:Harris角点检测中的权重系数,仅在useHarrisDetector=true时有效
*/

3、示例代码

cpp 复制代码
    QString imgPath = QApplication::applicationDirPath() + "/Images";
    cv::String s_imgPath = imgPath.toLocal8Bit().data();
    Mat img = imread(s_imgPath + "/lena.jpg", IMREAD_COLOR);
    if (img.empty())
    {
        qDebug() << "图片加载失败, 请确认图像文件名称是否正确";
        return;
    }
    /*转成灰度图*/
    Mat gray;
    cvtColor(img, gray, COLOR_BGR2GRAY);
    /*提取角点*/
    int maxCorners = 100;/*检测角点数目*/
    double quality_level = 0.01;/*质量等级,或者说阈值与最佳角点的比例关系*/
    double minDistance = 0.04;/*两个角点之间的最小欧氏距离*/
    vector<Point2f> corners;
    goodFeaturesToTrack(gray, corners, maxCorners, quality_level, minDistance, Mat(), 3, false);

    /*绘制角点*/
    vector<KeyPoint> keyPoints;/*存放角点的KeyPoint类,用于后期绘制角点时使用*/
    for (int i = 0; i < corners.size(); i++)
    {
        /*将角点存入KeyPoint中*/
        KeyPoint keyPoint;
        keyPoint.pt = corners[i];
        keyPoints.push_back(keyPoint);
    }
    drawKeypoints(img, keyPoints, img);

    imshow("img", img);
    waitKey(0);
    destroyAllWindows();

三、亚像素级别角点位置优化

1、亚像素级别角点位置优化原理介绍

**亚像素级别角点位置优化是指:**在已经检测到角点的大致像素位置后,再进一步计算,使角点坐标精确到"小数级别"。

**核心思想:**通过分析角点邻域灰度变化,迭代计算更精确的角点位置,使角点坐标不再局限于整数像素,而能够达到小数级精度。

2、相关函数

cpp 复制代码
/* 用途:用于对已有角点位置进行亚像素级精度优化,
       提高角点定位准确性 */
void cv::cornerSubPix( InputArray image, InputOutputArray corners,
                                Size winSize, Size zeroZone,
                                TermCriteria criteria );
/*
image:输入图像,必须是CV_8U或者CV_32F的单通道灰度图像
corners:角点坐标,既是输入的角点坐标又是精确后的角点坐标
winSize:搜索窗口的一半尺寸,必须是整数,实际的搜索窗口尺寸比该参数的2倍大1
zeroZone:搜索区域中间死区大小的一半,即不提取像素点的区域,(-1,-1)表示没有死区
criteria:终止角点优化迭代的条件
*/

3、示例代码

cpp 复制代码
    QString imgPath = QApplication::applicationDirPath() + "/Images";
    cv::String s_imgPath = imgPath.toLocal8Bit().data();
    Mat img = imread(s_imgPath + "/lena.jpg", IMREAD_COLOR);
    if (img.empty())
    {
        qDebug() << "图片加载失败, 请确认图像文件名称是否正确";
        return;
    }
    /*转成灰度图*/
    Mat gray;
    cvtColor(img, gray, COLOR_BGR2GRAY);
    /*提取角点*/
    int maxCorners = 100;/*检测角点数目*/
    double quality_level = 0.01;/*质量等级,或者说阈值与最佳角点的比例关系*/
    double minDistance = 0.04;/*两个角点之间的最小欧氏距离*/
    vector<Point2f> corners;
    goodFeaturesToTrack(gray, corners, maxCorners, quality_level, minDistance, Mat(), 3, false);

    
    /*计算亚像素级别角点坐标*/
    vector<Point2f> cornersSub = corners;/*角点备份,防止被函数修改*/
    Size winSize = Size(5, 5);
    Size zeroZone = Size(-1, -1);
    TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 40, 0.001);
    cornerSubPix(gray, cornersSub, winSize, zeroZone, criteria);


    for (int i = 0; i < corners.size(); i++)
    {
        string str = to_string(i);
        cout << i << "Coordinates: " << corners[i] << " Fine coordinates: " << cornersSub[i] << endl;
    }
    waitKey(0);
    destroyAllWindows();
相关推荐
许长安1 小时前
rpc和http的区别
经验分享·笔记·网络协议·http·rpc
萧戈1 小时前
C/C++ 运行时库概念详解
c语言·c++
十五年专注C++开发1 小时前
QFluentKit: 一个基于 Qt Widgets 的 Fluent Design 风格 UI 组件库
开发语言·c++·qt·ui·qfluentkit
白小沫1 小时前
TortoiseSVN 的每个菜单功能是什么??
笔记·学习
奶茶精Gaaa1 小时前
精彩bug--批量修改绩效系数溢出报500
学习
叶~小兮1 小时前
K8S-Helm与灰度发布学习笔记
笔记·学习·kubernetes
sheeta19981 小时前
vue_vuex笔记
javascript·vue.js·笔记
Hua-Jay1 小时前
OpenCV联合C++/Qt 学习笔记(十九)----图像分割
c++·笔记·qt·opencv·学习
kyle~1 小时前
调试器---GDB(Linux/Unix平台下编译型语言,C++、Go、Rust)
linux·c++·unix