使用 C# 位图更有效地将图像保存到磁盘
Saving image to disk with C# bitmap more efficiently
我正在使用 C# 程序每秒保存大约 10 个大小为 660x330 的屏幕截图。
此 C# 程序用作 GTA V 游戏的 .dll 脚本。
Bitmap catchBmp = new Bitmap(300, 660, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
Graphics g = Graphics.FromImage(catchBmp);
g.CopyFromScreen(new Point(Screen.AllScreens[0].Bounds.Width / 3 + 170, Screen.AllScreens[0].Bounds.Height / 6 + 60), new Point(0, 0), new Size(300, 660));
string tmp = Path.Combine(path, modNum.ToString(), location);
if (!Directory.Exists(tmp))
{
Directory.CreateDirectory(tmp);
}
string tmp_filename = tmp + "\" + location + "_" + weather + "_" + time + "_" + anim + "_" + view_angle + "_" + modNum + "_" + picNum.ToString() + ".jpg";
catchBmp.Save(tmp_filename);
UI.ShowSubtitle(tmp_filename);
Wait(100);
catchBmp.Dispose();
g.Dispose();
上面的代码是运行一个循环,运行每秒大约循环10次。
在脚本 运行s 大约 6 小时后,我的硬盘驱动器似乎达到了最大使用率并且脚本崩溃了。
有什么办法可以避免这种情况吗?我想一次 运行 这个脚本好几天。
使用线程保存图像会有帮助吗?或者在将队列保存到磁盘的同时实现队列?
这似乎是一个简单的磁盘跟不上的问题。
编辑:正如Nyerguds在评论中指出的那样,保存时需要指定图片格式,即catchBmp.Save(tmp_filename, ImageFormat.Jpeg);
否则将使用png压缩,这将需要更多的磁盘带宽。
一种选择是使用更高效的存储格式,即保存为可以利用帧之间的差异进行更好压缩的视频文件。参见示例 video-writing in aforge。虽然这会减少写入数据的大小,但会增加系统的 CPU 负载。
另一种选择是降低图像文件的质量,方法是降低分辨率,或者 adjusting the compression parameters. You could also switch image formats. Jpeg is an old standard, and tend to produce low quality images at low bitrates, a more modern format like jpeg xr 可能效果更好。
第三种选择是简单地获得更快的磁盘,and/or确保程序对磁盘具有独占访问权。
使用队列或线程可能不会有太大帮助,因为代码不会阻塞任何其他东西,而且它只会尽可能快地运行。但是我建议在位图之前处理图形,并在处理之后移动等待。
我正在使用 C# 程序每秒保存大约 10 个大小为 660x330 的屏幕截图。
此 C# 程序用作 GTA V 游戏的 .dll 脚本。
Bitmap catchBmp = new Bitmap(300, 660, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
Graphics g = Graphics.FromImage(catchBmp);
g.CopyFromScreen(new Point(Screen.AllScreens[0].Bounds.Width / 3 + 170, Screen.AllScreens[0].Bounds.Height / 6 + 60), new Point(0, 0), new Size(300, 660));
string tmp = Path.Combine(path, modNum.ToString(), location);
if (!Directory.Exists(tmp))
{
Directory.CreateDirectory(tmp);
}
string tmp_filename = tmp + "\" + location + "_" + weather + "_" + time + "_" + anim + "_" + view_angle + "_" + modNum + "_" + picNum.ToString() + ".jpg";
catchBmp.Save(tmp_filename);
UI.ShowSubtitle(tmp_filename);
Wait(100);
catchBmp.Dispose();
g.Dispose();
上面的代码是运行一个循环,运行每秒大约循环10次。
在脚本 运行s 大约 6 小时后,我的硬盘驱动器似乎达到了最大使用率并且脚本崩溃了。
有什么办法可以避免这种情况吗?我想一次 运行 这个脚本好几天。
使用线程保存图像会有帮助吗?或者在将队列保存到磁盘的同时实现队列?
这似乎是一个简单的磁盘跟不上的问题。
编辑:正如Nyerguds在评论中指出的那样,保存时需要指定图片格式,即catchBmp.Save(tmp_filename, ImageFormat.Jpeg);
否则将使用png压缩,这将需要更多的磁盘带宽。
一种选择是使用更高效的存储格式,即保存为可以利用帧之间的差异进行更好压缩的视频文件。参见示例 video-writing in aforge。虽然这会减少写入数据的大小,但会增加系统的 CPU 负载。
另一种选择是降低图像文件的质量,方法是降低分辨率,或者 adjusting the compression parameters. You could also switch image formats. Jpeg is an old standard, and tend to produce low quality images at low bitrates, a more modern format like jpeg xr 可能效果更好。
第三种选择是简单地获得更快的磁盘,and/or确保程序对磁盘具有独占访问权。
使用队列或线程可能不会有太大帮助,因为代码不会阻塞任何其他东西,而且它只会尽可能快地运行。但是我建议在位图之前处理图形,并在处理之后移动等待。