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

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

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.rhkb.cn/news/414615.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu22.04安装 docker和docker-compose环境

Docker简介 Docker 是一个开源的应用容器引擎&#xff0c;它使开发者能够打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互之间不会有任何接口&#xff08;…

蓝色炫酷碎粒子HTML5导航源码

源码介绍 蓝色炫酷碎粒子HTML5导航源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面&#xff0c;重定向这个界面 效果预览 源码获取 蓝色炫酷碎粒…

Halcon提取边缘线段lines_gauss 算子

Halcon提取边缘线段lines_gauss 算子 edges_color_sub_pix和edges_sub_pix两个算子使用边缘滤波器进行边缘检测。还有一个常用的算子lines_gauss算子&#xff0c;也可以用于提取边缘线段&#xff0c;它的鲁棒性非常好&#xff0c;提取出的线段类型是亚像素精度的XLD轮廓。其原…

LLM训练、精调与加速:大型语言模型的高效开发与应用策略

创作不易&#xff0c;您的关注、点赞、收藏和转发是我坚持下去的动力&#xff01; 大家有技术交流指导、论文及技术文档写作指导、项目开发合作的需求可以私信联系我 LLM&#xff08;大型语言模型&#xff09;的训练、精调和加速是当前人工智能研究和应用中的重要话题。下面将…

JVM垃圾判定算法

垃圾收集技术是Java的一堵高墙。Java堆内存中存放着几乎所有的对象实例&#xff0c;垃圾收集器在对堆内存进行回收前&#xff0c;第一件事情就是要确定这些对象中哪些还存活&#xff0c;哪些已经死去&#xff08;即不可能再被任何途径使用的对象&#xff09;。也就是判定垃圾。…

【学习笔记】卫星通信NTN 3GPP标准化进展分析(五)- 3GPP Release19 研究计划

一、引言&#xff1a; 本文来自3GPP Joern Krause, 3GPP MCC (May 14,2024) Non-Terrestrial Networks (NTN) (3gpp.org) 本文总结了NTN标准化进程以及后续的研究计划&#xff0c;是学习NTN协议的入门。 【学习笔记】卫星通信NTN 3GPP标准化进展分析&#xff08;一&#xff…

第二证券:大洗牌!头部券商营收、净利集体下滑

前十券商营收团体下滑&#xff0c;银河证券跌幅最小 新股IPO数量锐减129家至44家&#xff0c;国内证券市场股票基金交易量日均规划 同比下降 6.83%……关于证券公司而言&#xff0c;本年上半年可谓多重要素叠加冲击&#xff0c;成果下滑难以避免。于大多数证券公司而言&#x…

Vue(三)内置指令v-text、html、cloak、once、pre;自定义指令的三种方式、Vue生命周期

文章目录 1. 内置指令1.1 v-text、v-html指令1.2 v-cloak指令1.3 v-once指令1.4 v-pre指令 2. 自定义指令(directives)2.1 函数式2.2 对象式2.3 注意点 3. 生命周期3.1 挂载流程3.2 更新流程3.3 销毁流程 1. 内置指令 1.1 v-text、v-html指令 v-text与v-html都是向所在的节点…

EPLAN中部件库的导入和使用方法

EPLAN中部件库的导入和使用方法 如下图所示,点击工具-----部件------管理, 在弹出的窗口中点击附加------导入, 找到自己需要导入的文件,后缀名为EDZ,点击打开, 如下图所示,勾选"更新已有数据集并添加新建数据集",点击确定, 如下图所示,正在导

为什么一些行业刚起步就白热化竞争-例如机器人行业?

部分从事机器人行业的从业者交流就是特别卷。 明明是一个刚起飞的行业为何竞争如此残酷&#xff1f; 抛开降本增效的商业逻辑不谈。 只从一个侧面去观察-供需。 从事脑力劳动的机器人-处理文档 从事体力劳动的机器人-打螺丝 交流 机器人时代什么时候到来&#xff1f; 相似…

编译器基础介绍

随着深度学习的不断发展&#xff0c;AI 模型结构在快速演化&#xff0c;底层计算硬件技术更是层出不穷&#xff0c;对于广大开发者来说不仅要考虑如何在复杂多变的场景下有效的将算力发挥出来&#xff0c;还要应对 AI 框架的持续迭代。AI 编译器就成了应对以上问题广受关注的技…

论文翻译:Scaling Instruction-Finetuned Language Models

Scaling Instruction-Finetuned Language Models https://www.jmlr.org/papers/volume25/23-0870/23-0870.pdf 指令微调语言模型 文章目录 指令微调语言模型摘要1. 引言2. Flan微调2.1 微调数据2.2 微调过程2.3 评估协议 3. 扩展到5400亿参数和1836个任务4. 带有思维链注释的微…

HMI触屏网关-VISION如何与Modbus TCP从机通信

上文&#xff1a;HMI触屏网关-VISION如何与Modbus RTU从机通信-CSDN博客 1. 硬件连接 Modbus TCP协议采用网口通信的方式&#xff0c;因此&#xff0c;只需要保证网关的LAN口IP和Modbus TCP从机的IP在同一网段即可。 Modbus TCP从机参数说明&#xff1a; 2. VISION创建Modbu…

LaViT:这也行,微软提出直接用上一层的注意力权重生成当前层的注意力权重 | CVPR 2024

Less-Attention Vision Transformer利用了在多头自注意力&#xff08;MHSA&#xff09;块中计算的依赖关系&#xff0c;通过重复使用先前MSA块的注意力来绕过注意力计算&#xff0c;还额外增加了一个简单的保持对角性的损失函数&#xff0c;旨在促进注意力矩阵在表示标记之间关…

从0到1搭建用户管理系统

手把手教你搭建前后端框架 新手对于很多成熟框架&#xff0c;不知道如何搭建的&#xff0c;不知道如何实现等等&#xff0c;忙碌之余&#xff0c;写了一篇博客 手把手教你搭建前后端框架源码&#xff0c; springbootmysqlelementuivue 从0到1&#xff0c;搭建springboot框架&am…

出租车4G5G无线车载监控系统解决方案(下)

目录 一、项目概述 1.1 项目背景 1.2 设计原则 1.3 设计目标 1.4 实施意义 二、系统总体设计 2.1建设目标 2.2系统模式 2.3设计思路 2.4设计架构 2.5系统组成 2.6优势分析 2.7设备达到的功能要求 2.8系统组成 三、系统详细设计 3.1 出租车车载监控 3.1.1 系统功能设计 3.2系统前…

如何在退出Qt时保存用户配置

如何在退出Qt时保存用户配置 文章目录 如何在退出Qt时保存用户配置一、简介二、 保存配置数据&#xff08;方法一&#xff09;2.1 项目实现2.2 运行结果 三、保存配置数据&#xff08;方法二&#xff09;3.1 项目实现3.2 运行结果 四、写在最后 ​ 一、简介 在我们使用 Qt 进行…

吹爆上海交大的大模型实战教程!!非常详细收藏我这一篇就够了

各位好&#xff0c;这里是DASOU 今天分享一个上海交大的免费的大模型课程&#xff0c;有相关教程文档和Slides&#xff0c;目前是1.6K星标&#xff0c;还是挺火的 项目动机 《动手学大模型》系列编程实践教程&#xff0c;由上海交通大学2024年春季《人工智能安全技术》课程&…

MySQL集群

一、Mysql 在服务器中的部署方法 1.1源码安装 下载依赖性 dnf install cmake gcc-c openssl-devel ncurses-devel.x86_64 libtirpc-devel-1.3.3-8.el9_4.x86_64.rpm rpcgen.x86_64 解压压缩包并安装 tar zxf mysql-boost-5.7.44.tar.gz cd /root/mysql-5.7.44 cmake \ -DCM…

java写入word表格(poi-tl)

1.导入依赖 <!--poi-tl--> <dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.12.0</version> </dependency>2.代码 自己创建模板。放在&#xff08;resource/file&#xff09;…