一、边缘检测
提取边缘:根据灰度的差值来获取边缘
1、Canny算子
// 提取边缘
// 使用canny算子,阈值1和阈值2中的最小值用于边缘。
// 参数:输入图片,输出图片,阈值1,阈值2
//大于高阈值,强边缘点;小于高阈值高于低阈值,弱边缘点;小于低阈值,过滤。
//滞后边界跟踪:强边缘点被认为是真边缘点,弱边缘可能是真边缘也可能是噪声引起的假边缘点。只有当假边缘点连接到真边缘点时,保留假边缘点,否则去除。
CvInvoke.Canny(grayImage, cannyImg, 20, 40);
2、Soble算子
//提取边缘
//Sobel算子,参数:输入图片,输出图片,图像深度,x 方向上的几阶导数,y 方向上的几阶导数
CvInvoke.Sobel(grayImage, sobelImage, grayImage.Depth, 1, 0);
3、Laplacian算子
//提取边缘
//Laplacian算子 参数:输入图片,输出图片,图像深度,二阶导数滤波器的孔径大小,拉普拉斯值的可选比例因子,结果存储到之前添加到结果中的可选增量值
CvInvoke.Laplacian(grayImage, LaplacianImage, grayImage.Depth, 3, 1, 0);
4、三种算子的优缺点
//1、Canny 不容易受噪声干扰,使用两种不同的阈值能够检测到真正的弱边缘 容易把噪点误判为边界 常用
//2、Sobel 对灰度渐变和噪声较多的图像处理效果较好 精度不高 精度要求不高时常用
//3、Laplacian 无方向性,对任何走向的界线和线条进行锐化 对噪声特别敏感 一般图像用的较少
二、霍夫检测
1、霍夫圆检测
private void 霍夫圆检测ToolStripMenuItem_Click(object sender, EventArgs e)
{
Mat readImage = new Mat();
//为了简便、封装的获取图片方法
ClassStatic.readImage("7", ClassStatic.Jpg, ref readImage);
Mat grayImage = new Mat();
//转化为灰度
CvInvoke.CvtColor(readImage, grayImage, ColorConversion.Rgb2Gray);
Mat blurImage = new Mat();
//高斯滤波
CvInvoke.GaussianBlur(grayImage, blurImage, new Size(5, 5), 3);
//霍夫圆检测
//参数:输入图像,实现方法,dp,最小距离,参数1,参数2,最小圆半径,最大圆半径
//dp:累加器分辨率与图像分辨率的反比。例如,如果dp=1,累加器的分辨率与输入图像相同。如果dp=2,则蓄能器的宽度和高度为原来的一半。
//最小距离:检测到的圆的中心之间的最小距离。太小会多检,太大会漏检
//参数1:在CV_HOUGH_GRADIENT梯度的情况下,它是传递给Canny()边缘检测器的两个阈值中的较高阈值(较低的阈值是较小的两倍)。
//参数2:在CV_HOUGH_GRADIENT梯度的情况下,它是检测阶段圆心的累加器阈值。越小,可得到越多的圆。与较大累加器值相对应的圆将首先返回。
CircleF[] circles = CvInvoke.HoughCircles(blurImage, HoughModes.Gradient, 2, 20, 100, 180, 5);
Image<Bgr, byte> image = readImage.ToImage<Bgr, byte>().Copy();
foreach (CircleF circle in circles)
{
//画一个特定颜色和厚度的圆 参数:要绘制的圆,圆的颜色,厚度:如果厚度小于1,则填充圆
image.Draw(circle, new Bgr(Color.Blue), 4);
}
CvInvoke.Imshow("circle image", image);
}
2、霍夫线检测
private void 霍夫线检测ToolStripMenuItem_Click(object sender, EventArgs e)
{
Mat readImage = new Mat();
//为了简便、封装的获取图片方法
ClassStatic.readImage("8", ClassStatic.Jpg, ref readImage);
Mat grayImage = new Mat();
//转化为灰度
CvInvoke.CvtColor(readImage, grayImage, ColorConversion.Rgb2Gray);
Mat blurImage = new Mat();
//高斯滤波
CvInvoke.GaussianBlur(grayImage, blurImage, new Size(5, 5), 3);
Mat cannyImage = new Mat();
//canny算子提取边缘
CvInvoke.Canny(blurImage, cannyImage, 100, 120);
//霍夫线检测
//参数: 输入图形、累加器的距离分辨率(像素)、累加器的角度分辨率(弧度)、阈值、最小长度、最大间隙
LineSegment2D[] lines = CvInvoke.HoughLinesP(cannyImage, 1, Math.PI / 20, 30, 80, 30);
Image<Bgr, Byte> image = readImage.ToImage<Bgr, Byte>().Copy();
foreach (LineSegment2D line in lines)
{
//绘制线 参数:要绘制的线,线的颜色,线条粗细
image.Draw(line, new Bgr(Color.HotPink), 2);
}
CvInvoke.Imshow("Line Image", image);
}
3、矩形三角形检测
private void 矩形三角形检测ToolStripMenuItem_Click(object sender, EventArgs e)
{
Mat readImage = new Mat();
ClassStatic.readImage("9", ClassStatic.Jpg, ref readImage);
Mat grayImage = new Mat();
CvInvoke.CvtColor(readImage, grayImage, ColorConversion.Rgb2Gray);
Mat blurImage = new Mat();
CvInvoke.GaussianBlur(grayImage, blurImage, new Size(3, 3), 3);
Mat cannyImage = new Mat();
CvInvoke.Canny(blurImage, cannyImage, 60, 180);
CvInvoke.Imshow("", cannyImage);
List<Triangle2DF> triangleList = new List<Triangle2DF>(); //三角形列表
List<RotatedRect> rectList = new List<RotatedRect>();//矩形列表
//using(){}当我们做一些比较占用资源的操作,在此范围的末尾自动将对象释放。
//VectorOfVectorOfPoint:创建一个空的VectorOfPoint标准向量
using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
{
// 参数:输入图像,点向量,,检索类型,方法
CvInvoke.FindContours(cannyImage, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple);
for (int i = 0; i < contours.Size; i++)
{
using (VectorOfPoint contour = contours[i]) //点的标准矢量
using (VectorOfPoint approxContour = new VectorOfPoint())
{
// CvInvoke.ApproxPolyDP:指定精度的多边形曲线 参数:输入向量(轮廓),近似轮廓,近似精度,true:则闭合形状
// CvInvoke.ArcLength:计算轮廓长度 参数:轮廓,曲线是否闭合
CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.08, true); //0.08的相似度
//CvInvoke.ContourArea:计算轮廓面积 参数:轮廓,返回值是否为绝对值
//仅考虑面积大于50的轮廓
if (CvInvoke.ContourArea(approxContour, false) > 50)
{
if (approxContour.Size == 3)//轮廓有3个顶点:三角形
{
Point[] points = approxContour.ToArray(); //转化为数组
triangleList.Add(new Triangle2DF(points[0], points[1], points[2]));
}
else if (approxContour.Size == 4)//轮廓有4个顶点:矩形
{
bool isRect = true;
Point[] points = approxContour.ToArray();
LineSegment2D[] rects = PointCollection.PolyLine(points, true);
for (int j = 0; j < rects.Length; j++)
{
double angle = Math.Abs(
rects[(j + 1) % rects.Length].GetExteriorAngleDegree(rects[j]));
//角度在小于80,大于100,判定不是矩形
if (angle < 80 || angle > 100)
{
isRect = false;
break;
}
}
if (isRect) { rectList.Add(CvInvoke.MinAreaRect(approxContour)); }
}
}
}
}
}
//展示结果
//三角形
Image<Bgr, Byte> image = readImage.ToImage<Bgr, Byte>().Copy();
foreach (Triangle2DF triangle in triangleList)
{
image.Draw(triangle, new Bgr(Color.Red), 2);
}
CvInvoke.Imshow("Triangle Image", image);
//矩形
Image<Bgr, Byte> iamge1 = readImage.ToImage<Bgr, Byte>().Copy();
foreach (RotatedRect rect in rectList)
{
iamge1.Draw(rect, new Bgr(Color.Red), 2);
}
CvInvoke.Imshow("Rect Image", iamge1);
CvInvoke.WaitKey();
}