C#使用OpenCV剪切图像中的圆形和矩形
前言
本文主要介绍如何使用OpenCV剪切图像中的圆形和矩形。
准备工作
首先创建一个Wpf项目——WpfOpenCV,这里版本使用Framework4.7.2。
然后使用Nuget搜索【Emgu.CV】,如下图。
这里的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);
}
}
然后运行项目,点击剪切矩形文件。
然后到debug文件夹下,查看结果。
测试结果如下图所示:
图中红线为检测到矩形后,手动画上去的矩形轮廓。
使用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();
}
运行项目进行测试,结果如下:
----------------------------------------------------------------------------------------------------
到此,C#使用OpenCV剪切图像中的圆形和矩形就已经介绍完了。
代码已经传到Github上了,欢迎大家下载。
Github地址: https://github.com/kiba518/OpenCv_CutImage
----------------------------------------------------------------------------------------------------
注:此文章为原创,任何形式的转载都请联系作者获得授权并注明出处!
若您觉得这篇文章还不错,请点击下方的【推荐】,非常感谢!
https://www.cnblogs.com/kiba/p/14497894.html
C#使用OpenCV剪切图像中的圆形和矩形的更多相关文章
- C#使用OpenCV剪切图形中的人物头像
前言 本文主要介绍如何使用OpenCV剪切图形中的人物头像. 准备工作 首先创建一个Wpf项目--OpenCV_Face_Wpf,这里版本使用Framework4.7.2. 然后使用Nuget搜索[E ...
- (转)使用Python和OpenCV检测图像中的物体并将物体裁剪下来
原文链接:https://blog.csdn.net/liqiancao/article/details/55670749 介绍 硕士阶段的毕设是关于昆虫图像分类的,代码写到一半,上周五导师又给我新的 ...
- opencv 替换图像中的一部分
首先选取图像中的Roi区域,然后对Roi区域进行赋值,那么原图像相应的区域也跟着变化了: dst = src.clone(); cv::Mat Roi(dst, cv::Rect(x, y, cut_ ...
- 利用OpenCV检测图像中的长方形画布或纸张并提取图像内容
基于知乎上的一个答案.问题如下: 也就是在一张照片里,已知有个长方形的物体,但是经过了透视投影,已经不再是规则的长方形,那么如何提取这个图形里的内容呢?这是个很常见的场景,比如在博物馆里看到一幅很喜欢 ...
- OpenCV绘制图像中RGB三个通道的直方图
一开始是看<OpenCV计算机视觉编程攻略(第2版)>这本书学做直方图,但是书本里说直方图的部分只详细说了黑白图像(单通道)的直方图绘制方法,RGB图像的直方图只说了如何计算,没有说计算完 ...
- C++判断图像中一点是否在矩形中
需要判断出四条之间组成的矩形的范围,其中矩形的边缘可能是倾斜不平行于x或者y轴. 考虑和很久,参考博客http://blog.csdn.net/dapengbusi/article/details/5 ...
- 访问图像中的像素[OpenCV 笔记16]
再更一发好久没更过的OpenCV,不过其实写到这个部分对计算机视觉算法有所了解的应该可以做到用什么查什么了,所以后面可能会更的慢一点吧,既然开了新坑,还是机器学习更有研究价值吧... 图像在内存中的存 ...
- 在OpenCV中利用鼠标绘制矩形和截取图像的矩形区域
这是两个相关的程序,前者是后者的基础.实际上前一个程序也是在前面博文的基础上做的修改,请参考<在OpenCV中利用鼠标绘制直线> .下面贴出代码. 程序之一,在OpenCV中利用鼠标绘制矩 ...
- OpenCV——反向投影(定位模板图像在输入图像中的位置)
反向投影: #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namesp ...
随机推荐
- .NET并发编程-函数闭包
本系列学习在.NET中的并发并行编程模式,实战技巧 内容目录 函数式编程闭包的应用记忆化函数缓存 函数式编程 一个函数输出当做另一个函数输入.有时候一个复杂问题,我们拆分成很多个步骤函数,这些函数组合 ...
- [Python] Pandas 中 Series 和 DataFrame 的用法笔记
目录 1. Series对象 自定义元素的行标签 使用Series对象定义基于字典创建数据结构 2. DataFrame对象 自定义行标签和列标签 使用DataFrame对象可以基于字典创建数据结构 ...
- [Golang]-6 超时处理、非阻塞通道操作、通道的关闭和遍历
目录 超时处理 非阻塞通道操作 通道的关闭 通道遍历 超时处理 超时 对于一个连接外部资源,或者其它一些需要花费执行时间的操作的程序而言是很重要的. 得益于通道和 select,在 Go中实现超时操作 ...
- cmder设置方法
一.添加鼠标右键 Cmder.exe /REGISTER ALL 二.添加系统环境变量 我的电脑 > 右键属性 > 高级系统设置 > 环境变量 > 系统变量,在path中添加 ...
- 牛客国庆2 F-平衡二叉树【非原创】
题目:戳这里 学习博客:戳这里
- scu-4440 rectangle (非原创)
Rectangle frog has a piece of paper divided into nn rows and mm columns. Today, she would like to dr ...
- git merge bug
git merge bug 本地分支 dev commit 后, 直接 pull 远程 dev 分支, 导致远程 dev 分支 merge 到本地 dev 分支了, 取消本次 merge 操作? Re ...
- PEP 8 & Style Guide
PEP 8 & Style Guide Style Guide for Python Code https://www.python.org/dev/peps/pep-0008/ PEP Py ...
- Docker & Node.js
Docker & Node.js https://nodejs.org/en/docs/guides/nodejs-docker-webapp/ https://docs.docker.com ...
- Serverless & FaaS
Serverless & FaaS Function as a Service 通过 Functions(一个事件驱动型无服务器计算平台,还可以解决复杂的业务流程问题)更加高效地进行开发; 在 ...