开发者

Faster way to fill a 160x43 byte array from colors of Bitmap class

What's the faster way to effectively fill an array of bytes where each byte represents a pixel (black or white: < 125 = black, > 125 = white) from a Bitmap class?

I used this for colored images: Better/faster way to fill a big array in C#

However now I'm looking for something different (I can even use a single color like Red to fill this, it doesn't matter is just something I should choose), because the array format changed.

Any suggestion? Actually I'm using this code, which is obviusly not the best idea

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

My idea was parallelizing everything (yea, 1 thread per line maybe? (or per column)开发者_StackOverflow中文版), it should help I think.

EDIT:

Ok, first, I need a way to have the possibility to access different bytes of the image at the same time, Brandon Moretz is suggesting maybe the correct way to access bytes with lockbits. I would like to avoid, however, unsafe code. Does Lockbits involves necessarily unsafe code?

Second, my idea of parallelization was to use Parallel.For. This method should use the ThreadPool class, which will use an amount of threads not greater than cores of your cpu, and they are pre-allocated.

This method will be called a lot of times, so I think it's not a big trouble, because the threadpool will be used a lot after first call.

Is what I'm saying correct?


Is using "unsafe" code blocks an option? You can use LockBits on a Bitmap to get it's BitmapData, then use Scan0 & Stride properties to iterate over it.

If it's 255 colors I'm assuming a byte per pixel, so so something like:

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


General approach is to divide the image into regions then process. i.e. you can use:

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

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

where you would have two halves of the image be processed by different threads. You can divide further into 4, 8, etc. pieces as you wish. A thread per line would be excess, as thread creation overhead would overwhelm the benefits by a large margin.


I found the answer by myself, working with lockbits and Marshal.ReadByte with a really nice and fast result:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜