cad怎样生成轮廓线(图样中可见轮廓线用什么线)

一般在做影像处理时,为提升效率,常会将影像转为二值影像后再进行处理。在EmguCV内有许多找轮廓线的方法,但是随着版本更新,不同版本的函数不见得会一样,每次都要重新查询实在很麻烦,那不如把他们记下来。版本概要:EmguCV版本:3.2.0.2682编译器版本:VisualStudio2017Community方案平台:x64(许多导致程式无法执行的原因是因为没有改执

大家好,又见面了,我是你们的朋友全栈君。

一般在做影像处理时,为提升效率,常会将影像转为二值影像后再进行处理。
在EmguCV内有许多找轮廓线的方法,但是随着版本更新,不同版本的函数
不见得会一样,每次都要重新查询实在很麻烦,那不如把他们记下来。

版本概要:
EmguCV版本:3.2.0.2682
编译器版本: Visual Studio 2017 Community
方案平台: x64 (许多导致程式无法执行的原因是因为没有改执行平台!)

正文开始。
首先我们用小画家画了一张图来作为范本—一朵云。
因为形状奇特,非常适合用来说明。
这里写图片描述

1. BoundingBox: 可以框住全部范围的矩形。

这是没有经过旋转地矩形,有经过旋转的矩形在后面讨论。

using System;
using System.Windows.Forms;
using System.Drawing;

using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.CV.CvEnum;
using Emgu.CV.Util;


namespace Test
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

            Image<Gray, byte> I = new Image<Gray, byte>(@"D:\Test.jpg");
            Image<Bgr, byte> DrawI = I.Convert<Bgr, byte>();

            Image<Gray, byte> CannyImage = I.Clone();
            CvInvoke.Canny(I, CannyImage, 255, 255, 5, true);

            MyCV.BoundingBox(CannyImage, DrawI);
            pictureBox1.Image = DrawI.Bitmap;
        }
    }

    public class MyCV
    {
        public static void BoundingBox(Image<Gray, byte> src, Image<Bgr, byte> draw)
        {
            using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
            {
                CvInvoke.FindContours(src, contours, null, RetrType.External,
                                      ChainApproxMethod.ChainApproxSimple);

                int count = contours.Size;
                for (int i = 0; i < count; i++)
                {
                    using (VectorOfPoint contour = contours[i])
                    {
                        Rectangle BoundingBox = CvInvoke.BoundingRectangle(contour);
                        CvInvoke.Rectangle(draw, BoundingBox, new MCvScalar(255, 0, 255, 255), 3);
                    }
                }
            }
        }
    }
}

这里写图片描述

注:后面的程式码仅写出操作的函数,省略主视窗及名称空间,请自行代换主视窗的程式码。

在这边常有看到一些范例程式会建议使用ApproxPolyDP这个方法,取得近似的形状,
经过测试,若是在一些精度需求不高的情况下可以这么做,但就这个云形的例子而言不建议这样做。
下面是采用ApproxPolyDP函数的程式码与结果。

public static void ApproxBoundingBox(Image<Gray, byte> src, Image<Bgr, byte> draw)
{
    using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
    {
        CvInvoke.FindContours(src, contours, null, RetrType.External,
                              ChainApproxMethod.ChainApproxSimple);

        int count = contours.Size;
        for (int i = 0; i < count; i++)
        {
            using (VectorOfPoint contour = contours[i])
            using (VectorOfPoint approxContour = new VectorOfPoint())
            {
                CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.05, true);
                Rectangle BoundingBox = CvInvoke.BoundingRectangle(approxContour);
                CvInvoke.Rectangle(draw, BoundingBox, new MCvScalar(255, 0, 255, 255), 3);
            }
        }
    }
}

这里写图片描述

可以看到有许多卷卷的地方,都被近似掉了,以至于框选出来的范围会失真。
但,若目标是长方形或三角形这种比较规则的形状,使用近似的方法可以提升执行的效率。

其实若是直接把轮廓线画出来就可以看得更清楚,近似后许多细节会消失。
以下是程式码与执行结果。

public static void DrawContour(Image<Gray, byte> src, Image<Bgr, byte> draw)
{
    using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
    {
        CvInvoke.FindContours(src, contours, null, RetrType.External,
                                ChainApproxMethod.ChainApproxSimple);

        int count = contours.Size;
        for (int i = 0; i < count; i++)
        {
            using (VectorOfPoint contour = contours[i])
            using (VectorOfPoint approxContour = new VectorOfPoint())
            {
                // 原始輪廓線
                CvInvoke.DrawContours(draw, contours, i, new MCvScalar(255, 0, 255, 255), 3);

                // 近似後輪廓線
                CvInvoke.ApproxPolyDP(contour, approxContour, 
                                      CvInvoke.ArcLength(contour, true) * 0.02, true);
                Point[] pts = approxContour.ToArray();
                for(int j=0; j<pts.Length; j++)
                {
                    Point p1 = new Point(pts[j].X, pts[j].Y);
                    Point p2;

                    if (j == pts.Length - 1)
                        p2 = new Point(pts[0].X, pts[0].Y);
                    else
                        p2 = new Point(pts[j+1].X, pts[j+1].Y);

                    CvInvoke.Line(draw, p1, p2, new MCvScalar(255, 0, 0, 0), 3);
                }
            }
        }
    }
}

这里写图片描述

2. ConvexHull: 可以框住区块的最小多边形。

public static void ConvexHull(Image<Gray, byte> src, Image<Bgr, byte> draw)
{
    using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
    {
        CvInvoke.FindContours(src, contours, null, RetrType.External,
                                ChainApproxMethod.ChainApproxSimple);

        int count = contours.Size;
        for (int i = 0; i < count; i++)
        {
            using (VectorOfPoint contour = contours[i])
            {
                PointF[] temp = Array.ConvertAll(contour.ToArray(),
                                                new Converter<Point, PointF>(Point2PointF));
                PointF[] pts = CvInvoke.ConvexHull(temp, true);

                for (int j = 0; j < pts.Length; j++)
                {
                    Point p1 = new Point((int)pts[j].X, (int)pts[j].Y);
                    Point p2;

                    if (j == pts.Length - 1)
                        p2 = new Point((int)pts[0].X, (int)pts[0].Y);
                    else
                        p2 = new Point((int)pts[j + 1].X, (int)pts[j + 1].Y);

                    CvInvoke.Line(draw, p1, p2, new MCvScalar(255, 0, 255, 255), 3);
                }
            }
        }
    }
}

private static PointF Point2PointF(Point P)
{
    PointF PF = new PointF
    {
        X = P.X,
        Y = P.Y
    };
    return PF;
}

这里写图片描述

3. MinAreaBoundingBox: 可框住区域的最小矩形。

这是可旋转的矩形,意即找到面积最小,又可以框住该区域的矩形。

public static void MinAreaBoundingBox(Image<Gray, byte> src, Image<Bgr, byte> draw)
{
    using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
    {
        CvInvoke.FindContours(src, contours, null, RetrType.External,
                                ChainApproxMethod.ChainApproxSimple);

        int count = contours.Size;
        for (int i = 0; i < count; i++)
        {
            using (VectorOfPoint contour = contours[i])
            {
                RotatedRect BoundingBox = CvInvoke.MinAreaRect(contour);
                CvInvoke.Polylines(draw, Array.ConvertAll(BoundingBox.GetVertices(), Point.Round), 
                                   true, new Bgr(Color.DeepPink).MCvScalar, 3);
            }
        }
    }
}

这里写图片描述

4. MinAreaCircle:可框住区域的最小圆形。

public static void MinAreaCircle(Image<Gray, byte> src, Image<Bgr, byte> draw)
{
    using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
    {
        CvInvoke.FindContours(src, contours, null, RetrType.External,
                                ChainApproxMethod.ChainApproxSimple);

        int count = contours.Size;
        for (int i = 0; i < count; i++)
        {
            using (VectorOfPoint contour = contours[i])
            {
                CircleF circle = CvInvoke.MinEnclosingCircle(contour);       
                CvInvoke.Circle(draw, new Point((int)circle.Center.X, (int) circle.Center.Y),
                                (int)circle.Radius, new MCvScalar(255, 0, 255, 255), 3);
            }
        }
    }
}

这里写图片描述
在EmguCV内一种轮廓线就一种画法。
真的是要足够熟练才能够驾驭这些函数唉!

像是可怜的小夏已经陷在这些函数内好几天了,真是头昏眼花,临表泣涕,不知所云。

翻译自:dotblogs.com.tw 夏恩的程式笔记

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/129492.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 周鸿祎经典语录

    周鸿祎经典语录 ·如果是你想干的事情,在别人看起来可能是很难的一件事,不过你自己很喜欢,你不会觉得很苦。我开始创业那会是28岁。对我来讲,我创业的目的不是为了自己当老板,我希望有一个平台有一个环境,我可以控制一些资源,让我去创造一个新的产品和服务;  ·我不会顾忌别人怎么看,或者顾忌到放弃什么东西。我喜欢两句诗“天生我才必有用,千金散尽还复来”。当年离开方正,也是这样仰天大笑出门去……  ·如果说…

  • 简单单元測试思想

    简单单元測试思想

  • LiveWriter高亮显示方法专题「建议收藏」

    LiveWriter高亮显示方法专题「建议收藏」2013年9月26日花了一上午的时间,熟悉了LiveWriter的用法,学会了怎么配置语法高亮,总结下来。方法1.用博客园推荐的方法没有成功。pass方法2方法来自一个人的旅行.试过OK博客

  • FreeSync是什么

    FreeSync是什么FreeSync由AMD开发,是一种动态刷新率功能,通过嵌入式和外部DisplayPort面板实现,部分AMDGPU中的FreeSync技术解决了处理器和显示器之间的通信问题,消除了图像撕裂和波动,从而轻松实现流畅的游戏体验。于2014年首次宣布与Nvidia的专有G-Sync竞争。AMD已与VESA(视频电子标准协会)合作,将DisplaySync的支持添加到DisplayPort1.2a标准,以及后来的HDMI,然后将其用于FreeSync技

  • Java液晶数字字体显示当前时间[通俗易懂]

    Java液晶数字字体显示当前时间[通俗易懂]Java液晶数字字体显示当前时间importjava.text.SimpleDateFormat;importjava.util.ArrayList;importjava.util.Date;importjava.util.HashMap;importjava.util.List;importjava.util.Map;/****@authorzdy…

    2022年10月29日
  • 05_Spring Cloud Alibaba Dubbo

    05_Spring Cloud Alibaba Dubbo

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号