有没有一种在 C# 中处理高分辨率照片的有效方法?
Is there an efficient way of handling high-res photos in C#?
我做了一个程序来分析图像的第一个像素,然后在列表中记录它的值,这是为了检查图像是黑白的还是彩色的。现在,有谁知道阅读高分辨率图像的有效方法吗?现在我正在使用位图,但它们效率很低。这些图像每张大约 18 兆像素,我想分析大约 400 张照片。代码如下:
Bitmap b;
foreach (FileInfo f in files) {
// HUGE MEMORY LEAK
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
b = (Bitmap)Bitmap.FromFile(f.FullName);
// reading pixel (0,0) from bitmap
当我 运行 我的程序说:
"An unhandled exception of type 'System.OutOfMemoryException' occurred in System.Drawing.dll
Additional information: There is no available memory."
我已经尝试使用 System.GC.Collect() 进行清理,如您所见,但异常并没有消失。如果我分析一个只包含几张照片的文件夹,程序 运行 没问题,并且很乐意完成它的工作。
我想,如果您只需要第一个像素 - 没有必要读取所有文件。也许您应该只从位图字节数组中取出第一个像素并使用它。您应该手动找到像素阵列并先取。
如何找到像素阵列?好吧,这取决于文件格式。您应该找到每种可用格式的规范并使用它。这是 BMP reader
的示例
使用图像的第一个像素来检查它是否是颜色是错误的方法。
如果你有一张黑色背景的图片(RGB 中的像素值为 0,0,0),你怎么知道图片是黑白的,而不是黑色背景的彩色?
将位图放在 Using 中是正确的,因为它会正确处理。
以下内容可以解决问题。
class Program
{
static void Main(string[] args) {
List<String> ImageExtensions = new List<string> { ".JPG", ".JPE", ".BMP", ".GIF", ".PNG" };
String rootDir = "C:\Images";
foreach (String fileName in Directory.EnumerateFiles(rootDir)) {
if (ImageExtensions.Contains(Path.GetExtension(fileName).ToUpper())) {
try {
//Image.FromFile will work just as well here.
using (Image i = Bitmap.FromFile(fileName)) {
if (i.PixelFormat == PixelFormat.Format16bppGrayScale) {
//Grey scale...
} else if (i.PixelFormat == PixelFormat.Format1bppIndexed) {
//1bit colour (possibly b/w, but could be other indexed colours)
}
}
} catch (Exception e) {
Console.WriteLine("Error - " + e.Message);
}
}
}
}
}
可在此处找到 PixelFormat 的参考 - https://msdn.microsoft.com/en-us/library/system.drawing.imaging.pixelformat%28v=vs.110%29.aspx
C# 中的对象限制为 2Gb,因此我怀疑是单个图像导致了问题。
我还建议您永远不要手动调用 GC 来解决内存泄漏(尽管从技术上讲这不是泄漏,只是大量内存使用)。
Using 语句非常适合确保将对象标记为待处理,并且 GC 非常擅长清理。
我们在我们的软件中执行密集的图像处理,使用我展示的方法从未遇到过内存问题。
虽然简单地读取文件头来查找图像数据是一个完全正确的解决方案,但它确实意味着要解码不同的文件类型需要做很多额外的工作,除非您正在处理非常小的大量图像,否则这是没有必要的记忆(虽然如果这是你的目标,直接 C 是比 C# 更好的方法。课程和所有爵士乐的马匹!)
编辑 - 我只是 运行 这个目录包含超过 5000 个没有内存问题的高分辨率 TIFF。该过程中最慢的部分是控制台输出!
我做了一个程序来分析图像的第一个像素,然后在列表中记录它的值,这是为了检查图像是黑白的还是彩色的。现在,有谁知道阅读高分辨率图像的有效方法吗?现在我正在使用位图,但它们效率很低。这些图像每张大约 18 兆像素,我想分析大约 400 张照片。代码如下:
Bitmap b;
foreach (FileInfo f in files) {
// HUGE MEMORY LEAK
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
b = (Bitmap)Bitmap.FromFile(f.FullName);
// reading pixel (0,0) from bitmap
当我 运行 我的程序说:
"An unhandled exception of type 'System.OutOfMemoryException' occurred in System.Drawing.dll
Additional information: There is no available memory."
我已经尝试使用 System.GC.Collect() 进行清理,如您所见,但异常并没有消失。如果我分析一个只包含几张照片的文件夹,程序 运行 没问题,并且很乐意完成它的工作。
我想,如果您只需要第一个像素 - 没有必要读取所有文件。也许您应该只从位图字节数组中取出第一个像素并使用它。您应该手动找到像素阵列并先取。
如何找到像素阵列?好吧,这取决于文件格式。您应该找到每种可用格式的规范并使用它。这是 BMP reader
的示例使用图像的第一个像素来检查它是否是颜色是错误的方法。
如果你有一张黑色背景的图片(RGB 中的像素值为 0,0,0),你怎么知道图片是黑白的,而不是黑色背景的彩色?
将位图放在 Using 中是正确的,因为它会正确处理。
以下内容可以解决问题。
class Program
{
static void Main(string[] args) {
List<String> ImageExtensions = new List<string> { ".JPG", ".JPE", ".BMP", ".GIF", ".PNG" };
String rootDir = "C:\Images";
foreach (String fileName in Directory.EnumerateFiles(rootDir)) {
if (ImageExtensions.Contains(Path.GetExtension(fileName).ToUpper())) {
try {
//Image.FromFile will work just as well here.
using (Image i = Bitmap.FromFile(fileName)) {
if (i.PixelFormat == PixelFormat.Format16bppGrayScale) {
//Grey scale...
} else if (i.PixelFormat == PixelFormat.Format1bppIndexed) {
//1bit colour (possibly b/w, but could be other indexed colours)
}
}
} catch (Exception e) {
Console.WriteLine("Error - " + e.Message);
}
}
}
}
}
可在此处找到 PixelFormat 的参考 - https://msdn.microsoft.com/en-us/library/system.drawing.imaging.pixelformat%28v=vs.110%29.aspx
C# 中的对象限制为 2Gb,因此我怀疑是单个图像导致了问题。 我还建议您永远不要手动调用 GC 来解决内存泄漏(尽管从技术上讲这不是泄漏,只是大量内存使用)。
Using 语句非常适合确保将对象标记为待处理,并且 GC 非常擅长清理。
我们在我们的软件中执行密集的图像处理,使用我展示的方法从未遇到过内存问题。
虽然简单地读取文件头来查找图像数据是一个完全正确的解决方案,但它确实意味着要解码不同的文件类型需要做很多额外的工作,除非您正在处理非常小的大量图像,否则这是没有必要的记忆(虽然如果这是你的目标,直接 C 是比 C# 更好的方法。课程和所有爵士乐的马匹!)
编辑 - 我只是 运行 这个目录包含超过 5000 个没有内存问题的高分辨率 TIFF。该过程中最慢的部分是控制台输出!