从输入数组创建位图的更快方法,而不是使用for循环和SetPixel

问题描述

我具有以下工作代码,可以根据源 pixels 数组创建Bitmap。 源数组的类型为 byte [] ,它是库函数的输出,它是 flatten 数组3D => 1D。

我创建位图的代码:

var bmp = new Bitmap(width,height,PixelFormat.Format24bppRgb);
for (int j = 0; j < height; j++) {
    for (int i = 0; i < width; i++) {
        // unflattening 1D array using 3D coordinates
        //      index = z *   yMax *  xMax + y *  xMax + x
        var rv = pixels[0 * height * width + j * width + i];
        var gv = pixels[1 * height * width + j * width + i];
        var bv = pixels[2 * height * width + j * width + i];
        bmp.SetPixel(i,j,Color.FromArgb(rv,gv,bv));
    }
}

上面的代码有效,但是。对于2048 x 1364位图,创建大约需要2秒钟。 我检查了stackoverflow的类似情况,有使用BitmapDataMarshal.Copy的解决方案,但是当源数组不是3D => 1D扁平化数组时就是这种情况。当然,我尝试使用BitmapData并将其从像素复制到BitmapData.Scan0,但是得到了错误的位图。 有什么窍门,如何加快位图的创建速度?

更新: 根据下面的评论,我最终得到了这段代码,它的运行速度更快:

var bytes = new byte[pixels.Length];
var idx = 0L;
var area = height * width;
var area2 = 2 * area;
var bmp = new Bitmap(width,PixelFormat.Format24bppRgb);
var bmd = bmp.LockBits(new Rectangle(0,bmp.Width,bmp.Height),ImageLockMode.ReadWrite,bmp.PixelFormat);
for (int j = 0; j < height; j++) {
    for (int i = 0; i < width; i++) {
        var Unflatten1D = j * width + i;
        bytes[idx]      = pixels[Unflatten1D];
        bytes[idx + 1]  = pixels[Unflatten1D + area];
        bytes[idx + 2]  = pixels[Unflatten1D + area2];
        idx += 3;
    }
}
Marshal.Copy(bytes,bmd.Scan0,bytes.Length);
bmp.UnlockBits(bmd);

解决方法

您可以使用/ unsafe标志编译应用程序(在Visual Studio中,右键单击项目,然后在属性中允许使用不安全的代码)

接下来使方法代码不安全。例如:

public unsafe void CreateImage()

然后按如下所示更改代码。

var bmp = new Bitmap(width,height,PixelFormat.Format24bppRgb);
var bitmapData = bmp.LockBits(new Rectangle(0,width,height),ImageLockMode.ReadWrite,PixelFormat.Format24bppRgb);


byte* bits = (byte*)bitmapData.Scan0;
fixed (byte* p = pixels)
{
    // Avoid having those 2 multiplications in the loop
    int wtimesh1 = height * width * 1;
    int wtimesh2 = height * width * 2;
    for (int j = 0; j < height; j++)
    {
        // Avoid multiplication in the loop
        int jtimesw = j * width;
        for (int i = 0; i < width; i++)
        {
            // unflattening 1D array using 3D coordinates
            //      index = z *   yMax *  xMax + y *  xMax + x
            int pixel = j * bitmapData.Stride + i * 3;
            // Avoid recalculation
            int jtimeswplusi = jtimesw + i;
            bits[pixel + 2] = p[jtimeswplusi];
            bits[pixel + 1] = p[wtimesh1 + jtimeswplusi];
            bits[pixel] = p[wtimesh2 + jtimeswplusi];
        }
    }

}

在我的PC上,此优化使创建时间从2.1s减少到0.05s

当然这里需要说明的是,代码是不安全的(如编译器标志所暗示的),因此必须格外小心代码的正确性,以避免崩溃,不确定的行为和/或安全性问题。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...