且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Win8 Metro(C#)数字图像处理--2.48Canny边缘检测算法

更新时间:2022-09-27 14:35:57

原文:Win8 Metro(C#)数字图像处理--2.48Canny边缘检测算法



[算法说明]

Canny边缘检测算法可以分为4步:高斯滤波器平滑处理、梯度计算、非极大值抑制、双阈值边缘检

测和边缘连接。

  1,高斯滤波器平滑处理。由于图像中经常包含一些高斯噪声,因此在边缘检测前我们要先用高斯

滤波器对其进行滤波,为了方便,通常是使用一些高斯模板,这里我们使用如下的高斯滤波器模板。

Win8 Metro(C#)数字图像处理--2.48Canny边缘检测算法

        /// <summary>
        /// Canny edge detect process.
        /// </summary>
        /// <param name="src">The source image.</param>
        /// <param name="highThreshould">The high threshould value. </param>
        /// <param name="lowThreshould">The low threshould value. </param>
        /// <returns></returns>
        public static WriteableBitmap CannyedgedetectProcess(WriteableBitmap src,int highThreshould,int lowThreshould)////图像油画效果
        {
            if (src != null)
            {
                int w = src.PixelWidth;
                int h = src.PixelHeight;
                WriteableBitmap srcImage = new WriteableBitmap(w, h);
                byte[] temp = src.PixelBuffer.ToArray();
                byte[] tempMask = (byte[])temp.Clone();
                int[,] srcBytes = new int[w, h];
                for (int j = 0; j < h; j++)
                {
                    for (int i = 0; i < w; i++)
                    {
                        srcBytes[i, j] = (int)(tempMask[i * 4 + j * w * 4] * 0.114 + tempMask[i * 4 + 1 + j * w * 4] * 0.587 + tempMask[i * 4 + 2 + j * w * 4] * 0.299);
                    }
                }
                float gradientMax = 0;
                float[,] gradient = new float[w, h];
                byte[,] degree = new byte[w, h];
                GaussFilter(ref srcBytes, w, h);
                GetGradientDegree(srcBytes, ref gradient, ref degree, ref gradientMax, w, h);
                NonMaxMini(gradient, ref srcBytes, gradientMax, w, h, degree);
                TwoThreshouldJudge(highThreshould, lowThreshould, ref srcBytes, w, h);
                for (int j = 0; j < h; j++)
                {
                    for (int i = 0; i < w; i++)
                    {
                        temp[i * 4 + j * w * 4] = temp[i * 4 + 1 + j * w * 4] = temp[i * 4 + 2 + j * w * 4] = (byte)srcBytes[i, j];
                    }
                }
                Stream sTemp = srcImage.PixelBuffer.AsStream();
                sTemp.Seek(0, SeekOrigin.Begin);
                sTemp.Write(temp, 0, w * 4 * h);
                return srcImage;
            }
            else
            {
                return null;
            }
        }
        //高斯滤波
        private static void GaussFilter(ref int[,] src, int x, int y)
        {
            for (int j = 1; j < y - 1; j++)
            {
                for (int i = 1; i < x - 1; i++)
                {
                    src[i, j] = (4 * src[i, j] + src[i - 1, j - 1] + src[i + 1, j - 1] + src[i - 1, j + 1] + src[i + 1, j + 1] + 2 * src[i, j - 1] + 2 * src[i - 1, j] + 2 * src[i, j + 1] + 2 * src[i + 1, j]) / 16;
                }
            }
        }
        //梯度相位角获取
        private static void GetGradientDegree(int[,] srcBytes, ref float[,] gradient, ref byte[,] degree, ref float GradientMax, int x, int y)
        {
            gradient = new float[x, y];
            degree = new byte[x, y];
            int gx, gy;
            int temp;
            double div;
            for (int j = 1; j < y - 1; j++)
            {
                for (int i = 1; i < x - 1; i++)
                {
                    gx = srcBytes[i + 1, j - 1] + 2 * srcBytes[i + 1, j] + srcBytes[i + 1, j + 1] - srcBytes[i - 1, j - 1] - 2 * srcBytes[i - 1, j] - srcBytes[i - 1, j + 1];
                    gy = srcBytes[i - 1, j - 1] + 2 * srcBytes[i, j - 1] + srcBytes[i + 1, j - 1] - srcBytes[i - 1, j + 1] - 2 * srcBytes[i, j + 1] - srcBytes[i + 1, j + 1];
                    gradient[i, j] = (float)Math.Sqrt((double)(gx * gx + gy * gy));
                    if (GradientMax < gradient[i, j])
                    {
                        GradientMax = gradient[i, j];
                    }
                    if (gx == 0)
                    {
                        temp = (gy == 0) ? 0 : 90;
                    }
                    else
                    {
                        div = (double)gy / (double)gx;
                        if (div < 0)
                        {
                            temp = (int)(180 - Math.Atan(-div) * 180 / Math.PI);
                        }
                        else
                        {
                            temp = (int)(Math.Atan(div) * 180 / Math.PI);
                        }
                        if (temp < 22.5)
                        {
                            temp = 0;
                        }
                        else if (temp < 67.5)
                        {
                            temp = 45;
                        }
                        else if (temp < 112.5)
                        {
                            temp = 90;
                        }
                        else if (temp < 157.5)
                        {
                            temp = 135;
                        }
                        else
                            temp = 0;
                    }
                    degree[i, j] = (byte)temp;
                }
            }
        }
        //非极大值抑制
        private static void NonMaxMini(float[,] gradient, ref int[,] srcBytes, float GradientMax, int x, int y, byte[,] degree)
        {
            float leftPixel = 0, rightPixel = 0;
            for (int j = 1; j < y - 1; j++)
            {
                for (int i = 1; i < x - 1; i++)
                {
                    switch (degree[i, j])
                    {
                        case 0:
                            leftPixel = gradient[i - 1, j];
                            rightPixel = gradient[i + 1, j];
                            break;
                        case 45:
                            leftPixel = gradient[i - 1, j + 1];
                            rightPixel = gradient[i + 1, j - 1];
                            break;
                        case 90:
                            leftPixel = gradient[i, j + 1];
                            rightPixel = gradient[i, j - 1];
                            break;
                        case 135:
                            leftPixel = gradient[i + 1, j + 1];
                            rightPixel = gradient[i - 1, j - 1];
                            break;
                        default:
                            break;
                    }
                    if ((gradient[i, j] < leftPixel) || (gradient[i, j] < rightPixel))
                    {
                        srcBytes[i, j] = 0;
                    }
                    else
                    {
                        srcBytes[i, j] = (int)(255 * gradient[i, j] / GradientMax);
                    }
                }
            }
        }
        //双阈值边缘判断
        private static void TwoThreshouldJudge(int highThreshold, int lowThreshould, ref int[,] srcBytes, int x, int y)
        {
            for (int j = 1; j < y - 1; j++)
            {
                for (int i = 1; i < x - 1; i++)
                {
                    if (srcBytes[i, j] > highThreshold)
                    {
                        srcBytes[i, j] = 255;
                    }
                    else if (srcBytes[i, j] < lowThreshould)
                    {
                        srcBytes[i, j] = 0;
                    }
                    else
                    {
                        if (srcBytes[i - 1, j - 1] < highThreshold && srcBytes[i, j - 1] < highThreshold && srcBytes[i + 1, j - 1] < highThreshold && srcBytes[i - 1, j] < highThreshold
                            && srcBytes[i + 1, j] < highThreshold && srcBytes[i - 1, j + 1] < highThreshold && srcBytes[i, j + 1] < highThreshold && srcBytes[i + 1, j + 1] < highThreshold)
                        {
                            srcBytes[i, j] = 0;
                        }
                        else
                            srcBytes[i, j] = 255;
                    }
                }
            }
        }
Win8 Metro(C#)数字图像处理--2.48Canny边缘检测算法