如何在Windows Phone 8中对图像执行边缘检测

时间:2013-09-19 02:48:00

标签: c# windows-phone-7 windows-phone-8 writeablebitmapex

我是图像处理新手,希望在我的应用程序中实现边缘检测功能。在看了几个例子之后,Sobel 3x3方法脱颖而出,成为我想尝试的方法。我引用了http://code.msdn.microsoft.com/wpapps/Image-Edge-Detection-5c5a0dc2,但Windows Phone中不存在System.Drawing。我无法为我的目的修改样本。通过直接修改argb像素数据的值,我一直在使用WriteableBitmapEx来获得一些图像效果。有没有办法为Sobel边缘检测方法做到这一点?

Sobel.cs

public string Name { get { return "Sobel"; } }

    public Sobel()
    {
    }

    /// <returns>The result of WriteabelBitmap processing.</returns>
    public WriteableBitmap Process(WriteableBitmap input)
    {
        // Prepare some variables
        var width = input.PixelWidth;
        var height = input.PixelHeight;
        return Process(input.Pixels, width, height).ToWriteableBitmap(width, height);
    }

    /// <returns>The result of the processing.</returns>
    public int[] Process(int[] inputPixels, int width, int height)
    {
        WriteableBitmap output = ExtBitmap.ConvolutionFilter(inputPixels.ToWriteableBitmap(width, height), Matrix.Sobel3x3Horizontal,
                                               Matrix.Sobel3x3Vertical,
                                                    1.0, 0, false);
        return output.Pixels;
    }

Matrix.cs

public static double[,] Sobel3x3Horizontal
    {
        get
        {
            return new double[,] 
            { { -1,  0,  1, }, 
              { -2,  0,  2, }, 
              { -1,  0,  1, }, };
        }
    }

    public static double[,] Sobel3x3Vertical
    {
        get
        {
            return new double[,] 
            { {  1,  2,  1, }, 
              {  0,  0,  0, }, 
              { -1, -2, -1, }, };
        }
    }

ExtBitmap.cs(我的代码示例中的粗略实现)

public static class ExtBitmap
{
    private static WriteableBitmap ConvolutionFilter(WriteableBitmap sourceBitmap,
                                         double[,] filterMatrix,
                                              double factor = 1,
                                                   int bias = 0,
                                         bool grayscale = false)
    {
        //BitmapData sourceData = sourceBitmap.LockBits(new Rectangle(0, 0,
        //                         sourceBitmap.PixelWidth, sourceBitmap.PixelHeight),
        //                                           ImageLockMode.ReadOnly,
        //                                     PixelFormat.Format32bppArgb);

        byte[] pixelBuffer = new byte[sourceBitmap.Pixels.Count()];
        byte[] resultBuffer = new byte[sourceBitmap.Pixels.Count()];

        //Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length);
        //sourceBitmap.UnlockBits(sourceData);

        if (grayscale == true)
        {
            float rgb = 0;

            for (int k = 0; k < pixelBuffer.Length; k += 4)
            {
                rgb = pixelBuffer[k] * 0.11f;
                rgb += pixelBuffer[k + 1] * 0.59f;
                rgb += pixelBuffer[k + 2] * 0.3f;


                pixelBuffer[k] = (byte)rgb;
                pixelBuffer[k + 1] = pixelBuffer[k];
                pixelBuffer[k + 2] = pixelBuffer[k];
                pixelBuffer[k + 3] = 255;
            }
        }

        double blue = 0.0;
        double green = 0.0;
        double red = 0.0;

        int filterWidth = filterMatrix.GetLength(1);
        int filterHeight = filterMatrix.GetLength(0);

        int filterOffset = (filterWidth - 1) / 2;
        int calcOffset = 0;

        int byteOffset = 0;

        for (int offsetY = filterOffset; offsetY <
            sourceBitmap.PixelHeight - filterOffset; offsetY++)
        {
            for (int offsetX = filterOffset; offsetX <
                sourceBitmap.PixelWidth - filterOffset; offsetX++)
            {
                blue = 0;
                green = 0;
                red = 0;

                byteOffset = offsetY *
                             sourceBitmap.PixelWidth +
                             offsetX * 4;

                for (int filterY = -filterOffset;
                    filterY <= filterOffset; filterY++)
                {
                    for (int filterX = -filterOffset;
                        filterX <= filterOffset; filterX++)
                    {

                        calcOffset = byteOffset +
                                     (filterX * 4) +
                                     (filterY * sourceBitmap.PixelWidth);

                        blue += (double)(pixelBuffer[calcOffset]) *
                                filterMatrix[filterY + filterOffset,
                                                    filterX + filterOffset];

                        green += (double)(pixelBuffer[calcOffset + 1]) *
                                 filterMatrix[filterY + filterOffset,
                                                    filterX + filterOffset];

                        red += (double)(pixelBuffer[calcOffset + 2]) *
                               filterMatrix[filterY + filterOffset,
                                                  filterX + filterOffset];
                    }
                }

                blue = factor * blue + bias;
                green = factor * green + bias;
                red = factor * red + bias;

                if (blue > 255)
                { blue = 255; }
                else if (blue < 0)
                { blue = 0; }

                if (green > 255)
                { green = 255; }
                else if (green < 0)
                { green = 0; }

                if (red > 255)
                { red = 255; }
                else if (red < 0)
                { red = 0; }

                resultBuffer[byteOffset] = (byte)(blue);
                resultBuffer[byteOffset + 1] = (byte)(green);
                resultBuffer[byteOffset + 2] = (byte)(red);
                resultBuffer[byteOffset + 3] = 255;
            }
        }

        WriteableBitmap resultBitmap = new WriteableBitmap(sourceBitmap.PixelWidth, sourceBitmap.PixelHeight);

        //BitmapData resultData = resultBitmap.LockBits(new Rectangle(0, 0,
        //                         resultBitmap.Width, resultBitmap.Height),
        //                                          ImageLockMode.WriteOnly,
        //                                     PixelFormat.Format32bppArgb);

        //Marshal.Copy(resultBuffer, 0, resultData.Scan0, resultBuffer.Length);
        //resultBitmap.UnlockBits(resultData);

        return resultBitmap;
    }

    public static WriteableBitmap ConvolutionFilter(this WriteableBitmap sourceBitmap,
                                            double[,] xFilterMatrix,
                                            double[,] yFilterMatrix,
                                                  double factor = 1,
                                                       int bias = 0,
                                             bool grayscale = false)
    {
        //BitmapData sourceData = sourceBitmap.LockBits(new Rectangle(0, 0,
        //                         sourceBitmap.Width, sourceBitmap.Height),
        //                                           ImageLockMode.ReadOnly,
        //                                      PixelFormat.Format32bppArgb);

        byte[] pixelBuffer = new byte[sourceBitmap.Pixels.Count()];
        byte[] resultBuffer = new byte[sourceBitmap.Pixels.Count()];

        //Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length);
        //sourceBitmap.UnlockBits(sourceData);

        if (grayscale == true)
        {
            float rgb = 0;

            for (int k = 0; k < pixelBuffer.Length; k += 4)
            {
                rgb = pixelBuffer[k] * 0.11f;
                rgb += pixelBuffer[k + 1] * 0.59f;
                rgb += pixelBuffer[k + 2] * 0.3f;

                pixelBuffer[k] = (byte)rgb;
                pixelBuffer[k + 1] = pixelBuffer[k];
                pixelBuffer[k + 2] = pixelBuffer[k];
                pixelBuffer[k + 3] = 255;
            }
        }

        double blueX = 0.0;
        double greenX = 0.0;
        double redX = 0.0;

        double blueY = 0.0;
        double greenY = 0.0;
        double redY = 0.0;

        double blueTotal = 0.0;
        double greenTotal = 0.0;
        double redTotal = 0.0;

        int filterOffset = 1;
        int calcOffset = 0;

        int byteOffset = 0;

        for (int offsetY = filterOffset; offsetY <
            sourceBitmap.PixelHeight - filterOffset; offsetY++)
        {
            for (int offsetX = filterOffset; offsetX <
                sourceBitmap.PixelWidth - filterOffset; offsetX++)
            {
                blueX = greenX = redX = 0;
                blueY = greenY = redY = 0;

                blueTotal = greenTotal = redTotal = 0.0;

                byteOffset = offsetY *
                             sourceBitmap.PixelWidth +
                             offsetX * 4;

                for (int filterY = -filterOffset;
                    filterY <= filterOffset; filterY++)
                {
                    for (int filterX = -filterOffset;
                        filterX <= filterOffset; filterX++)
                    {
                        calcOffset = byteOffset +
                                     (filterX * 4) +
                                     (filterY * sourceBitmap.PixelWidth);

                        blueX += (double)(pixelBuffer[calcOffset]) *
                                  xFilterMatrix[filterY + filterOffset,
                                          filterX + filterOffset];

                        greenX += (double)(pixelBuffer[calcOffset + 1]) *
                                  xFilterMatrix[filterY + filterOffset,
                                          filterX + filterOffset];

                        redX += (double)(pixelBuffer[calcOffset + 2]) *
                                  xFilterMatrix[filterY + filterOffset,
                                          filterX + filterOffset];

                        blueY += (double)(pixelBuffer[calcOffset]) *
                                  yFilterMatrix[filterY + filterOffset,
                                          filterX + filterOffset];

                        greenY += (double)(pixelBuffer[calcOffset + 1]) *
                                  yFilterMatrix[filterY + filterOffset,
                                          filterX + filterOffset];

                        redY += (double)(pixelBuffer[calcOffset + 2]) *
                                  yFilterMatrix[filterY + filterOffset,
                                          filterX + filterOffset];
                    }
                }

                blueTotal = Math.Sqrt((blueX * blueX) + (blueY * blueY));
                greenTotal = Math.Sqrt((greenX * greenX) + (greenY * greenY));
                redTotal = Math.Sqrt((redX * redX) + (redY * redY));

                if (blueTotal > 255)
                { blueTotal = 255; }
                else if (blueTotal < 0)
                { blueTotal = 0; }

                if (greenTotal > 255)
                { greenTotal = 255; }
                else if (greenTotal < 0)
                { greenTotal = 0; }

                if (redTotal > 255)
                { redTotal = 255; }
                else if (redTotal < 0)
                { redTotal = 0; }

                resultBuffer[byteOffset] = (byte)(blueTotal);
                resultBuffer[byteOffset + 1] = (byte)(greenTotal);
                resultBuffer[byteOffset + 2] = (byte)(redTotal);
                resultBuffer[byteOffset + 3] = 255;
            }
        }

        WriteableBitmap resultBitmap = new WriteableBitmap(sourceBitmap.PixelWidth, sourceBitmap.PixelHeight);

        //BitmapData resultData = resultBitmap.LockBits(new Rectangle(0, 0,
        //                         resultBitmap.Width, resultBitmap.Height),
        //                                          ImageLockMode.WriteOnly,
        //                                      PixelFormat.Format32bppArgb);

        //Marshal.Copy(resultBuffer, 0, resultData.Scan0, resultBuffer.Length);
        //resultBitmap.UnlockBits(resultData);

        return resultBitmap;
    }
}

2 个答案:

答案 0 :(得分:1)

您应该尝试使用WriteableBitmapEx及其Convolution过滤器。只需提供一个适当的卷积矩阵,你就可以了。它已经有3个,所以应该很容易适应。请在此处查看源代码文件:

https://writeablebitmapex.codeplex.com/SourceControl/latest#trunk/Source/WriteableBitmapEx/WriteableBitmapFilterExtensions.cs

答案 1 :(得分:-1)

AForge.Net框架附带了一堆过滤器,其中包括Sobel边缘检测器。它使用起来非常简单,只需实例化一个SobelEdgeDetector并在图像上调用它的Apply或ApplyInPlace方法。

http://www.aforgenet.com/framework/docs/html/2c8218cc-921c-34d8-5c88-39c652488490.htm