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

发布于 2024-12-06 16:50:34 字数 1133 浏览 1 评论 0原文

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

我将其用于彩色图像: 更好/更快的方法在 C# 中填充一个大数组

但是现在我正在寻找不同的东西(我什至可以使用像红色这样的单一颜色来填充它,这并不重要,只是我应该选择的东西),因为数组格式改变了。

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

        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个线程也许?(或每列)),它应该对我有帮助。

编辑:

好吧,首先,我需要一种能够同时访问图像的不同字节的方法,布兰登·莫瑞兹建议也许是使用锁定位访问字节的正确方法。然而,我想避免不安全的代码。 Lockbits 是否必然涉及不安全代码?

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

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

我说的对吗?

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)), 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

指尖上的星空 2024-12-13 16:50:34

使用“不安全”代码块是一种选择吗?您可以在位图上使用 LockBits 来获取其 BitmapData,然后使用 Scan0 &跨过属性来迭代它。

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

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

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);
随心而道 2024-12-13 16:50:34

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

线程 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 份等。每行一个线程将是多余的,因为线程创建开销将大大抵消其好处。

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.

杀お生予夺 2024-12-13 16:50:34

我自己找到了答案,使用 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);
    }

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);
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文