编程获取图像中的圆半径

2023-09-15 13:03:02

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

即将推出EmguCV的教程,请大家还稍作等待。

之前网友咨询如何获得图像中圆形的半径,其中有两个十字作为标定,十字之间距离为100mm。如下图:

说实在的,单靠VB.net很难获得相关圆形信息,为了弥补这部分知识,下定决心学习了EmguCV。以下是具体代码:https://blog.csdn.net/UruseiBest

        Dim msrc As New Mat("C:\learnEmgucv\celiang.jpg", ImreadModes.Color)

        Dim mgray As New Mat()
        CvInvoke.CvtColor(msrc, mgray, ColorConversion.Bgr2Gray)

        Dim kernel As New Mat
        kernel = CvInvoke.GetStructuringElement(ElementShape.Cross, New Drawing.Size(3, 3), New Point(-1, -1))

        Dim merode As New Mat        '
        '这里使用了2次迭代
        CvInvoke.Dilate(mgray, merode, kernel, New Point(-1, -1), 1, BorderType.Constant, Nothing)

        CvInvoke.Threshold(merode, merode, 200, 255, ThresholdType.BinaryInv)


        '获得所有轮廓 https://blog.csdn.net/UruseiBest
        Dim contours As New VectorOfVectorOfPoint
        Dim hierarchy As New VectorOfRect

        CvInvoke.FindContours(merode, contours, hierarchy, RetrType.List, ChainApproxMethod.ChainApproxSimple)
        Dim m2 As New Mat(merode.Size, DepthType.Cv8U, 1)
        m2.SetTo(New MCvScalar(0))


        '圆轮廓
        Dim contourCircle As VectorOfPoint

        '圆轮廓的周长
        Dim perimeter As Double

        '绘制轮廓 https://blog.csdn.net/UruseiBest
        For i As Integer = 0 To contours.Size - 1
            Dim carea As VectorOfPoint = contours(i)
            '获得轮廓面积
            Dim area As Double = CvInvoke.ContourArea(carea, False)
            '符合条件时,绘制轮廓,排除圆形,只保留十字线 
            '本图中圆形面积为2449,直线面积为8,需要根据实际情况调整
            If area < 200 Then
                CvInvoke.DrawContours(m2, contours, i, New MCvScalar(255), 0.4)
            Else
                '得到圆形,图像中只有三个轮廓:2个交叉十字线段、1个圆形
                '这里简化操作,否则在多个轮廓情况下,应获取最大面积的轮廓判断为圆形
                contourCircle = contours(i)

                '获取轮廓周长
                perimeter = CvInvoke.ArcLength(contourCircle, True)
            End If
        Next
        ImageBox1.Image = m2

        '使用HoughLinesP方法检测图像中的直线,并将其绘制到图像
        '因为本图中十字线上的线段较短,所以这里阈值设置很小
        Dim lines As LineSegment2D() = CvInvoke.HoughLinesP(m2, 1, Math.PI / 180, 5, 5, 80)

        Dim m3 As New Mat(merode.Size, DepthType.Cv8U, 3)
        m3.SetTo(New MCvScalar(0, 0, 0))

        For Each line As LineSegment2D In lines
            CvInvoke.Line(m3, line.P1, line.P2, New MCvScalar(0, 255, 0), 2)
        Next

        ImageBox2.Image = m3

       '对直线进行分类,将其分为垂直和水平两类:
        Dim verticalLines As New List(Of LineSegment2D)
        Dim horizontalLines As New List(Of LineSegment2D)

        '计算每条直线的倾斜角度来进行分类,
        '将倾斜角度在60 - 120度之间的直线划分为垂直类,
        '将倾斜角度在30 - 150度之间的直线划分为水平类。
        For Each line As LineSegment2D In lines
            Dim angle As Double = Math.Atan2(line.P2.Y - line.P1.Y, line.P2.X - line.P1.X) * 180 / Math.PI
            If angle < 0 Then angle += 180

            If angle > 60 AndAlso angle < 120 Then
                verticalLines.Add(line)
            ElseIf angle > 150 OrElse angle < 30 Then
                horizontalLines.Add(line)
            End If
        Next

        '对垂直和水平直线进行匹配,并计算十字中心点的位置:
        Dim intersections As New List(Of PointF)

        '得到两个相交点 https://blog.csdn.net/UruseiBest
        For Each verticalLine As LineSegment2D In verticalLines
            For Each horizontalLine As LineSegment2D In horizontalLines
                '基于图像中两条直线真实相交,
                '如果垂直线的中点X坐标在水平线两端点X坐标之间
                '那么,这条垂直线段和这条水平线段相交
                Dim centerX As Single = (verticalLine.P1.X + verticalLine.P2.X) / 2
                If horizontalLine.P1.X < horizontalLine.P2.X Then
                    If centerX > horizontalLine.P1.X And centerX < horizontalLine.P2.X Then
                        Dim intersectionPoint As New PointF(
                            (horizontalLine.P1.X + horizontalLine.P2.X + verticalLine.P1.X + verticalLine.P2.X) / 4,
                            (horizontalLine.P1.Y + horizontalLine.P2.Y + verticalLine.P1.Y + verticalLine.P2.Y) / 4
                        )
                        intersections.Add(intersectionPoint)
                    End If
                Else
                    If centerX > horizontalLine.P2.X And centerX < horizontalLine.P1.X Then
                        Dim intersectionPoint As New PointF(
                            (horizontalLine.P1.X + horizontalLine.P2.X + verticalLine.P1.X + verticalLine.P2.X) / 4,
                            (horizontalLine.P1.Y + horizontalLine.P2.Y + verticalLine.P1.Y + verticalLine.P2.Y) / 4
                        )
                        intersections.Add(intersectionPoint)
                    End If
                End If
            Next
        Next

        If intersections.Count <> 2 Then
            MessageBox.Show("未能获得两个十字线的交叉点")
            Exit Sub
        End If
        CvInvoke.Line(msrc, PointFToPoint(intersections(0)), PointFToPoint(intersections(1)), New MCvScalar(0, 255, 0), 2)

        CvInvoke.Imshow("m3", msrc)

       '计算两个交点的距离
        Dim distance As Double = Math.Sqrt(
            (intersections(0).X - intersections(1).X) ^ 2 +
            (intersections(0).Y - intersections(1).Y) ^ 2
        )

        '实际中两交点距离为100毫米,计算相应比例
        Dim proportion As Double = 100 / distance


        '以下是基于最小外接圆来计算实际圆半径
        Dim cf As CircleF
        cf = CvInvoke.MinEnclosingCircle(contourCircle)
        '获得外接圆形 https://blog.csdn.net/UruseiBest
        CvInvoke.Circle(msrc, New Point(CInt(cf.Center.X), CInt(cf.Center.Y)), cf.Radius, New MCvScalar(0, 0, 255), 2)
        CvInvoke.Imshow("m4", msrc)

       '实际圆半径
        Dim realradius1 As Double
        realradius1 = proportion * cf.Radius


        '以下是基于轮廓周长来计算实际圆半径
        '实际圆周长
        Dim realperimeter As Double = perimeter * proportion

        '图像中的圆半径 https://blog.csdn.net/UruseiBest
        Dim radius As Double
        radius = (perimeter / Math.PI) / 2

        '实际圆半径
        Dim realradius2 As Double
        realradius2 = proportion * radius

        MessageBox.Show("最小外接圆来计算实际圆半径:" & realradius1 & ControlChars.CrLf &
                        "基于轮廓周长来计算实际圆半径:" & realradius2)

这个网友当时提出来问题的时候,我还没有办法解决,不过经过不断学习,目前已经学习了不少相关知识,至少可以获得圆半径了,还是略微感到欣慰。 

关于EmguCV的知识,下一步整理出来。

由于.net平台下C#和vb.NET很相似,本文也可以为C#爱好者提供参考。

学习更多vb.net知识,请参看vb.net 教程 目录

更多推荐

关于什么是框架

框架(Framework)是一个框子——指其约束性,也是一个架子——指其支撑性。IT语境中的框架,特指为解决一个开放性问题而设计的具有一定性的支撑结构。在此结构上约束可以根据具体问题扩展、安插更多的组成部分,从而更迅速和方便地构建完整的解决问题的方案。目前还没看到什么有趣的个人化解释,可能是因为要解决都复杂到设计出框架

u盘上面 安装 ubuntu 系统

u盘上面安装ubuntu系统下载一个Ubuntu22.04.3LTS桌面版https://ubuntu.com/download/desktop找到一个U盘参考文章:把Ubuntu装到U盘里随身携带,并同时支持BIOS和UEFI启动https://www.luogu.com.cn/blog/GGAutomaton/po

消息队列-rabbitMq

消息队列(MQ)到底能干什么?MQ全称为MessageQueue,也就是消息队列,是应用程序和应用程序之间的通信方法。在微服务盛行的当下,MQ被使用的也是越来越多,一般常用来进行业务异步解耦、解耦微服务、流量削峰填谷、消息分发、分布式事务的数据一致性。1、业务异步解耦最常见的场景就是用户注册之后,需要发送注册短信、邮件

Spring Boot业务系统如何实现海量数据高效实时搜索

1.概述我们都知道随着业务系统的发展和使用,数据库存储的业务数据量会越来越大,逐渐成为了业务系统的瓶颈。在阿里巴巴开发手册中也建议:单表行数超过500万行或者单表容量超过2GB才推荐进行分库分表,如果预计三年后数据量根本达不到这个级别,请不要在创建表时就分库分表。数据库最终都是存储在磁盘上,随着数据量变大,会导致数据操

TCP IP网络编程(六) 基于UDP的服务器端、客户端

文章目录一、理解UDP1.UDP套接字的特点2.UDP内部工作原理3.UDP的高效使用二、实现基于UDP的服务器端、客户端1.UDP中的服务端和客户端没有连接2.UDP服务器端和客户端均只需要一个套接字3.基于UDP的数据I/O函数4.基于UDP的回声服务器端、客户端5.UDP客户端套接字的地址分配三、UDP的数据传输

2023研究生数学建模D题思路代码 区域双碳目标与路径规划研究

D题思路代码区域双碳目标与路径规划研究完整解题思路可看视频:2023华为杯研赛D题区域双碳目标与路径规划研究(附代码+全保姆教程)_哔哩哔哩_bilibili​www.bilibili.com/video/BV1Cm4y157CH/?spm_id_from=333.999.0.0问题一:区域碳排放量以及经济、人口、能源

Spring Security 用了那么久,你对它有整体把控吗?

文章目录1.ServletFilter:守门人的角色2.DelegatingFilterProxy:桥接Servlet和Spring的神器3.FilterChainProxy:SpringSecurity过滤器链的管家3.SecurityFilterChain:Security过滤器的串绳4.SpringSecurit

【Vue】避免Vue组件中常见的props默认值陷阱

1.对象和数组默认值的共享问题当你将一个对象或数组作为props的默认值时,它们会在组件的所有实例之间共享。这意味着如果一个组件修改了这个默认值,其他组件也会受到影响,因为它们共享同一个引用。陷阱:props:{userInfo:{type:Object,default:{}}}问题:如果一个组件修改了userInfo

基于vue3 + ant-design 自定义SVG图标iconfont的解决方案;ant-design加载本地iconfont.js不显示图标问题

基于vue3+ant-design自定义SVG图标iconfont的解决方案;ant-design加载本地iconfont.js不显示图标问题一、准备工作1、首先去阿里巴巴矢量图标库自定义添加自己的图标;网站地址https://www.iconfont.cn/整个步骤是:选择图标–添加到项目-项目设置-下载到本地已经选

Web Storage是什么?Web Storage详解

WebStorag是HTML5引入的一个非常重要的功能,可以将数据存储在本地,如保存用户的偏好设置、复选框的选中状态、文本框默认填写的值等。用户在浏览器中刷新网页时,网页通过WebStorage就可以知道用户之前所做的一些修改,而不需要将用户修改的内容存储在服务器端。WebStorage类似于Cookie,但相比Coo

【docker安装Mysql并配置主从复制】

Mysql主从复制目的:是为了后面naocs集群的服务配置做准备工作准备工作准备至少两台虚拟机或服务器,安装好了docker,找到他们的ip地址后面操作都用xshell操作来代替拉取并启动mysql镜像和容器主机的命令为mysql01,对外端口用3310来连接dockerrun-d-p3310:3306-v/home/

热文推荐