OpenCV开发笔记六十一红胖子8分钟带你深入了解ShiTomasi角点检测图文并茂浅显易懂程序源码

10次阅读

共计 5595 个字符,预计需要花费 14 分钟才能阅读完成。

若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/106436768
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究
红胖子 (红模仿) 的博文大全:开发技术集合(包含 Qt 实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…(点击传送门)

OpenCV 开发专栏(点击传送门)

上一篇:《OpenCV 开发笔记(六十):红胖子 8 分钟带你深入了解 Harris 角点检测(图文并茂 + 浅显易懂 + 程序源码)》
下一篇:持续补充中…

前言

  红胖子,来也!
  做识别,有时候遇到需求,比如识别一个三角形,并求得三角形三个顶点的角度,这种属于教育集合场景,还有其他类似场景,那么检测角点就显得很重要了。

Demo

  
  
  
  
  

图像特征三大类型

  • 边缘:图像强度发生突变的区域,其实就是高强度梯度区域;
  • 角点:两个边缘相交的地方,看起来像一个角;
  • 斑点:按特征划分的区域,强度特别高、强度特别低或具备特定纹理的区域;

Shi-Tomasi 角点

概述

  Shi-Tomasi 角点检测是改进了 Harris 算法,次算法最原始的定义是将矩阵 M 的行列式与 M 的迹想见,再将差值进行同预先给定的预制进行比较,后来再次改进,若两个特征值中较小的一个大于最小阈值,则会得到强角点。

原理

  由于 Harris 算法的稳定性和 k 值有关,Shi-Tomasi 发现,角点的稳定性和矩阵 M 的较小特征值有关,改进的 Harris 算法即直接计算出矩阵 M 的特征值,用较小的特征值与阈值比较,大于阈值的即为强特征点。

Harris 角点概述

  Harris 角点检测是一种基于灰度图像的角点提取算法,稳定性高,在 opencv 中 harris 角点检测的性能相对较低,因为其使用了高斯滤波。
  基于灰度图像的角点检测又分为基于梯度、基于模板和基于模板梯度组合三类型的方法,而 Harris 算法就是基于灰度图像中的基于模板类型的算法。

Harris 角点原理

  人眼对角点的识别通常是通过一个局部的小窗口内完成的:如果在各个方向上移动这个小窗口,窗口内的灰度发生了较大的变化,那么说明窗口内存在角点,具体分为以下三种情况:

  • 如果在各个方向移动,灰度几乎不变,说明是平坦区域;
  • 如果只沿着某一个方向移动,灰度几乎不变,说明是直线;
  • 如果沿各个方向移动,灰度均发生变化,说明是角点。

  基本的原理,如下图:
  
  具体的计算公式如下:

  
  泰勒展开:
  
  代入得到:
  
  其中:
  
  二次项函数本质上就是一个椭圆函数,椭圆的扁平率和尺寸是由矩阵 M 的两个特征值决定的。
    
  
  矩阵 M 的两个特征值与图像中的角点,边缘,平坦区域的关系。
  Harris 定义角点响应函数即:
  
  即 R =Det(M)-ktrace(M)trace(M),k 为经验常数 0.04~0.06。
  定义当 R >threshold 时且为局部极大值的点时,定义为角点。

Shi-Tomasi 检测角点函数原型

// 重载函数:九个参数
void goodFeaturesToTrack( InputArray image,
                          OutputArray corners,
                          int maxCorners,
                          double qualityLevel,
                          double minDistance,
                          InputArray mask = noArray(),
                          int blockSize = 3,
                          bool useHarrisDetector = false,
                          double k = 0.04);
// 重载函数:十个参数
void goodFeaturesToTrack( InputArray image,
                          OutputArray corners,
                          int maxCorners,
                          double qualityLevel,
                          double minDistance,
                          InputArray mask,
                          int blockSize,
                          int gradientSize,
                          bool useHarrisDetector = false,
                          double k = 0.04 );
  • 参数一:InputArray 类型的 image,输入图像,即源图像,填 Mat 类的对象 即可,且须为单通道 8 位或者浮点型 32 位单通道图像;
  • 参数二:OutputArray 类型的 corners,检测到的角点的输出向量;
  • 参数三:int 类型的 maxCorners,角点的最大数据量;
  • 参数四:double 类型的 qualityLevel,角点检测可接受的最小特征值。其实实际用于过滤角点的最小特征是 qualityLevel 与图像中最大特征值的乘积。所以 qualityLevel 通常不会超过 1(常用的值为 0.10 或者 0.01)。检测完后所有的交点后,还要进一步提出掉一些距离较近的角点;
  • 参数五:double 类型的 minDistance,角点之间的最细小距离,次参数用于保证返回的角点之间的距离不小于 minDistance;
  • 参数六:InputArray 类型的 mask,可选参数,表示感情兴的区域,默认为 noArray(),若此参数非空则必须需为 CV_8UC1 类型,且和第一个参数 image 有相同的尺寸;
  • 参数七:int 类型的 blockSize,有默认值 3,是计算导数自相关矩阵时指定的领域范围;
  • 参数八:bool 类型的 useHarrisDetector,只是是否使用 Harris 角点检测,默认为 false,不使用;
  • 参数九:double 类型的 k,为用于设置 Hessian 自相关矩阵韩烈士的相对权重的权重系数,默认值为 0.04;

Demo 源码

void OpenCVManager::testShiTomasi()
{
    QString fileName1 =
"E:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.jpg";
    int width = 400;
    int height = 300;

    cv::Mat srcMat = cv::imread(fileName1.toStdString());
    cv::resize(srcMat, srcMat, cv::Size(width, height));

    cv::String windowName = _windowTitle.toStdString();
    cvui::init(windowName);

    cv::Mat windowMat = cv::Mat(cv::Size(srcMat.cols * 2, srcMat.rows * 3),
                                srcMat.type());

    int threshold1 = 200;
    int threshold2 = 100;
    int qualityLevel = 1;
    int minDistance = 10;
    while(true)
    {windowMat = cv::Scalar(0, 0, 0);

        cv::Mat mat;

        cv::Mat tempMat;
        // 原图先 copy 到左边
        mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1),
                        cv::Range(srcMat.cols * 0, srcMat.cols * 1));
        cv::addWeighted(mat, 0.0f, srcMat, 1.0f, 0.0f, mat);

        {
            // 灰度图
            cv::Mat grayMat;
            cv::cvtColor(srcMat, grayMat, cv::COLOR_BGR2GRAY);
            // copy
            mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
                            cv::Range(srcMat.cols * 0, srcMat.cols * 1));
            cv::Mat grayMat2;
            cv::cvtColor(grayMat, grayMat2, cv::COLOR_GRAY2BGR);
            cv::addWeighted(mat, 0.0f, grayMat2, 1.0f, 0.0f, mat);

            // 均值滤波
            cv::blur(grayMat, tempMat, cv::Size(3, 3));

            cvui::printf(windowMat, width * 1 + 20, height * 0 + 20, "threshold1");
            cvui::trackbar(windowMat, width * 1 + 20, height * 0 + 40, 200, &threshold1, 0, 255);
            cvui::printf(windowMat, width * 1 + 20, height * 0 + 80, "threshold2");
            cvui::trackbar(windowMat, width * 1 + 20, height * 0 + 100, 200, &threshold2, 0, 255);

            // canny 边缘检测
            cv::Canny(tempMat, tempMat, threshold1, threshold2);
            // copy
            mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
                            cv::Range(srcMat.cols * 1, srcMat.cols * 2));
            cv::cvtColor(tempMat, grayMat2, cv::COLOR_GRAY2BGR);
            cv::addWeighted(mat, 0.0f, grayMat2, 1.0f, 0.0f, mat);

            cvui::printf(windowMat, width * 1 + 20, height * 0 + 140, "qualityLevel / 100.0f");
            cvui::trackbar(windowMat, width * 1 + 20, height * 0 + 160, 200, &qualityLevel, 1, 100);
            cvui::printf(windowMat, width * 1 + 20, height * 0 + 200, "minDistance");
            cvui::trackbar(windowMat, width * 1 + 20, height * 0 + 220, 200, &minDistance, 1, 100);


            // Shi-Tomasi 角点检测
            std::vector<cv::Point2f> corners;
            cv::goodFeaturesToTrack(grayMat,    // 输入图像
                                    corners,    // 输出角点
                                    100,        // 最大输出角点数量
                                    qualityLevel / 100.0f,  // 最小特征值
                                    minDistance,    // 最小间隔距离
                                    cv::noArray(),  // 感兴趣的区域
                                    3,          // 计算矩阵时的领域范围
                                    false,      // 不适用 harris 角点检测
                                    0.04);      // 权重系数
            // 绘制检测到的角点
            cv::Mat tempMat2 = srcMat.clone();
            for(int index = 0; index < corners.size(); index++)
            {cv::circle(tempMat2, corners.at(index), 2, cv::Scalar(0, 0, 255), 2);
            }
            // copy
            mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
                            cv::Range(srcMat.cols * 0, srcMat.cols * 1));
            cv::addWeighted(mat, 0.0f, tempMat2, 1.0f, 0.0f, mat);

            // Shi-Tomasi 角点检测
            cv::goodFeaturesToTrack(tempMat,    // 输入图像
                                    corners,    // 输出角点
                                    100,        // 最大输出角点数量
                                    qualityLevel / 100.0f,  // 最小特征值
                                    minDistance,    // 最小间隔距离
                                    cv::noArray(),  // 感兴趣的区域
                                    3,          // 计算矩阵时的领域范围
                                    false,      // 不适用 harris 角点检测
                                    0.04);      // 权重系数
            // 绘制检测到的角点
            tempMat = srcMat.clone();
            for(int index = 0; index < corners.size(); index++)
            {cv::circle(tempMat, corners.at(index), 2, cv::Scalar(0, 0, 255), 2);
            }
            // copy
            mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
                            cv::Range(srcMat.cols * 1, srcMat.cols * 2));
            cv::addWeighted(mat, 0.0f, tempMat, 1.0f, 0.0f, mat);
        }
        // 更新
        cvui::update();
        // 显示
        cv::imshow(windowName, windowMat);
        // esc 键退出
        if(cv::waitKey(25) == 27)
        {break;}
    }
}

工程模板:对应版本号 v1.55.0

  对应版本号 v1.55.0

上一篇:《OpenCV 开发笔记(六十):红胖子 8 分钟带你深入了解 Harris 角点检测(图文并茂 + 浅显易懂 + 程序源码)》
下一篇:持续补充中…

原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/106436768

正文完
 0