【问题标题】:Strategies for working with large amounts of image data处理大量图像数据的策略
【发布时间】:2012-02-01 21:42:53
【问题描述】:

技术栈:C#/.NET 4/WinForms

背景:

我正在从事的项目是一系列图像堆栈的可视化应用程序。具体来说,每个图像堆栈都对齐到一个网格,在任何时候显示相同的图像,并对当前视图中的图像应用处理函数。图像堆栈本身为 150-300 MB,每个图像为 512KB-1MB。一个典型的数据集将包含约 100 个图像堆栈。

问题:

为了尝试处理这么多的数据,我使用了几种技术:

  • 内存映射文件:图像堆栈在应用程序启动时从磁盘加载
  • 在 x64 下编译允许不安全代码:显然我需要 64 位地址空间来存储这种大小的文件。我正在将当前显示的图像从内存映射文件移动到通过 Marshal.Copy 使用不安全指针生成位图的方法。
  • System.Threading.Tasks:我尽可能使用并行循环进行处理
  • System.Drawing.BufferedGraphicsContext:每个图像堆栈都有一个活动图像,该图像在传递到 PictureBox 以显示给用户之前合成到 BufferedGraphicsContext。
  • 高端系统要求:四核 CPU 或更高、SSD、12GB 内存等

然而,即使使用上述所有方法,响应性仍有很多不足之处。使用 SysInternals Process Explorer,CPU 使用率很低 (

分析表明,大部分执行时间都花在了从内存映射文件中获取数据上。我假设它正在等待操作系统将请求的内存分页回活动内存?

我还能做些什么来提高性能?

注意:

  • 大多数(如果不是全部)图像堆栈将同时可见,因此剪辑到当前视口可能不会产生很大的速度。
  • 调整显示大小是一种选择,但完整的原始数据必须始终可用以进行处理,因此这似乎只是一个额外的步骤。

更新 1:

  • 对于内存,我的开发盒只有 6 GB(因此我试图加载更少的文件),但部署系统将有 24 GB。
  • 我正在研究通过英特尔性能基元和通过 CUDA 的 GPU 加速来使用 SSE 优化。
  • 我之所以尝试将所有数据加载到内存中,是因为一个重要的可视化步骤是以 15-60 Hz 的频率在图像堆栈中循环,我害怕颠簸。

【问题讨论】:

  • 只是想检查一下 - 有没有办法很多这些都可以交给显卡来担心?
  • “大量内存”对你来说是什么?

标签: c# .net memory-management image-processing parallel-processing


【解决方案1】:

首先,我认为使用不安全的代码和内存映射文件不是很有帮助。您需要从磁盘读取大约 20GB 的数据。如果您只使用流,从​​磁盘读取它比在内存中多一份副本花费的时间要长得多——您在错误的地方进行了优化。

我认为你应该从不同的角度来看待它。您正在显示一堆图像 - 价值 20GB,在一个可以显示少于 10MB 数据的显示器上。您无需读取 20GB 的数据即可显示所有图像堆栈并在处理这些图像时提供响应式 UI。您只需要从每个堆栈中加载顶部图像 - 这会快得多快得多

至于实际处理,除非你能以某种方式利用 GPU,否则我认为你不能让它比并行处理图像更快。我想这取决于您实际执行的处理。

【讨论】:

    【解决方案2】:

    您仍然可以为每个图像预先生成拇指图像,并在所有图像可用时仅将它们加载到Grid。在用户将效果/转换应用于图像的那一刻,您可以加载 only 该图像。甚至在加载only该图像的过程中,您也可以将其划分为剪切加载扇区并以异步方式加载它们。如果您查看Google Street View,它是如何在缩放后加载的,您会发现从来没有整个图像(即使是您请求的)立即加载,而是按扇区加载。 p>

    我认为另一种非常有趣的技术,Deep Zoom 可以,如果不能解决您的问题,但至少可以提供一个很好的提示。

    Another example on Deep Zoom 来自 Scott Hanselman

    祝你好运。

    【讨论】:

      【解决方案3】:

      尽管这听起来很反常,但您应该在应用程序启动时尝试触摸(即,从每个文件的开头每 4KB 的倍数读取一个字节)内存映射文件中的所有数据。由于您有足够的 RAM,问题可能不在于操作系统正在将您的图像分页,而在于它最初并未将它们分页。内存映射文件是延迟加载的,因此在您实际尝试之前操​​作系统不会访问磁盘访问内存映射文件中的数据。因此,在应用程序加载时触摸内存将导致磁盘读取发生,而不是用户查看图像堆栈的时间。

      【讨论】:

        【解决方案4】:

        减少并行处理的图像数量以增加内存局部性。 因此,您的 4 个内核应该同时处理一张图像。 这对处理器缓存有好处。

        【讨论】:

          【解决方案5】:

          根据显示器和图像的大小,您可以尝试对图像进行下采样以适应堆栈所在正方形的分辨率。然后,如果您想专注于图像的某个点,可以重新加载原图。

          如果您使用的是 WPF,您可以尝试使用 DecodePixelWidth 和 DecodePixelHeight。也许在winforms中有一个等价物

          【讨论】:

            猜你喜欢
            • 2010-09-24
            • 2011-03-23
            • 2019-04-01
            • 2018-01-31
            • 2014-03-27
            • 2013-01-31
            • 1970-01-01
            • 2022-01-20
            • 2018-10-22
            相关资源
            最近更新 更多