c++ opencv求mat的最小值_OpenCV开发笔记(六十):红胖子8分钟带你深入了解Harris角点检测...

9b1ea4bad8e5befe72cc4ea5856e1050.png

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

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

上一篇:《OpenCV开发笔记(五十九):红胖子8分钟带你深入了解分水岭算法(图文并茂+浅显易懂+程序源码)》
下一篇:持续补充中…

前言

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

Demo

74d17dde7f382562a6f71cbc6a38a3e9.png

3e203071620192a4dc94970255c01ffe.png

3a404d1006d200f1f2891fc3ba5ef12a.png

d340faf530e0b805985b5fe2206af731.png

37414a89af1d4c0d508b6687db1123ed.png

dd5846bb63ab167f3ebc2cde901d9bf3.png

图像特征三大类型

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

Harris角点

概述

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

原理

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

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

03b0e07214acef319029bfeaa16008bc.png


具体的计算公式如下:

e53375dbc4c80fabc7c47b676b07cc3f.png

3c011dfefd3a10e6852bbfdb61961c93.png


泰勒展开:

2533a5039e000f1218c78f65f04a9cb7.png


代入得到:

737ece548aca5fcea569b915352c480a.png


其中:

b6a72e17d08a2b6147ceaa85673ca1fe.png


二次项函数本质上就是一个椭圆函数,椭圆的扁平率和尺寸是由矩阵M的两个特征值决定的。

bc47d3f4770acb24c2a1e34fdb3f99cf.png

81390a8e6601e7824a5b4e86073db8b9.png


矩阵M的两个特征值与图像中的角点,边缘,平坦区域的关系。
Harris定义角点响应函数即:

8a98b571bfd2f89ffdae452459f7002d.png


即R=Det(M)-k*trace(M)*trace(M),k为经验常数0.04~0.06 。
定义当R>threshold时且为局部极大值的点时,定义为角点。

Harris函数原型

void cornerHarris(InputArray src,
                  OutputArray dst,
                  int blockSize,
                  int ksize,
                  double k,
                  intborderType=BORDER_DEFAULT );
  • 参数一:InputArray类型的src,输入图像,即源图像,填Mat类的对象 即可,且须为单通道8位或者浮点型图像;
  • 参数二:OutputArray类型的dst,函数调用后的运算结果存在这里,即这个参数用于存放Harris角点检测的输出结果,和源图片有一样的尺寸,特别注意输出类型是CV_32F;
  • 参数三:int类型的blockSize,表示邻域的大小;
  • 参数四:int类型的ksize,表示Sobel()算子的孔径大小;
  • 参数五:double类型的k,Harris角点响应函数,一般为0.04~0.06;
  • 参数六:int类型的borderType,图像像素的边界模式:

1582fda11bcba54132f0313e9477925f.png

归一化概述

归一化是指对矩阵cv::Mat进行归一化操作。
归一化是一种无量纲处理手段,使物理系统数值的绝对值变成某种相对值关系。简化计算,缩小量值的有效办法。例如,滤波器中各个频率值以截止频率作归一化后,频率都是截止频率的相对值,没有了量纲。阻抗以电源内阻作归一化后,各个阻抗都成了一种相对阻抗值,“欧姆”这个量纲也没有了。等各种运算都结束后,反归一化一切都复原了。信号处理工具箱中经常使用的是nyquist频率,它被定义为采样频率的二分之一,在滤波器的阶数选择和设计中的截止频率均使用nyquist频率进行归一化处理。例如对于一个采样频率为500hz的系统,400hz的归一化频率就为400/500=0.8,归一化频率范围在[0,1]之间。
归一化函数原型

void normalize( InputArray src,
                InputOutputArray dst,
                double alpha = 1,
                double beta = 0,
                int norm_type = NORM_L2,
                int dtype = -1,
                InputArray mask = noArray());

参数一:InputArray类型的src,一般为mat;

  • 参数二:InputOutputArray类型的dst,一般为mat,大小与src一样;
  • 参数三:double类型的alpha,归一化的最小值,默认值1;
  • 参数四:double类型的beta,归一化的最大值,默认值0;
  • 参数五:int类型的norm_type,归一化类型,具体查看cv::NormTypes,默认为;
  • 参数六:int类型的dtype,默认值-1,负数时,其输出矩阵与src类型相同,否则它和src有同样的通道数,且此时图像深度为CV_MAT_DEPTH。
  • 参数七:InputArray类型的mask,可选的操作掩膜,默认值为noArray();

增强图像函数原型

void convertScaleAbs(InputArray src,
                     OutputArray dst,
                     double alpha = 1,
                     double beta = 0);

参数一:InputArray类型的src,一般为mat;

  • 参数二:OutputArray类型的dst,一般为mat,大小与src一样;
  • 参数三:double类型的alpha,归一化的最大值,默认值1;
  • 参数四:double类型的beta,归一化的最大值,默认值0;

Demo源码

void OpenCVManager::testHarris()
{
    QString fileName1 =
            "E:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/16.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;
    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 + 100, "threshold2");
            cvui::trackbar(windowMat, width * 1 + 20, height * 0 + 120, 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);

            // harris角点检测
            cv::cornerHarris(grayMat, grayMat2, 2, 3, 0.01);
            // 归一化与转换
            cv::normalize(grayMat2, grayMat2, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());
            cv::convertScaleAbs(grayMat2 , grayMat2); //将归一化后的图线性变换成 8U位元符号整
            // copy
            mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
                            cv::Range(srcMat.cols * 0, srcMat.cols * 1));
            cv::cvtColor(grayMat2, grayMat2, cv::COLOR_GRAY2BGR);

            cv::addWeighted(mat, 0.0f, grayMat2, 1.0f, 0.0f, mat);

            // harris角点检测
            cv::cornerHarris(tempMat, tempMat, 2, 3, 0.01);
            // 归一化与转换
            cv::normalize(tempMat, tempMat, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());
            cv::convertScaleAbs(tempMat , tempMat); //将归一化后的图线性变换成 8U位元符号整
            // copy
            mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
                            cv::Range(srcMat.cols * 1, srcMat.cols * 2));
            cv::cvtColor(tempMat, tempMat, cv::COLOR_GRAY2BGR);
            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.54.0

对应版本号v1.54.0

上一篇:《OpenCV开发笔记(五十九):红胖子8分钟带你深入了解分水岭算法(图文并茂+浅显易懂+程序源码)》
下一篇:持续补充中…

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值