2

Using the Sobel edge detector code below I find that the output bitmap has a diagonal line of zero values superimposed over detected edges if the input bitmap has a width not divisible by 4. The red square marked in the output bitmap at co-ords (80,80) is broken up and incorrectly placed in this case. Why is this and how can I make the code work with any bitmap width?

        private Bitmap SobelEdgeDetect2(Bitmap original, byte Threshold = 128)
    {

        // https://stackoverflow.com/questions/16747257/edge-detection-with-lockbits-c-sharp

        int width = original.Width;
        int height = original.Height;

        int BitsPerPixel = Image.GetPixelFormatSize(original.PixelFormat);
        int OneColorBits = BitsPerPixel / 8;

        BitmapData bmpData = original.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, original.PixelFormat);
        int position;
        int[,] gx = new int[,] { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } };
        int[,] gy = new int[,] { { 1, 2, 1 }, { 0, 0, 0 }, { -1, -2, -1 } };

        Bitmap dstBmp = new Bitmap(width, height, original.PixelFormat);
        BitmapData dstData = dstBmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, dstBmp.PixelFormat);

        int byteCount = dstData.Stride * dstBmp.Height;          
        byte[] input = new byte[byteCount];
        byte[] processed = new byte[byteCount];
        IntPtr ptr = bmpData.Scan0;
        IntPtr dst = dstData.Scan0;
        Marshal.Copy(ptr, input, 0, input.Length);
        Marshal.Copy(dst,processed, 0, input.Length);

        int BlackPoints = 0;
        int WhitePoints = 0;

        for (int i = 1; i < height - 1; i++) // y
        {
            for (int j = 1; j < width - 1; j++)  // x 
                 {
                int NewX = 0, NewY = 0;

                for (int ii = 0; ii < 3; ii++)
                {
                    for (int jj = 0; jj < 3; jj++)
                    {
                        int I = i + ii - 1;
                        int J = j + jj - 1;

                            byte Current = input[(I * (width) + J) * OneColorBits];
                            NewX += gx[ii, jj] * Current;
                            NewY += gy[ii, jj] * Current;                            
                    }
                }
                position = (i * (width) + j) * OneColorBits;

                if (NewX * NewX + NewY * NewY > Threshold * Threshold)
                {
                    processed[position] = 255;
                    processed[position + 1] = 255;
                    processed[position + 2] = 255;
                    WhitePoints++;
                }
                else
                {
                    processed[position] = 0;
                    processed[position + 1] = 0;
                    processed[position + 2] = 0;
                    BlackPoints++;
                }

                if (j >= 78 && j <= 82 && i >= 78 && i <= 82)
                {
                    processed[position] = 0;
                    processed[position + 1] = 0;
                    processed[position + 2] = 255;
                }

            }

        }

        Marshal.Copy(processed, 0, dst, input.Length);
        dstBmp.UnlockBits(dstData);

        return dstBmp;
    }
SimonKravis
  • 553
  • 1
  • 3
  • 24

1 Answers1

0

For a 201 pixel wide bitmap, dstData.Stride was 604. For a 200 pixel wide bitmap dstData.Stride was 612, which explains why width had to be divisible by 4 for my code.

Replacing

position = (i * (width) + j) * OneColorBits;

by

position = i * dstData.Stride + j * OneColorBits;

and

byte Current = input[(I * (width) + J) * OneColorBits];

by

byte Current = input[I * dstData.Stride + J * OneColorBits];

fixed the problem.

SimonKravis
  • 553
  • 1
  • 3
  • 24