问题描述
我具有以下工作代码,可以根据源 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的类似情况,有使用BitmapData和Marshal.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
当然这里需要说明的是,代码是不安全的(如编译器标志所暗示的),因此必须格外小心代码的正确性,以避免崩溃,不确定的行为和/或安全性问题。