Sobel & Convolution statement with WriteableBitmapEx

So I am using WriteableBitmapEx for an application on Windows RT. I am trying to implement edge detection on an image using the sobel operator. I have successfully applied both kernels to detect x and y on an image using .Convolute (), but now I am stuck adding both images to one. The problem is that all pixels of both images are set to 0 for transparency (hence A in ARGB). I can display both images on my own with no problem, but adding them gives me just a black image. So my questions are:

  • Why is transparency set to 0 for every pixel after convolution?
  • Why can I display an image without it being black?
  • Why is it black when I add two images?
  • Is there a better way to combine two images? Blit unfortunatley doesn't seem to support this kind of pixel addition. But ForEach is really slow ...

For callification, here's my code so far. I can display both wbmpY and wbmpX, but finalbmp is completely black.

    public int[,] sobelY = new int[3, 3] { { 1, 2, 1 }, { 0, 0, 0 }, { -1, -2, -1 } };
    public int[,] sobelX = new int[3, 3] { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } };

    public void trim(WriteableBitmap wbmp)
    {
        var graybmp = wbmp.Clone();
        graybmp.ForEach(toGrayscale);

        var wbmpY = graybmp.Clone();
        var wbmpX = graybmp.Clone();

        wbmpY = wbmpY.Convolute(sobelY, 1, 0);
        wbmpX = wbmpX.Convolute(sobelX, 1, 0);

        var finalbmp = combineSobel(wbmpX, wbmpY);           
     }

    public WriteableBitmap combineSobel(WriteableBitmap img, WriteableBitmap img2)
    {
        int height = img.PixelHeight;
        int width = img.PixelWidth;
        WriteableBitmap result = img.Clone();
        for (int x = 0; x < width; x++)
        {
            for (int y = 0; y < height; y++)
            {
                Color imgColor = img.GetPixel(x, y);
                Color img2Color = img2.GetPixel(x, y);
                Color newColor = Color.FromArgb(
                    Math.Min((byte)Math.Sqrt(Math.Pow(imgColor.A, 2) + Math.Pow(img2Color.A, 2)), (byte)255),
                    Math.Min((byte)Math.Sqrt(Math.Pow(imgColor.R, 2) + Math.Pow(img2Color.R, 2)), (byte)255),
                    Math.Min((byte)Math.Sqrt(Math.Pow(imgColor.G, 2) + Math.Pow(img2Color.G, 2)), (byte)255),
                    Math.Min((byte)Math.Sqrt(Math.Pow(imgColor.B, 2) + Math.Pow(img2Color.B, 2)), (byte)255)
                );

                result.SetPixel(x, y, newColor);
            }
        }
        return result;
    }

      

+3


source to share


3 answers


The convolution is applied to all available channels. Not only are the reds, greens, and blues processed (which you want in this case), but also the alpha channel. This results in an alpha value of zero (100% transparent). Consider the following example:

1 0 -1 255 255 255
2 0 -2 over 255 255 255
1 0 -1 255 255 255
1 * 255 0 * 255 -1 * 255 255 0 -255
2 * 255 0 * 255 -2 * 255 = 510 0 -510
1 * 255 0 * 255 -1 * 255 255 0 -255

2 * 255 + 510 + 3 * 0 - 2 * 255 - 510 = 0 for all pixels


Technically fine, it doesn't detect any borders above the alpha channel. Functionally, however, this is not what you want in this case. If this behavior is undesirable, you can skip processing the alpha channel (if the source allows you), or reset alpha to 255 after.

I am going to talk about the black image that will be shown on the screen because I have no experience with the technology. Many frameworks first reset the image to a solid color (in which case it is black). This is necessary to prevent the previous image from breaking through if you are dealing with transparent images (or parts of it). Adding a collapsed (transparent) image to that solid color will result in the same solid color. Therefore, the image will be shown in black.

Note: combSobel uses all channels, but since it was previously converted to grayscale, you can optimize the color generation.

+2


source


Is there a better way to combine two images? Blit unfortunatley doesn't seem to support this type of pixel addition. But ForEach is really slow ...

For this reason, you must use unsafe code, check this: Why is my unsafe code blocking slower than my safe code?

As speed, think about calling 16 functions (4xMath.Min, 4xMath.Pow, 4xMath.Sqrt) for each pixel. This is a huge overhead.



Pixel values โ€‹โ€‹are in the range [0.255] Math.Pow ([0.255], 2) + Mat.Pow ([0.255], 2) results in the range [0.2 * Math.Pow (255.2)] => [0.130 050] I would build a lookup table like this:

byte[] LUT4Sqrt = new byte[130051];

for (int i = 0; i < 130051; i++)
{
    LUT4Sqrt[i] = (byte)(Math.Sqrt(i));
}

      

The lookup table for Math.Pow can also be done.

+1


source


there are 2 problems in your code:

1) I tried and the collapsed method doesn't work for me - it just creates an empty image. I don't think this is your fault. When you combine 2 blank images, you end up with a blank one.

2) There is a small problem with the implementation of your combine. You can set opacity to 255 without sqrt calc as you do on r, g, b

hope this helps

0


source







All Articles