C#:Canny边缘检测
2023-01-14 本文已影响0人
大龙10
边缘检测目的是在保留原有图像属性的情况下,显著减少图像的数据规模。
有多种算法可以进行边缘检测,虽然Canny算法年代久远,但可以说它是边缘检测的一种标准算法。
一、Canny边缘检测
- Canny边缘检测的历史比较久远,最早是在1986年的时候提出的,通常称为Canny边缘检测算法。
- Canny边缘检测算法是一种对噪声比较敏感的边缘检测方法,
所以通常在使用Canny边缘检测之前,首先对图像进行降噪。 - 图像噪声抑制方法主要有均值滤波、高斯滤波、中值滤波,
一般情况下,会优先考虑使用高斯滤波来完成噪声抑制,
因为多数噪声都是自然界中的随机噪声,高斯模糊对它们有不同程度的抑制作用。 - Canny边缘检测一个最大的创新在于其使用两个阈值尝试把所有的边缘像素连接起来,形成边缘曲线或者线段。
二、检测步骤
完整的Canny边缘检测由如下步骤组成。
- 1)高斯模糊:完成噪声抑制。
- 2)灰度转换:在灰度图像上计算梯度值。
- 3)计算梯度:使用Sobel/Scharr。
- 4)非最大信号抑制:在梯度图像上寻找局部最大值。
- 5)高低阈值连接:把边缘像素连接为线段,形成完整边缘轮廓。
上面的第5步是使用高低阈值连接,Canny推荐的高低阈值比在2:1到3:1之间,
首先使用低阈值,把低于低阈值边缘的像素点都去掉,
然后保留所有高于高阈值的像素点,
对于处于高阈值与低阈值之间的像素点,如果从高阈值像素点出发,经过的所有像素点都高于低阈值,则保留这些像素,否则丢弃。
OpenCV中Canny边缘检测函数已经包含了上述5个步骤。
三、函数Cv2.Canny
Cv2.Canny(src_img, dst, tkBarCannyMin.Value, kBarCannyMax.Value, hole, rbBtnTrue.Checked);
参数:
- 1,8 bit 输入图像;
- 2,输出边缘图像,一般是二值图像,背景是黑色;
- 3,低阈值。值越大,找到的边缘越少;
- 4,高阈值;
- 5,表示应用Sobel算子的孔径大小,其有默认值3;
- 6,计算图像梯度幅值的标识,有默认值false。
低于阈值1的像素点会被认为不是边缘;
高于阈值2的像素点会被认为是边缘;
在阈值1和阈值2之间的像素点,若与一阶偏导算子计算梯度得到的边缘像素点相邻,则被认为是边缘,否则被认为不是边缘。
四、程序
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using Sunny.UI;
namespace Ky_Cv2Canny
{
public partial class Form1 : UIForm
{
private Image image = null;
private Mat dst = new Mat();
private Mat src_img;
string filePath = "";
//private static int Num = 20;
private List<Mat> reList = new List<Mat>();
private int step = 1;
public Form1()
{
InitializeComponent();
this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint, true);
}
private void openImage_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Title = "选择操作的图片";
openFileDialog.Filter = "图片 *.jpg|*.jpg|图像*.png|*.png";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
filePath = openFileDialog.FileName;
image = Image.FromFile(filePath);
src_img = Cv2.ImRead(filePath);
Mat tem1 = new Mat();
src_img.CopyTo(tem1);
if (reList.Count > 0)
{
reList[0] = tem1;
}
else
{
reList.Add(tem1);
}
}
if (filePath != "")
{
picBoxShowDel.Image = image;
picShowOri.Image = image;
}
}
/// <summary>
/// 边缘检测Canny
/// </summary>
private void Canny()
{
int hole = 0;
if (!int.TryParse(txtBoxCannyHole.Text, out hole))
{
return;
}
try
{
Cv2.Canny(src_img, dst, tkBarCannyMin.Value, tkBarCannyMax.Value, hole, rbBtnTrue.Checked);
picBoxShowDel.Image = dst.ToBitmap();
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
private void tkBarCannyMin_Scroll(object sender, EventArgs e)
{
if (tkBarCannyMin.Value < 0)
{
tkBarCannyMin.Value = 0;
}
uiLabel_Cs3.Text = tkBarCannyMin.Value.ToString();
}
private void tkBarCannyMax_Scroll(object sender, EventArgs e)
{
if (tkBarCannyMax.Value < 0)
{
tkBarCannyMax.Value = 0;
}
uiLabel_Cs4.Text = tkBarCannyMax.Value.ToString();
}
private void uiButton1_Click(object sender, EventArgs e)
{
Canny();
}
}
}
五、资料
xaiqpl的博客 https://blog.csdn.net/xaiqpl/article/details/118597812?spm=1001.2014.3001.5502