C#使用OpenCV剪切图像中的圆形和矩形

简介: 本文主要介绍如何使用OpenCV剪切图像中的圆形和矩形。

前言

本文主要介绍如何使用OpenCV剪切图像中的圆形和矩形。


准备工作

首先创建一个Wpf项目——WpfOpenCV,这里版本使用Framework4.7.2。然后使用Nuget搜索【Emgu.CV】,如下图。

17.png

这里的Emgu.CV选择4.3.0.3890版本,然后安装Emgu.CV和Emgu.CV.runtime.windows。

使用OPenCV剪切矩形

现在,我们进入项目,进行OPenCV的调用。首先引入命名空间,如下:

using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using System.Drawing;
using System.Windows.Forms;

然后编写矩形剪切函数——CutRectangleImage。

函数里,我们先将图像进行缩放,这样可以有效的减少检测到的矩形数量。

再将图片处理成灰度模式,然后再高斯模糊,再边缘化。

然后,我们就可以在图片里查找图形轮廓了,当轮廓有三个顶点,那么它是三角形,如果有四个顶点,那么它是四边形;我们要截取矩形,所以这里要加一个角度的判断,四个角必须都在80-100度之间。

取到了顶点后,在依据顶点剪切图片就可以了。

下面是截取矩形的代码,代码中只截取了宽度最大的那个矩形。

public void CutRectangleImage(string imagePath)
{
    Image<Bgr, Byte> src = new Image<Bgr, byte>(imagePath);
    int scale = 1;
    if (src.Width > 500)
    {
        scale = 2;
    }
    if (src.Width > 1000)
    {
        scale = 10;
    }
    if (src.Width > 10000)
    {
        scale = 100;
    }
    var size = new Size(src.Width / scale, src.Height / scale);
    Image<Bgr, Byte> srcNewSize = new Image<Bgr, byte>(size);
    CvInvoke.Resize(src, srcNewSize, size);
    //将图像转换为灰度
    UMat grayImage = new UMat(); 
    CvInvoke.CvtColor(srcNewSize, grayImage, ColorConversion.Bgr2Gray);
    //使用高斯滤波去除噪声
    CvInvoke.GaussianBlur(grayImage, grayImage, new Size(3, 3), 3);
    UMat cannyEdges = new UMat();
    CvInvoke.Canny(grayImage, cannyEdges, 60, 180);//通过边缘化,然后取出轮廓
    #region 取三角形和矩形的顶点坐标
    List<Triangle2DF> triangleList = new List<Triangle2DF>();
    List<RotatedRect> boxList = new List<RotatedRect>(); //旋转的矩形框
    using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
    {
        CvInvoke.FindContours(cannyEdges, contours, null, RetrType.List, 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.08, true);
                //仅考虑面积大于50的轮廓
                if (CvInvoke.ContourArea(approxContour, false) > 50)
                {
                    if (approxContour.Size == 3) //轮廓有3个顶点:三角形
                    {
                        System.Drawing.Point[] pts = approxContour.ToArray();
                        triangleList.Add(new Triangle2DF(pts[0], pts[1], pts[2]));
                    }
                    else if (approxContour.Size == 4) //轮廓有4个顶点
                    {
                        #region 检测角度,如果角度都在 [80, 100] 之间,则为矩形
                        bool isRectangle = true;
                        System.Drawing.Point[] pts = approxContour.ToArray();
                        LineSegment2D[] edges = Emgu.CV.PointCollection.PolyLine(pts, true);
                        for (int j = 0; j < edges.Length; j++)
                        {
                            double angle = Math.Abs(edges[(j + 1) % edges.Length].GetExteriorAngleDegree(edges[j]));
                            if (angle < 80 || angle > 100)
                            {
                                isRectangle = false;
                                break;
                            }
                        }
                        #endregion
                        if (isRectangle) boxList.Add(CvInvoke.MinAreaRect(approxContour));
                    }
                }
            }
        }
    }
    #endregion
    #region 保存剪切的最大的矩形图片  
    Rectangle rectangle = new Rectangle(0, 0, src.Width, src.Height);
    int maxWidth = 0;
    //boxList = boxList.Where(p => p.Size.Width > 300).ToList();
    for (int i = 0; i < boxList.Count(); i++)
    {
        RotatedRect box = boxList[i];
        Rectangle rectangleTemp = box.MinAreaRect();
        //这里对取到的顶点坐标进行了加宽,因为矩形可能存在角度,这里没有进行角度旋转,所以加宽了取值范围就可以取到完整的图了
        rectangleTemp = new Rectangle(rectangleTemp.X * scale, rectangleTemp.Y * scale, rectangleTemp.Width * scale + scale, rectangleTemp.Height * scale + scale);
        //取最大的矩形图片
        if (rectangleTemp.Width > maxWidth)
        {
            maxWidth = rectangleTemp.Width;
            rectangle = rectangleTemp;
        }
    }
    src.Draw(rectangle, new Bgr(System.Drawing.Color.Red), 4);//在图片中画线
    CvInvoke.Imwrite("原始图片.bmp", src); //保存原始图片
    CvInvoke.cvSetImageROI(src.Ptr, rectangle);//设置兴趣点—ROI(region of interest )
    var clone = src.Clone(); 
    CvInvoke.Imwrite("剪切的矩形图片.bmp", clone); //保存结果图  
    #endregion
    src.Dispose();
    srcNewSize.Dispose();
    grayImage.Dispose();
}

然后编写一个打开文件的函数,在成功打开文件后调用CutRectangleImage。

private void btnRectangle_Click(object sender, RoutedEventArgs e)
{
    System.Windows.Forms.OpenFileDialog frm = new System.Windows.Forms.OpenFileDialog();
    frm.Filter = "(*.jpg,*.png,*.jpeg,*.bmp,*.gif)|*.jgp;*.png;*.jpeg;*.bmp;*.gif|All files(*.*)|*.*";
    if (frm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
    {
        CutRectangleImage(frm.FileName);
    } 
}

然后运行项目,点击剪切矩形文件。

118.png


然后到debug文件夹下,查看结果。

测试结果如下图所示:

18.png


图中红线为检测到矩形后,手动画上去的矩形轮廓。


使用OPenCV剪切圆形

编写矩形剪切函数——CutCircleImage。

函数里,我们依然先将图像进行缩放,为了有效的减少检测到的圆形数量。

再将图片处理成灰度模式,然后再高斯模糊。

然后再使用霍夫圆检测函数,获取圆的圆心和半径。

最后再根据圆心和半径计算出最小矩形,然后将圆剪切并保存。

代码如下:

public void CutCircleImage(string imagePath)
{ 
    Image<Bgr, Byte> src = new Image<Bgr, byte>(imagePath);
    int scale = 1;
    if (src.Width > 500)
    {
        scale = 2;
    }
    if (src.Width > 1000)
    {
        scale = 10;
    }
    if (src.Width > 10000)
    {
        scale = 100;
    } 
    var size = new Size(src.Width / scale, src.Height / scale);
    Image<Bgr, Byte> srcNewSize = new Image<Bgr, byte>(size);
    CvInvoke.Resize(src, srcNewSize, size);
    //将图像转换为灰度
    UMat grayImage = new UMat();
    CvInvoke.CvtColor(srcNewSize, grayImage, ColorConversion.Bgr2Gray); 
    //使用高斯滤波去除噪声
    CvInvoke.GaussianBlur(grayImage, grayImage, new Size(3, 3), 3); 
    //霍夫圆检测
    CircleF[] circles = CvInvoke.HoughCircles(grayImage, HoughModes.Gradient, 2.0, 200.0, 100.0, 180.0, 5);
    Rectangle rectangle = new Rectangle();
    float maxRadius = 0;
    foreach (CircleF circle in circles)
    {
        var center = circle.Center;//圆心
        var radius = circle.Radius;//半径
        if (radius > maxRadius)
        {
            maxRadius = radius;
            rectangle = new Rectangle((int)(center.X - radius) * scale,
                (int)(center.Y - radius) * scale,
                (int)radius * 2 * scale + scale,
                (int)radius * 2 * scale + scale);
        }
        srcNewSize.Draw(circle, new Bgr(System.Drawing.Color.Blue), 4);
    }
    CvInvoke.Imwrite("原始图片.bmp", srcNewSize); //保存原始图片
    if (maxRadius == 0)
    {
        MessageBox.Show("没有圆形");
    }
    CvInvoke.cvSetImageROI(srcNewSize.Ptr, rectangle);//设置兴趣点—ROI(region of interest )
    var clone = srcNewSize.Clone();
    CvInvoke.Imwrite("剪切的圆形图片.bmp", clone); //保存结果图  
    src.Dispose();
    srcNewSize.Dispose();
    grayImage.Dispose();
}


运行项目进行测试,结果如下:


19.png


到此,C#使用OpenCV剪切图像中的圆形和矩形就已经介绍完了。

代码已经传到Github上了,欢迎大家下载。

Github地址:https://github.com/kiba518/OpenCv_CutImage

本文作者:kiba518,全栈.Net软件工程师

声明:本文为 脚本之家专栏作者 投稿,未经允许请勿转载。

相关文章
|
2月前
|
计算机视觉
Opencv学习笔记(三):图像二值化函数cv2.threshold函数详解
这篇文章详细介绍了OpenCV库中的图像二值化函数`cv2.threshold`,包括二值化的概念、常见的阈值类型、函数的参数说明以及通过代码实例展示了如何应用该函数进行图像二值化处理,并展示了运行结果。
470 0
Opencv学习笔记(三):图像二值化函数cv2.threshold函数详解
|
3月前
|
数据采集 JavaScript C#
C#图像爬虫实战:从Walmart网站下载图片
C#图像爬虫实战:从Walmart网站下载图片
|
3月前
|
算法 计算机视觉
opencv图像形态学
图像形态学是一种基于数学形态学的图像处理技术,它主要用于分析和修改图像的形状和结构。
52 4
|
3月前
|
存储 计算机视觉
Opencv的基本操作(一)图像的读取显示存储及几何图形的绘制
本文介绍了使用OpenCV进行图像读取、显示和存储的基本操作,以及如何绘制直线、圆形、矩形和文本等几何图形的方法。
Opencv的基本操作(一)图像的读取显示存储及几何图形的绘制
|
4月前
|
算法 计算机视觉 Python
python利用opencv进行相机标定获取参数,并根据畸变参数修正图像附有全部代码(流畅无痛版)
该文章详细介绍了使用Python和OpenCV进行相机标定以获取畸变参数,并提供了修正图像畸变的全部代码,包括生成棋盘图、拍摄标定图像、标定过程和畸变矫正等步骤。
python利用opencv进行相机标定获取参数,并根据畸变参数修正图像附有全部代码(流畅无痛版)
WK
|
4月前
|
编解码 计算机视觉 Python
如何在OpenCV中进行图像转换
在OpenCV中,图像转换涉及颜色空间变换、大小调整及类型转换等操作。常用函数如`cvtColor`可实现BGR到RGB、灰度图或HSV的转换;`resize`则用于调整图像分辨率。此外,通过`astype`或`convertScaleAbs`可改变图像数据类型。对于复杂的几何变换,如仿射或透视变换,则可利用`warpAffine`和`warpPerspective`函数实现。这些技术为图像处理提供了强大的工具。
WK
120 1
|
6月前
|
算法 计算机视觉
【Qt&OpenCV 图像的感兴趣区域ROI】
【Qt&OpenCV 图像的感兴趣区域ROI】
199 1
|
5月前
|
机器学习/深度学习 XML 计算机视觉
OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习库,它提供了大量的函数和工具,用于处理图像和视频数据。
OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习库,它提供了大量的函数和工具,用于处理图像和视频数据。
|
1月前
|
C# 开发者
C# 一分钟浅谈:Code Contracts 与契约编程
【10月更文挑战第26天】本文介绍了 C# 中的 Code Contracts,这是一个强大的工具,用于通过契约编程增强代码的健壮性和可维护性。文章从基本概念入手,详细讲解了前置条件、后置条件和对象不变量的使用方法,并通过具体代码示例进行了说明。同时,文章还探讨了常见的问题和易错点,如忘记启用静态检查、过度依赖契约和性能影响,并提供了相应的解决建议。希望读者能通过本文更好地理解和应用 Code Contracts。
32 3
|
3月前
|
API C#
C# 一分钟浅谈:文件系统编程
在软件开发中,文件系统操作至关重要。本文将带你快速掌握C#中文件系统编程的基础知识,涵盖基本概念、常见问题及解决方法。文章详细介绍了`System.IO`命名空间下的关键类库,并通过示例代码展示了路径处理、异常处理、并发访问等技巧,还提供了异步API和流压缩等高级技巧,帮助你写出更健壮的代码。
46 2