1

这是一个获取透明和白色图像并尝试将其转换为布尔数组的函数。

我的单元测试代码给了我 2 张我期望的图像(见下文),但“numberOfMasked”总是高于我的预期。例如,如果“maskBuffer”标记了一个像素(参见下面的 mask_image_test.bmp),那么尽管“mask_bool_test70.bmp”)创建了一个标记了一个像素的图像。由于某种原因,标记为 true 的实际布尔值要高得多,而且看起来是随机的。我看到它的范围是 25 - > 70。

public static bool[] ConvertImageToBoolAray(Bitmap maskbuffer)
    {
        bool[] mask = null;
        int w = maskbuffer.Width;
        int h = maskbuffer.Height;

        #region unit_test
            maskbuffer.Save("mask_image_test.bmp");
        #endregion

        lock (maskbuffer)
        {
            BitmapData bmpData = maskbuffer.LockBits(new Rectangle(0, 0, w, h),
                ImageLockMode.ReadOnly,
                PixelFormat.Format8bppIndexed);

            const int numBmpChannel = 1;
            int maskIndex = 0;
            int bmpIndex = 0;

            unsafe
            {

                byte* pixels = (byte*) bmpData.Scan0;
                int numPixels = w*h;

                mask = new bool[numPixels];

                for (;
                    maskIndex < numPixels;
                    bmpIndex += numBmpChannel, maskIndex++)
                {
                    byte red = pixels[bmpIndex];
                    bool masked = red != 0;
                    mask[maskIndex] = masked;
                }

            }
            maskbuffer.UnlockBits(bmpData);
        }

        #region unit_test
            byte[] boolAsByte = Array.ConvertAll(mask, b => b ? (byte)1 : (byte)0);
            Bitmap maskBitmap = GLImageConvertor.ConvertByteBufferToBitmap(boolAsByte, w, h, PixelFormat.Format8bppIndexed);
            int numberOfMasked = mask.Count(b => b);
            maskBitmap.Save("mask_bool_test" + numberOfMasked + ".bmp");
        #endregion


        return mask;
    }

有人对这种奇怪的行为有任何想法吗?

调试表明,在“像素”内存中,有一些我没想到的字节,我希望看到一个字节设置为“FF”,但我有随机的数据部分。

mask_image_test.bmp:

mask_image_test.bmp

mask_bool_test70.bmp:

mask_bool_test70.bmp

4

2 回答 2

1

您需要在算法中考虑StrideWidth之间的差异。

步幅是单行像素(扫描线)的宽度,四舍五入到四字节边界。

由于 70 不能被 4 整除,因此有一些备用像素,可能填充了随机数据。

你需要类似的东西

int count = 0;
int stride = bmpData.Stride;

for (int column = 0; column < bmpData.Height; column++)
{
    for (int row = 0; row < bmpData.Width; row++)
    {
        red = pixels[(column * stride) + (row * 3) + 2]);
    }
}
于 2015-09-08T13:26:05.497 回答
1

正如托马斯指出的那样,我没有考虑步幅!没想到 C# 会打包位图中的额外字节。但在这种情况下,宽度!= 步幅(宽度为 111,但步幅为 112)确实足够了。我决定编写一个更简单的版本,完全避免使用原始缓冲区以避免粘性问题(并且我不再为原始缓冲区所困扰)

 public static bool[] ConvertImageToBoolAray(Bitmap maskbuffer)
    {
        bool[] mask = null;
        int w = maskbuffer.Width;
        int h = maskbuffer.Height;

        #region unit_test
        //maskbuffer.Save("mask_image_test.bmp");
        #endregion

        lock (maskbuffer)
        {
            int numPixels = w * h;
            mask = new bool[numPixels];

            for (int y = 0; y < maskbuffer.Height; ++y)
            {
                for (int x = 0; x < maskbuffer.Width; ++x)
                {
                    Color color = maskbuffer.GetPixel(x, y);
                    int index = x + (y*maskbuffer.Width);
                    mask[index] = color.A != 0;
                }
            }
        }

        #region unit_test
        //byte[] boolAsByte = Array.ConvertAll(mask, b => b ? (byte)1 : (byte)0);
       // Bitmap maskBitmap = GLImageConvertor.ConvertByteBufferToBitmap(boolAsByte, w, h, PixelFormat.Format8bppIndexed);
       // int numberOfMasked = mask.Count(b => b);
       // maskBitmap.Save("mask_bool_test" + numberOfMasked + ".bmp");
        #endregion


        return mask;
    }

如果有人想发布正确的原始缓冲区版本,请继续,我会将您的标记为最佳答案。

--- 更新 --- 添加了重新设计的版本以直接使用缓冲区

   private static bool[] ConvertImageToBoolArayUnsafe(Bitmap maskbuffer)
    {
        bool[] mask = null;
        int w = maskbuffer.Width;
        int h = maskbuffer.Height;

        #region unit_test
            //maskbuffer.Save("mask_image_test.bmp");
        #endregion

        lock (maskbuffer)
        {
            BitmapData bmpData = maskbuffer.LockBits(new Rectangle(0, 0, w, h),
                ImageLockMode.ReadOnly,
                PixelFormat.Format8bppIndexed);


            int stride = bmpData.Stride;
            unsafe
            {

                byte* pixels = (byte*) bmpData.Scan0;


                mask = new bool[w * h];

                for (int y = 0; y < h; ++y)
                {
                    for (int x = 0; x < w; ++x)
                    {
                        int imageIndex = x + (y * stride);
                        byte color = pixels[imageIndex];
                        int maskIndex = x + (y * w);
                        mask[maskIndex] = color != 0;
                    }
                }

            }
            maskbuffer.UnlockBits(bmpData);
        }

        #region unit_test
           // byte[] boolAsByte = Array.ConvertAll(mask, b => b ? (byte)1 : (byte)0);
          //  Bitmap maskBitmap = GLImageConvertor.ConvertByteBufferToBitmap(boolAsByte, w, h, PixelFormat.Format8bppIndexed);
          //  int numberOfMasked = mask.Count(b => b);
          //  maskBitmap.Save("mask_bool_test" + numberOfMasked + ".bmp");
        //check equality to safe version (as that is correct)
        #endregion


        return mask;
    }
于 2015-09-08T13:33:31.990 回答