EmguCV学习笔记 C# 6.S 特别示例

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

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博客

6.S 特别示例

6.S.1图像中的圆半径

本示例来自一名网友咨询如何获得图像中圆形的半径,其中有两个十字作为标记,十字之间距离为100mm。如下图:

 

图6-28 根据给出的定位标记求圆半径

【代码位置:frmChapter6_S1】Button1_Click、PointFToPoint

        private void Button1_Click(object sender, EventArgs e)

        {

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

            Mat mgray = new Mat();

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

            Mat kernel = new Mat();

            kernel = CvInvoke.GetStructuringElement(ElementShape.Cross, new Size(3, 3), new Point(-1, -1));

            Mat merode = new Mat();

            //这里使用了2次迭代

            CvInvoke.Dilate(mgray, merode, kernel, new Point(-1, -1), 1, BorderType.Constant, new MCvScalar());

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

            ImageBox1.Image = merode;

            //获得所有轮廓

            VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();

            VectorOfRect hierarchy = new VectorOfRect();

            CvInvoke.FindContours(merode, contours, hierarchy, RetrType.List, ChainApproxMethod.ChainApproxSimple);

            Mat m2 = new Mat(merode.Size, DepthType.Cv8U, 1);

            m2.SetTo(new MCvScalar(0));

            //圆轮廓

            VectorOfPoint contourCircle =new VectorOfPoint();

            //圆轮廓的周长

            Double perimeter =0;

            //绘制轮廓

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

            {

                VectorOfPoint carea = contours[i];

                //获得轮廓面积

                Double area = CvInvoke.ContourArea(carea, false);

                //符合条件时,绘制轮廓,排除圆形,只保留十字线

                //本图中圆形面积为2449,直线面积为8,需要根据实际情况调整

                if (area < 200)

                {

                    CvInvoke.DrawContours(m2, contours, i, new MCvScalar(255),1);

                }

                else

                {

                    //得到圆形,图像中只有三个轮廓:2个交叉十字线段、1个圆形

                    //这里简化操作,否则在多个轮廓情况下,应获取最大面积的轮廓判断为圆形

                    contourCircle = contours[i];

                    //获取轮廓周长

                    perimeter = CvInvoke.ArcLength(contourCircle, true);

                }

            }

            ImageBox1.Image = m2;

            //使用HoughLinesP方法检测图像中的直线,并将其绘制到图像

            //因为本图中十字线上的线段较短,所以这里阈值设置很小

            LineSegment2D[] lines = CvInvoke.HoughLinesP(m2, 1, Math.PI / 180, 5, 5, 80);

            Mat m3 = new Mat(merode.Size, DepthType.Cv8U, 3);

            m3.SetTo(new MCvScalar(0, 0, 0));

            foreach (LineSegment2D line in lines)

                CvInvoke.Line(m3, line.P1, line.P2, new MCvScalar(0, 255, 0), 2);

            ImageBox2.Image = m3;

            //对直线进行分类,将其分为垂直和水平两类:

            List<LineSegment2D> verticalLines = new List<LineSegment2D>();

            List<LineSegment2D> horizontalLines = new List<LineSegment2D>();

            //计算每条直线的倾斜角度来进行分类,

            //将倾斜角度在60 - 120度之间的直线划分为垂直类,

            //将倾斜角度在30 - 150度之间的直线划分为水平类。

            foreach (LineSegment2D line in lines)

            {

                Double angle = Math.Atan2(line.P2.Y - line.P1.Y, line.P2.X - line.P1.X) * 180 / Math.PI;

                if (angle < 0)

                    angle += 180;

                if (angle > 60 && angle < 120)

                    verticalLines.Add(line);

                else if ( angle > 150 || angle< 30 )

                    horizontalLines.Add(line);

            }

            //对垂直和水平直线进行匹配,并计算十字中心点的位置:

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

            //得到两个相交点

            foreach (LineSegment2D verticalLine in verticalLines)

            {

                foreach (LineSegment2D horizontalLine in horizontalLines)

                {

                    //基于图像中两条直线真实相交,

                    //如果垂直线的中点X坐标在水平线两端点X坐标之间

                    //那么,这条垂直线段和这条水平线段相交

                    Single centerX = (verticalLine.P1.X + verticalLine.P2.X) / 2;

                    if (horizontalLine.P1.X < horizontalLine.P2.X)

                    {

                        if ((centerX > horizontalLine.P1.X) && (centerX < horizontalLine.P2.X))

                        {

                            PointF intersectionPoint = 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);

                        }

                    }

                    else

                    {

                        if (centerX > horizontalLine.P2.X && centerX < horizontalLine.P1.X)

                        {

                            PointF intersectionPoint = 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);

                        }

                    }

                }

            }

            if (intersections.Count != 2)

            {

                MessageBox.Show("未能获得两个十字线的交叉点");

                return;

            }

            CvInvoke.Line(msrc, PointFToPoint(intersections[0]), PointFToPoint(intersections[1]), new MCvScalar(0, 255, 0), 2);

            CvInvoke.Imshow("m3", msrc);

            //计算两个交点的距离

            Double distance = Math.Sqrt(

                    Math.Pow((intersections[0].X - intersections[1].X),2) +Math.Pow((intersections[0].Y - intersections[1].Y) ,2)

                    );

            //实际中两交点距离为100毫米,计算相应比例

            Double proportion = 100 / distance;

            //以下是基于最小外接圆来计算实际圆半径

            CircleF cf = CvInvoke.MinEnclosingCircle(contourCircle);

            //获得外接圆形

            CvInvoke.Circle(msrc, new Point((int)cf.Center.X, (int)cf.Center.Y), (int)cf.Radius, new MCvScalar(0, 0, 255), 2);

            CvInvoke.Imshow("m4", msrc);

            //实际圆半径

            Double realradius1 = proportion * cf.Radius;

            //以下是基于轮廓周长来计算实际圆半径

            //实际圆周长

            Double realperimeter = perimeter * proportion;

            //图像中的圆半径

            Double radius = (perimeter / Math.PI) / 2;

            //实际圆半径

            Double realradius2 = proportion * radius;

            MessageBox.Show("最小外接圆来计算实际圆半径:" + realradius1 + "\r\n" +

                                "基于轮廓周长来计算实际圆半径:" + realradius2);

        }

输出结果如下图所示:

 

图6-29 求出的圆半径

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值