C#Canny边缘检测算法

在进行边沿检测前先对当前图像做相关操作,m_Bitmap是当前图像

Rectangle rect = new Rectangle(0, 0, m_Bitmap.Width, m_Bitmap.Height);
BitmapData bmpData = m_Bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, m_Bitmap.PixelFormat);
IntPtr ptr = bmpData.Scan0;
int bytes = m_Bitmap.Width * m_Bitmap.Height*3 ;
byte[] grayValues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);

设置相关变量

				//得到阈值
                byte[] thresh = new byte[2];
                thresh[0] = Convert.ToByte(60);//根据实际需求改动
                thresh[1] = Convert.ToByte(25);//根据实际需求改动
                //得到均方差
                double sigema = 1.5;//根据实际需求改动
                double[] tempArray;
                double[] tempImage = new double[bytes];
                double[] grad = new double[bytes];
                byte[] aLable = new byte[bytes];
                double[] edgeMap = new double[bytes];
                double gradX, gradY, angle;

高斯模板半径

				//高斯模板半径=3sigema
                int rad = Convert.ToInt16(Math.Ceiling(3 * sigema));
                for (int i = 0; i < bytes; i++)
                {
                    tempImage[i] = Convert.ToDouble(grayValues[i]);
                }

//调用高斯平滑处理方法,在最下面会把该方法给出来

 gaussSmooth(tempImage, out tempArray, sigema);

//sobel一阶偏导求梯度幅值和方向

				for (int i = 0; i < m_Bitmap.Height; i++)
                {
                    for (int j = 0; j < m_Bitmap.Width; j++)
                    {
                        //水平方向梯度
                        gradX = tempArray[((Math.Abs(i - 1)) % m_Bitmap.Height) * m_Bitmap.Width + ((j + 1) % m_Bitmap.Width)] + 2 * tempArray[i * m_Bitmap.Width + ((j + 1) % m_Bitmap.Width)] + tempArray[((i + 1) % m_Bitmap.Height) * m_Bitmap.Width + ((j + 1) % m_Bitmap.Width)] - tempArray[((Math.Abs(i - 1)) % m_Bitmap.Height) * m_Bitmap.Width + ((Math.Abs(j - 1)) % m_Bitmap.Width)] - 2 * tempArray[i * m_Bitmap.Width + ((Math.Abs(j - 1)) % m_Bitmap.Width)] - tempArray[((i + 1) % m_Bitmap.Height) * m_Bitmap.Width + ((Math.Abs(j - 1)) % m_Bitmap.Width)];

                        //垂直方向梯度
                        gradY = tempArray[((Math.Abs(i - 1)) % m_Bitmap.Height) * m_Bitmap.Width + ((Math.Abs(j - 1)) % m_Bitmap.Width)] + 2 * tempArray[((Math.Abs(i - 1)) % m_Bitmap.Height) * m_Bitmap.Width + j] + tempArray[((Math.Abs(i - 1)) % m_Bitmap.Height) * m_Bitmap.Width + ((j + 1) % m_Bitmap.Width)] - tempArray[((i + 1) % m_Bitmap.Height) * m_Bitmap.Width + ((Math.Abs(j - 1)) % m_Bitmap.Width)] - 2 * tempArray[((i + 1) % m_Bitmap.Height) * m_Bitmap.Width + j]- tempArray[((i + 1) % m_Bitmap.Height) * m_Bitmap.Width+ ((j + 1) % m_Bitmap.Width)];

                        //梯度和
                        grad[i * m_Bitmap.Width + j] = Math.Sqrt(gradX * gradX + gradY * gradY);

                        //梯度方向(弧度)
                        
                        angle = Math.Atan2(gradY, gradX);

                        //四个方向量化
                        if ((angle >= -1.178097 && angle <= 1.178097) || angle >= 2.748894 || angle < -2.748894)
                        {
                            aLable[i * m_Bitmap.Width + j] = 0;
                        }
                        else if ((angle >= 0.392699 && angle < 1.178097) || (angle >= -2.748894 && angle < -1.963495))
                        {
                            aLable[i * m_Bitmap.Width + j] = 1;
                        }
                        else if ((angle >= -1.178097 && angle < -0.392699) || (angle >= 1.963495 && angle < 2.748894)) 
                        {
                            aLable[i * m_Bitmap.Width + j] = 2;
                        }
                        else
                        {
                            aLable[i * m_Bitmap.Width + j] = 3;
                        }

                    }
                }


//双阈值算法

				Array.Clear(grayValues, 0, bytes);
                for (int i = 0; i < m_Bitmap.Height ; i++)
                {
                    for (int j = 0; j < m_Bitmap.Width; j++)
                    {
                        if (edgeMap[i * m_Bitmap.Width + j]> thresh[0])
                        {
                            grayValues[i * m_Bitmap.Width + j] = 255;
                            //调用边缘的跟踪方法      
                            traceEdge(i, j, edgeMap, ref grayValues, thresh[1]);
                        }
                    }
                }

解锁m_Bitmap并在picturebox显示出来

				System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr, bytes);
                m_Bitmap.UnlockBits(bmpData);
                Invalidate();
                pictureBox1.Image = m_Bitmap;

在这个程序中涉及到两个方法
一个是高斯平滑处理方法:

		//高斯平滑处理方法
        //inputImage 输入图像
        // outputImage 输出图像
        //sigema 均方差
        private void gaussSmooth(double[]inputImage,out double[] outputImage,double sigema)
        {
            //方差
            double std2 = 2 * sigema * sigema;
            //半径=3sigema
            int radius = Convert.ToInt16(Math.Ceiling(3 * sigema));
            int filterWidth = 2 * radius + 1;
            double[] filter = new double[filterWidth];
            outputImage = new double[inputImage.Length];

            //限定输入的情况为方阵的情况下得到的图像的宽度和高度
            int length = Convert.ToInt16(Math.Sqrt(inputImage.Length));
            double[] tempImage = new double[inputImage.Length];

            double sum = 0;
            //产生一维高斯函数
            for (int i = 0; i < filterWidth; i++)
            {
                int xx = (i - radius) * (i - radius);
                filter[i] = Math.Exp(-xx / std2);
                sum += filter[i];
            }

            //归一化
            for (int i = 0; i < filterWidth; i++)
            {
                filter[i] = filter[i] / sum;
            }

            //水平方向滤波
            for (int i = 0; i < length; i++)
            {
                for (int j = 0; j < length; j++)
                {
                    double temp = 0;
                    for (int k = -radius; k <= radius; k++)
                    {
                        //循环拓展
                        int rem = (Math.Abs(j + k) % length);
                        //计算卷积和
                        temp += inputImage[i * length + rem] * filter[k + radius];
                    }
                    tempImage[i + length + j] = temp;
                }
            }

            //垂直方向滤波
            for (int j = 0; j < length; j++)
            {
                for (int i = 0; i < length; i++)
                {
                    double temp = 0;
                    for (int k = -radius ; k <=radius; k++)
                    {
                        //循环拓展
                        int rem = (Math.Abs(i + k) )% length;

                        //计算卷积和
                        temp += tempImage[rem * length + j] * filter[k + radius];
                    }
                    outputImage[i * length + j] = temp;
                }
            }
        }

另一个是边缘点跟踪方法:

		//边缘点跟踪方法
        //边缘跟踪,递归算法
        //k:图像纵坐标
        //l:图像横坐标
        //inputImage 梯度图像
        //outputImage 输出边缘图像
        //thrLow:低阈值
        private void traceEdge(int k,int l,double[]inputImage,ref byte[]outputImage,byte thrLow)
        {
            //8领域
            int[] kOffset = new int[] { 1, 1, 0, -1, -1, -1, 0, 1 };
            int[] lOffset = new int[] { 0, 1, 1, -1, 1, 0, -1, -1 };

            int kk, ll;
            
            for (int p = 0; p < 8; p++)
            {
                kk = k + kOffset[p];
                //循环拓展
                kk = Math.Abs(kk) % m_Bitmap.Height;

                ll = l + lOffset[p];
                //循环拓展
                ll = Math.Abs(ll) % m_Bitmap.Width;

                if (outputImage[ll * m_Bitmap.Width + kk] != 255) 
                {
                    if (inputImage[ll * m_Bitmap.Width + kk] > thrLow) 
                    {
                        outputImage[ll * m_Bitmap.Width + kk] = 255;

                        //递归调用
                        traceEdge(ll, kk, inputImage, ref outputImage, thrLow);
                    }
                }
            }
        }
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
OpenCVSharp 是一个用于计算机视觉的 C# 接口,它实现了 OpenCV 库的操作。在 OpenCVSharp 中,边缘检测是一项非常重要的任务,可以帮助我们找到图像中的物体轮廓,或者是进行图像分割等任务。 下面介绍几种 OpenCVSharp 中常用的边缘检测算法: 1. Canny 算法 Canny 算法是一种经典的边缘检测算法,它通过计算图像中像素点的梯度值,并进行非极大值抑制、双阈值处理等操作,最终得到图像中的边缘信息。在 OpenCVSharp 中,可以使用以下代码来进行 Canny 边缘检测: ```csharp Mat src = Cv2.ImRead("input.jpg", ImreadModes.Grayscale); Mat dst = new Mat(); Cv2.Canny(src, dst, 100, 200); Cv2.ImShow("Canny", dst); Cv2.WaitKey(0); ``` 2. Sobel 算法 Sobel 算法是一种基于梯度的边缘检测算法,它利用图像中像素点的梯度信息来检测边缘。在 OpenCVSharp 中,可以使用以下代码来进行 Sobel 边缘检测: ```csharp Mat src = Cv2.ImRead("input.jpg", ImreadModes.Grayscale); Mat dst = new Mat(); Cv2.Sobel(src, dst, MatType.CV_8U, 1, 1); Cv2.ImShow("Sobel", dst); Cv2.WaitKey(0); ``` 3. Laplacian 算法 Laplacian 算法是一种基于二阶导数的边缘检测算法,它可以检测出图像中的高频部分,从而得到图像的边缘信息。在 OpenCVSharp 中,可以使用以下代码来进行 Laplacian 边缘检测: ```csharp Mat src = Cv2.ImRead("input.jpg", ImreadModes.Grayscale); Mat dst = new Mat(); Cv2.Laplacian(src, dst, MatType.CV_8U); Cv2.ImShow("Laplacian", dst); Cv2.WaitKey(0); ``` 以上是 OpenCVSharp 中常用的几种边缘检测算法,不同的算法适用于不同的场景,可以根据具体需求选择合适的算法

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

稻田里展望者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值