首页 > 解决方案 > 当位图宽度不能被 4 整除时,为什么这个边缘检测器不能正常工作?

问题描述

使用下面的 Sobel 边缘检测器代码,如果输入位图的宽度不能被 4 整除,我发现输出位图有一条零值对角线叠加在检测到的边缘上。输出位图中在坐标处标记的红色方块(80 ,80) 在这种情况下被分解并错误放置。为什么会这样?如何使代码适用于任何位图宽度?

        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;
    }

标签: c#image-processingedge-detection

解决方案


对于 201 像素宽的位图,dstData.Stride 是 604。对于 200 像素宽的位图,dstData.Stride 是 612,这就解释了为什么我的代码宽度必须能被 4 整除。

更换

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

经过

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

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

经过

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

解决了这个问题。


推荐阅读