【C#】用EmguCV 绘制各种轮廓线
来源:互联网 发布:美工运营对骂gif 编辑:程序博客网 时间:2024/05/29 10:08
一般在做影像处理时,为提升效率,常会将影像转为二值影像后再进行处理。
在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\1.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 夏恩的程式笔记
- 【C#】用EmguCV 绘制各种轮廓线
- 【EmguCV】EmguCV各种调用
- Emgucv绘制图形
- 轮廓 - 查找轮廓、表示轮廓、绘制轮廓
- 轮廓 - 查找轮廓、表示轮廓、绘制轮廓
- 轮廓 - 查找轮廓、表示轮廓、绘制轮廓
- opencv找轮廓线并绘制轮廓线
- OpenCV与EmguCV中的图像轮廓提取
- EmguCV提取轮廓的一个例子
- opencv 查找轮廓 绘制轮廓
- C#+Emgucv视频获取
- 第八章 - 轮廓 - 查找轮廓、表示轮廓、绘制轮廓
- CvDrawContours绘制轮廓
- cvDrawContours绘制轮廓
- mfc 绘制文字轮廓
- Basemap绘制四川轮廓
- 使用几何着色器来实现绘制模型轮廓线
- 使用emguCV/C# opencv绘制自定义直方图
- Windows环境下使用Nexus 3.X 搭建Maven私服及使用介绍
- 利用 Python 进行数据分析之IPython (一)
- 通过存储控制器访问外设
- MYSQL存储引擎特性及选择
- 最长上升子序列LIS
- 【C#】用EmguCV 绘制各种轮廓线
- hdu 2807 The Shortest Path(矩阵计算+Floyd)
- 使用tensorflow:LSTM神经网络预测股票(二)
- ASP.NET Web.config
- 【设计模式系列】之设计模式概述
- 【设计模式系列】之单利模式
- ActivityLifecycleCallbacks 实现app中所有Activity实例查找
- Javascript之变量作用域
- OSGi初识