EmguCV学习笔记 C# 7.1 角点检测

news2024/11/15 11:32:56

版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。

EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。

教程VB.net版本请访问:EmguCV学习笔记 VB.Net 目录-CSDN博客

教程C#版本请访问:EmguCV学习笔记 C# 目录-CSDN博客

笔者的博客网址:https://blog.csdn.net/uruseibest

教程配套文件及相关说明以及如何获得pdf教程和代码,请移步:EmguCV学习笔记

学习VB.Net知识,请移步: vb.net 教程 目录_vb中如何用datagridview-CSDN博客

 学习C#知识,请移步:C# 教程 目录_c#教程目录-CSDN博客

7.1 角点检测

角点是特征点的一种,是指在图像中具有尖锐变化的像素点,例如像素值最大或最小的点、线段的顶点、两直线的交点等,它通常具有一些特征,如灰度值变化较大、梯度变化较大、边缘交汇处等。在计算机视觉领域中,角点通常被用作特征点的一种,用于目标检测、图像配准、三维重建等任务中。

7.1.1 ConvertScaleAbs

CvInvoke.ConvertScaleAbs用于对图像进行线性变换并将结果转换为无符号的8位整型图像。它可以将图像中的像素值进行缩放和偏移,常用于图像增强、特征提取等任务中。该方法的声明如下:

public static void ConvertScaleAbs(

           IInputArray src,

                    IOutputArray dst,

                    double scale,

           double shift

)

参数说明:

  1. src:要进行线性变换的源图像。
  2. dst:变换后的目标图像。
  3. scale:变换中的缩放比例。
  4. shift:变换中的偏移量。

注意:ConvertScaleAbs方法只能将结果转换为无符号的8位整型图像,如果需要转换为其他类型的图像(比如CV32F、Cv16U等),可以使用CvInvoke.ConvertScale方法。

【代码位置:frmChapter7】Button1_Click

        //ConvertScaleAbs

        private void Button1_Click(object sender, EventArgs e)

        {

            Mat msrc = new Mat("c:\\learnEmgucv\\lena.jpg", ImreadModes.Color);

            ImageBox1.Image = msrc;

            Mat mdst = new Mat();

            CvInvoke.ConvertScaleAbs(msrc, mdst, 1.5, 10);

            ImageBox2.Image = mdst;

        }

输出结果如下图所示:

 

图7-1 图像线性变换结果

可以看出,ConvertScaleAbs实际有两个作用:1、对图像像素点进行线性变换;2、对于非CV8U的图像,转为CV8U。

7.1.2 Normalize

CvInvoke.Normalize用于对图像进行归一化处理。它可以将图像中的像素值按照一定的规则进行缩放,使得像素值的范围在指定的范围内,常用于图像增强、特征提取等任务中。该方法的声明如下:

public static void Normalize(

           IInputArray src,

                    IOutputArray dst,

                    double alpha = 1,

                    double beta = 0,

                    NormType normType = NormType.L2,

                    DepthType dType = DepthType.Default,

           IInputArray mask = null

)

参数说明:

  1. src:要进行归一化处理的源图像。
  2. dst:归一化处理后的图像。
  3. alpha:下限范围。
  4. beta:上限范围,只在normType =NormType.MinMax时起作用。。
  5. normType:归一化处理中的算法类型,这是一个NormType枚举类型,可以选择NormType.MinMax、NormType.L1、NormType.L2等。当设置为MinMax时,Normalize()会把原矩阵中的值范围从最小值-最大值,按比例变换到alpha-beta的范围。
  6. dType:归一化处理后的目标图像的深度类型。
  7. mask:可选参数,表示要进行归一化处理的像素点的掩码图像,只有掩码图像中像素值为非零的像素点才会进行归一化处理。

【代码位置:frmChapter7】Button2_Click

        //Normalize

        private void Button2_Click(object sender, EventArgs e)

        {

            Mat msrc = new Mat("c:\\learnEmgucv\\lena.jpg", ImreadModes.Color);

            ImageBox1.Image = msrc;

            Mat mdst = new Mat();

            CvInvoke.Normalize(msrc, mdst, 50, 200, NormType.MinMax);

            ImageBox2.Image = mdst;

        }

输出结果如下图所示:

 

图7-2 图像归一化处理

7.1.3 CornerHarris

Harris角点检测算法是一种经典的角点检测算法,由Chris Harris和Mike Stephens在1988年提出。该算法通过计算图像中每个像素的响应函数值,来确定图像中的角点位置。

在使用EmguCV进行图像处理时,CvInvoke.CornerHarris方法用于检测图像中的角点。该方法基于Harris角点检测算法,可以识别出图像中的角点位置,其声明如下:

public static void CornerHarris(

           IInputArray image,

                    IOutputArray harrisResponse,

                    int blockSize,

                    int apertureSize = 3,

                    double k = 0.04,

           BorderType borderType = BorderType.Reflect101

)

参数说明:

  1. image:待检测的图像。必须是CV8U或者CV32F的单通道图像。
  2. harrisResponse:输出的角点响应图像,存放Harris评价系数的矩阵,这是一个CV32F的单通道图像,和image图像大小一致。
  3. blockSize:以当前像素为中心的邻域大小。通常是一个大于1的奇数。
  4. apertureSize:Sobel算子的大小。通常是一个大于1的奇数。
  5. k:Harris评价系数的权重系数,通常取值范围为0.04- 0.06。
  6. borderType:边界模式,用于处理图像边界情况。

【代码位置:frmChapter7】Button3_Click

        //CornerHarris

        private void Button3_Click(object sender, EventArgs e)

        {

            Mat m = new Mat("c:\\learnEmgucv\\chess.jpg", ImreadModes.Color);

            //获得灰度图像

            Mat mgray = new Mat();

            CvInvoke.CvtColor(m, mgray, ColorConversion.Bgr2Gray);

            ImageBox1.Image = mgray;

            //大小同mgray,存放评价系数的CV32F矩阵

            Mat mhr = new Mat();

            //检测角点

            CvInvoke.CornerHarris(mgray, mhr, 2, 3, 0.04);

            //归一化处理,之后处理的是存放评价系数的CV32F矩阵

            Mat mn = new Mat();

            CvInvoke.Normalize(mhr, mn, 0, 255, NormType.MinMax);

            //图像转为CV8U

            Mat mabs = new Mat();

            CvInvoke.ConvertScaleAbs(mn, mabs, 1, 0);

            //二值化

            Mat madp = new Mat();

            CvInvoke.Threshold(mabs, madp, 100, 255, ThresholdType.Binary);

            //由于之前二值化了,这里只需要获得非0值的点

            VectorOfPoint ps = new VectorOfPoint();

            CvInvoke.FindNonZero(madp, ps);

            //绘制出角点

            Mat mdst = new Mat();

            mdst = m.Clone();

            for (int i = 0; i < ps.Size; i++)

                CvInvoke.Circle(mdst, ps[i], 20, new MCvScalar(0, 0, 255), -1);

            ImageBox2.Image = mdst;

        }

输出结果如下图所示:

 

图7-3 棋盘上的角点

7.1.4 CornerSubPix

在数字图像处理领域中,亚像素级别(Subpixel Level)指的是比像素级别更细小的精度。像素级别指的是图像上的最小单位,通常是一个正方形的颜色区域。而亚像素级别则指的是像素内部的更细小的精度,例如像素内部的小数点位数。使用亚像素级别的精度可以提高图像处理的精度和准确度。例如,在角点检测任务中,使用亚像素级别的定位可以提高角点定位的精度,从而提高图像特征匹配的准确度。使用亚像素级别的精度需要借助于一些图像处理算法,例如插值算法、滤波算法等。

在使用EmguCV进行图像处理时,CvInvoke.CornerSubPix方法用于在亚像素级别上对角点进行精确化处理。该方法通过迭代优化提高角点的精度和准确性。该方法声明如下:

public static void CornerSubPix(

           IInputArray image,

                    IInputOutputArray corners,

                    Size win,

                    Size zeroZone,

           MCvTermCriteria criteria

)

参数说明:

  1. image:待处理的图像。
  2. corners:角点的位置数组,通常是通过CornerHarris等方法检测到的初始角点。这个参数既是输入也是输出。
  3. win:表示搜索窗口的大小。通常是一个大于1的奇数,表示在某个角点周围的邻域内进行亚像素级别的优化。
  4. zeroZone:表示搜索窗口中心的边界区域,通常是一个Size对象,用于将搜索窗口的中心排除在优化过程之外。
  5. criteria:表示优化过程的迭代终止准则,它是一个McvTermCriteria类,可以设置最大迭代次数和最小变化量的阈值。其中:
    1. maxIter:最大迭代次数,当迭代次数达到该值时,迭代终止。
    2. epsilon:迭代精度,当每一步迭代的变化量小于该值时,迭代终止。

下面的代码表示最大迭代次数为30次,每一步迭代的变化量小于0.01时,迭代终止:

Dim criteria As New MCvTermCriteria(30, 0.01)

【代码位置:frmChapter7】Button4_Click、getMax、outputMatdata32F1C、PointFToPoint

        //CornerSubPix

        private void Button4_Click(object sender, EventArgs e)

        {

            Mat m = new Mat("c:\\learnEmgucv\\chess.jpg", ImreadModes.Color);

            //获得灰度图像

            Mat mgray = new Mat();

            CvInvoke.CvtColor(m, mgray, ColorConversion.Bgr2Gray);

            ImageBox1.Image = mgray;

            //大小同mgray,存放评价系数的CV32F矩阵

            Mat mhr = new Mat();

            //检测角点

            CvInvoke.CornerHarris(mgray, mhr, 2, 3, 0.04);

            VectorOfPointF vopf = new VectorOfPointF();

            vopf = outputMatdata32F1C(mhr);

            CvInvoke.CornerSubPix(mgray, vopf, new Size(5, 5), new Size(-1, -1), new MCvTermCriteria(100, 0.01));

            //绘制出角点

            Mat mdst = new Mat();

            mdst = m.Clone();

            for (int i = 0; i < vopf.Size; i++)

                CvInvoke.Circle(mdst, PointFToPoint(vopf[i]), 20, new MCvScalar(0, 0, 255), -1);

            ImageBox2.Image = mdst;

        }

        //获得矩阵中的最大值,用来后面计算阈值

        private Double getMax(Mat m )

        {

            Double[] maxvalues;

            Double[] minvalues;

            Point[] maxposes;

            Point[] minposes;

            //只能查找每个通道的最大值和最小值,而不是查找每个通道的所有最大值和最小值

            //最大值和最小值的位置,也只是返回最先的那个。

            m.MinMax(out minvalues,out maxvalues, out minposes, out maxposes);

            //返回矩阵中的最大值

            return maxvalues[0];

        }

        //输出符合条件的点

        private VectorOfPointF outputMatdata32F1C(Mat m)

        {

            //设置阈值

            Double threshold = 0.01 * getMax(m);

            //为了计算方便,将m转为Matrix

            //这里m32F,所以使用Single

            Matrix<Single> matr = new Matrix<Single>(m.Size);

            //MatCopyTo方法

            m.CopyTo(matr);

            VectorOfPointF corners = new VectorOfPointF();

            int colcount = matr.Cols;

            int rowcount = matr.Rows;

            List<PointF> lstPf = new List<PointF>();

            for (int i = 0; i < rowcount; i++)

            {

                for (int j = 0; j < colcount; j++)

                {

                    Single outSingle = matr[i, j];

                    //存储大于阈值的点坐标

                    if (outSingle > threshold)

                        lstPf.Add(new PointF(j, i));

                }

            }

            //获得VectorOfPointF

            corners.Push(lstPf.ToArray());

            return corners;

        }

输出结果如下图所示:

 

图7-4 棋盘上的角点

【代码位置:frmChapter7】Button5_Click

        //直接CornerHarrisCornerSubPix的比较

        private void Button5_Click(object sender, EventArgs e)

        {

            Mat m = new Mat("c:\\learnEmgucv\\lena.jpg", ImreadModes.Color);

            //获得灰度图像

            Mat mgray = new Mat();

            CvInvoke.CvtColor(m, mgray, ColorConversion.Bgr2Gray);

            //大小同mgray,存放评价系数的CV32F矩阵

            Mat mhr = new Mat();

            //检测角点

            CvInvoke.CornerHarris(mgray, mhr, 2, 3, 0.04);

            //设定阈值

            Double threshold = 0.01 * getMax(mhr);

            //二值化,分离不符合阈值的点

            Mat mtsd = new Mat();

            CvInvoke.Threshold(mhr, mtsd, threshold, 255, ThresholdType.Binary);

            //获得非0值的点

            VectorOfPoint ps = new VectorOfPoint();

            CvInvoke.FindNonZero(mtsd, ps);

            //绘制出角点

            Mat mdst = new Mat();

            mdst = m.Clone();

            for (int i = 0; i < ps.Size; i++)

                CvInvoke.Circle(mdst, ps[i], 2, new MCvScalar(0, 0, 255), -1);

            ImageBox1.Image = mdst;

            VectorOfPointF vopf = new VectorOfPointF();

            vopf = outputMatdata32F1C(mhr);

            CvInvoke.CornerSubPix(mgray, vopf, new Size(5, 5), new Size(-1, -1), new MCvTermCriteria(100, 0.01));

            //绘制出角点

            Mat mdst2 = new Mat();

            mdst2 = m.Clone();

            for (int i = 0; i < vopf.Size; i++)

                CvInvoke.Circle(mdst2, PointFToPoint(vopf[i]), 2, new MCvScalar(0, 0, 255), -1);

            ImageBox2.Image = mdst2;

        }

输出结果如下图所示:

 

图7-5 直接CornerHarris和CornerSubPix后的比较

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2083775.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Excel中让第一行始终显示

要在Excel中让第一行始终显示&#xff0c;你可以使用冻结窗格功能。具体步骤如下&#xff1a; 打开需要设置第一行一直显示的工作表。将光标定位在工作表内任意一个单元格内。选择“视图”菜单&#xff0c;单击工具栏中的“冻结窗格”命令。在弹出的下拉菜单中选择“冻结首行”…

字母的大小写转换(tolower、toupper、transform)

字母的大小写转换&#xff08;tolower、toupper、transform&#xff09; 1. tolower&#xff08;&#xff09;、toupper&#xff08;&#xff09;函数 &#xff08;这个在之前的一篇文章 “字符串中需要掌握的函数总结&#xff08;1&#xff09;”中有较为详细的介绍。&#…

时利和:如何提升工装夹具的加工质量?

在机械加工领域&#xff0c;工装夹具起着至关重要的作用。它不仅能够提高生产效率&#xff0c;还能保证加工精度&#xff0c;确保产品质量的稳定性。那么&#xff0c;如何提升工装夹具的加工质量呢?以下是时利和整理分享的几个关键因素。 一、精准的设计 工装夹具的设计是决定…

使用物联网卡访问萤石云的常见问题

使用物联网卡接入萤石开放平台时经常遇到各种问题&#xff0c;这边总结了常见的一些 用的是哪家运营商的卡&#xff1f; 电信 移动 联通&#xff08;申请的时候可以自主选择&#xff09; 卡有什么限制&#xff1f; 定向流量卡&#xff0c;只能访问萤石云平台&#xff0c;只能…

完美解决Jenkins重启后自动杀掉衍生进程(子进程)问题

完美解决Jenkins重启后自动杀掉衍生进程(子进程)问题 本文中使用的Jenkins版本为Version 2.452.3 先罗列一下前置问题&#xff1a;Jenkins任务构建完成自动杀掉衍生进程 用过Jenkins的都知道&#xff0c;Jenkins任务构建完成后&#xff0c;是会自动杀掉衍生进程&#xff0c;这…

安卓AppBarLayout与ViewPager2里的fragment里的webview滑动冲突

今天开发遇见一个头痛的问题&#xff0c;就是AppBarLayout和webview会存在一个冲突问题。如图下 问题出现在webview推到顶端的时候&#xff0c;AppBarLayout并不会跟着响应伸缩&#xff0c;解决办法是 在 webview 包 一个 父的 NestedScrollView 就能解决了。 运行效果入下 更改…

单向链表和双向链表的一些基本算法

单向链表头插尾插 单向链表的销毁与反转 反转原理&#xff1a;将头节点与后面的节点分开&#xff0c;然后从第一个节点开始对每个节点使用头插法 冒泡排 选排 链表环&#xff1a; 判断是否有环&#xff1a;弗洛伊德快慢指针&#xff08;快指针一般是慢指针的2倍&#xff0c;差为…

Selenium(HTML基础)

一、HTML基础 &#xff08;在学习自动化时&#xff0c;保证能看懂&#xff09; 1.1.HTML介绍 英文是HyperText Markup Language&#xff0c;译为:超文本标记语言是Internet上用于设计网页的主要语言&#xff0c;2008年发布了HTML5.0,是目前互联网的标准&#xff0c;并作为互联…

数据结构之 “单链表“

&#xff08;1&#xff09;在顺表表中&#xff0c;如果是头插/删的时间复杂度是O(1)&#xff1b;尾插/删的时间复杂度是O(N) &#xff08;2&#xff09;增容一般是呈2倍的增长&#xff0c;势必会有一定的空间浪费。比如&#xff1a;申请了50个空间&#xff0c;只用了两个&#…

【Matlab】SSA-BP麻雀搜索算法优化BP神经网络回归预测 可预测未来(附代码)

资源下载&#xff1a; 资源合集&#xff1a; 目录 一&#xff0c;概述 传统的BP神经网络存在一些问题&#xff0c;比如容易陷入局部最优解、训练速度慢等。为了解决这些问题&#xff0c;我们引入了麻雀算法作为优化方法&#xff0c;将其与BP神经网络相结合&#xff0c;提出了…

精准高效,省时省力——2024年翻译工具新趋势

如果你收到一份外文文档&#xff0c;但是你看不懂急需翻译成中文&#xff0c;将文档内容复制粘贴到翻译的的窗口获得中文内容是不是很麻烦。我了解到了deepl翻译文档之后还认识了不少的翻译神器&#xff0c;这次分享给你一起试试吧。 第一款福晰在线翻译 链接直达>>htt…

3D工艺大师:精准助力医疗设备远程维修

医疗设备是现代医疗体系中不可或缺的重要工具&#xff0c;它们帮助医生更准确地诊断病情&#xff0c;更有效地进行治疗。但随着技术的进步&#xff0c;这些设备变得越来越复杂&#xff0c;维修起来也面临诸多挑战。 首先&#xff0c;医疗设备结构复杂&#xff0c;零件众多&…

【Material-UI】Rating组件中的Rating precision属性

文章目录 一、Rating组件概述1. 组件简介2. precision属性的作用 二、Rating precision的基本用法三、Rating precision属性详解1. 精度选择的意义2. 如何在项目中选择合适的精度 四、Rating precision属性的实际应用场景1. 电商平台中的应用2. 电影评分应用3. 专业评测网站 五…

[Tomcat源码解析]——热部署和热加载原理

热部署 在Tomcat中可以通过Host标签设置热部署,当 autoDeploy为true时,在运行中的Tomcat中丢入一个war包,那么Tomcat不需要重启就可以自动加载该war包。 <Host name="localhost" appBase="webapps"unpackWARs="true" autoDeploy="…

Ubuntu18.04 下安装CUDA

安装步骤 1.查看是否安装了cuda # 法1 cat /usr/local/cuda/version.txt # 法2 nvcc --version 2.若没有安装&#xff0c;则查看是否有N卡驱动&#xff0c;若无N卡驱动&#xff0c;则到软件与更新 -> 附加驱动中安装驱动 3.查看N卡驱动支持的cuda版本 nvidia-smi 如下…

RabbitMQ 集群与高可用性

目录 单节点与集群部署 1.1. 单节点部署 1.2. 集群部署 镜像队列 1.定义与工作原理 2. 配置镜像队列 3.应用场景 4. 优缺点 5. Java 示例 分布式部署 1. 分布式部署的主要目标 2. 典型架构设计 3. RabbitMQ 分布式部署的关键技术 4. 部署策略和实践 5. 分布式部署…

图像变换——等距变换、相似变换、仿射变换、投影变换

%%图像变换 % I imread(cameraman.tif); I imread(F:\stitching\imagess\or\baiyun2.jpg); figure; imshow(I); title(原始图像); [w,h]size(I); thetapi/4;%旋转角 t[200,80];%平移tx,ty s0.3;%缩放尺度 %% 等距变换平移变换旋转变换 H_eprojective2d([cos(theta) sin(theta…

体育风尚杂志体育风尚杂志社体育风尚编辑部2024年第8期目录

体讯 体育产业“破圈” 3-7 成都大运会获2023年度最佳体育赛事媒体设施奖 8-10 斯巴达勇士赛 2024斯巴达勇士赛深圳站漫威主题赛在深圳光明欢乐田园揭幕 11-15 篮球 CBA季后赛 深圳马可波罗挺进季后赛八强 16-24 游泳 周六福2024年全国游泳冠军赛4月深圳激…

集成电路与电路基础之-二极管

二极管是什么 二极管&#xff0c;又称肖特基二极管或晶体二极管&#xff0c;是一种最基本的半导体器件之一。它由半导体材料&#xff08;如硅、硒、锗等&#xff09;制成&#xff0c;其内部结构是一个PN结&#xff0c;即由一个P型半导体区和一个N型半导体区组成。这种结构赋予…

【freeDiameter】服务端和客户端的连接流程

连接流程详解 进程启动时&#xff0c;先使用main_cmdline解析命令行参数&#xff0c;比如使用-c就会使用指定路径的配置文件&#xff0c;使用-d就会启用后台进程。 之后使用fd_core_initialize初始化核心库。具体会先使用fd_conf_init初始化配置&#xff0c;比如设置各项的默…