从Bitmap类的颜色填充160x43字节数组的更快方法

时间:2011-09-27 19:42:04

标签: c# parallel-processing

有效填充字节数组的更快方法是什么?每个字节代表一个Bitmap类的像素(黑色或白色:<125 =黑色,> 125 =白色)?

我用它来制作彩色图像:Better/faster way to fill a big array in C#

然而现在我正在寻找不同的东西(我甚至可以使用像Red这样的单一颜色来填充它,这无关紧要只是我应该选择的东西),因为数组格式发生了变化。

有什么建议吗?实际上我正在使用这个代码,这显然不是最好的主意

        for (int x = 0; x < LgLcd.NativeConstants.LGLCD_BMP_WIDTH; ++x)
        {
            for (int y = 0; y < LgLcd.NativeConstants.LGLCD_BMP_HEIGHT; ++y)
            {
                tmp = bmp.GetPixel(x, y);
                array[y * LgLcd.NativeConstants.LGLCD_BMP_WIDTH + x] = (byte)((tmp.R == 255 && tmp.G == 255 && tmp.B == 255) ? 0 : 255);
                //array[y * x] = (byte)0;
            }
        }

我的想法是将所有内容并行化(是的,每行可能有1个帖子?(或每列)),这应该对我有所帮助。

修改

好的,首先,我需要一种方法可以同时访问图像的不同字节,Brandon Moretz建议使用lockbits访问字节的正确方法。但是,我想避免使用不安全的代码。 Lockbits是否涉及不安全的代码?

其次,我对并行化的想法是使用Parallel.For。这个方法应该使用ThreadPool类,它将使用不大于你的cpu核心的线程数量,并且它们是预先分配的。

这种方法会被调用很多次,所以我认为这不是一个大麻烦,因为线程池在第一次调用后会被大量使用。

我说的是对的吗?

3 个答案:

答案 0 :(得分:3)

使用“不安全”代码阻止选项吗?您可以在位图上使用LockBits来获取BitmapData,然后使用Scan0&amp;跨越属性以迭代它。

如果它是255种颜色,我假设每个像素有一个字节,所以就像这样:

*( ( ( byte* )bmpData.Scan0 ) + ( y * bmpData.Stride ) + x ) = (byte)((tmp.R == 255 && tmp.G == 255 && tmp.B == 255) ? 0 : 255);

答案 1 :(得分:1)

一般方法是将图像划分为区域然后处理。即你可以使用:

线程1)for (int x = 0; x < LGLCD_BMP_WIDTH /2; ++x) { ... }

线程2)for (int x = LGLCD_BMP_WIDTH / 2; x < LGLCD_BMP_WIDTH; ++x) { ... }

您将有两半图像由不同的线程处理。您可以根据需要进一步划分为4,8等。每行的一个线程将是多余的,因为线程创建开销将大大超过好处。

答案 2 :(得分:1)

我自己找到了答案,使用了lockbits和Marshal.ReadByte并获得了非常好的快速结果:

    public void SetPixels(Bitmap image)
    {
        byte[] array = Pixels;
        var data = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
        Parallel.For(0, data.Height, new Action<int>(i =>
        {
            byte tmp;
            int pixel4bpp, pixelPerbpp;
            pixelPerbpp = data.Stride / data.Width;
            for (pixel4bpp = 0; pixel4bpp < data.Stride; pixel4bpp += pixelPerbpp)
            {
                tmp = (byte)((
   Marshal.ReadByte(data.Scan0, 0 + (data.Stride * i) + pixel4bpp)
 + Marshal.ReadByte(data.Scan0, 1 + (data.Stride * i) + pixel4bpp)
 + Marshal.ReadByte(data.Scan0, 2 + (data.Stride * i) + pixel4bpp)
 + Marshal.ReadByte(data.Scan0, 3 + (data.Stride * i) + pixel4bpp)
 ) / pixelPerbpp);

                array[i * data.Width + (pixel4bpp / pixelPerbpp)] = tmp;
            }
        }));
        image.UnlockBits(data);
    }