【问题标题】:How can I make displaying images on WPF more “snappy”?如何使 WPF 上的图像显示更“活泼”?
【发布时间】:2012-02-16 02:56:09
【问题描述】:

我正在编写一个 WPF 图像查看器,显示图像网格。由于性能缓慢,我感到困惑:即使显示 11 x 11 网格也会使 VM 长时间无响应、缓慢且缓慢。即使在强大的主机上也表现得非常出色。

该程序基于 SO WPF: arranging collection items in a grid 中的设计:一个 ItemsControl 绑定到 Items,一个 ObservableCollection。每个 Item 包含一个文件系统绝对 URI。 ItemsControl 的 DataTemplate 包含一个 Image 元素,其 Source 绑定到 URI。

似乎问题不在于磁盘 (SSD)、内存(8GB VM、24GB 主机)或 CPU (i750)。此外,大部分工作都是由 WPF 完成的,所以我什至无法在我的代码中找到问题:我的代码只是将 URI(即图像的路径,而不是图像)加载到集合中并快速返回。然后等待,WPF 显示图像。

我能想到的唯一问题是图像处理——通过 WPF 缩小比例。但即使在拥有“足够好”的 5850 ATI Radeon HD 卡的主机上,性能也不是很出色。

所以,我的问题是:如何让 WPF 上的图像显示更加“快捷”?

编辑:图像是从高清 m2ts 视频中捕获的 1920x1080 22 位高清 JPEG。我尝试将它们(使用 FFmpeg)预缩放为 'ega' 640x350。 性能改进,但 FFmpeg 的按比例缩小的图像看起来比 WPF 的差很多。

编辑:感谢 David Osborne,代码现在以 x64 格式运行。还是很慢。

编辑 真正改善这种情况的是 Matěj Zábský 所说的缩放图像:降低分辨率。为了未来读者的利益:

            fullPath = new Uri(path, UriKind.Absolute);


            BitmapImage smallerBitmapImage = new BitmapImage();
            smallerBitmapImage.BeginInit();
            smallerBitmapImage.DecodePixelWidth = (int) (theWidthOfTheGrid / theNumberOfColumns);
            smallerBitmapImage.UriSource = fullPath;
            smallerBitmapImage.EndInit();

            FormatConvertedBitmap formatConvertedBitmap = new FormatConvertedBitmap();
            formatConvertedBitmap.BeginInit();
            formatConvertedBitmap.Source = smallerBitmapImage;
            formatConvertedBitmap.DestinationFormat = PixelFormats.Gray16;
            formatConvertedBitmap.EndInit();
            formatConvertedBitmap.Freeze();

            this.ImageSource = formatConvertedBitmap;

【问题讨论】:

标签: wpf performance image


【解决方案1】:

我一直处于类似的位置(我必须实时显示大图像的缩略图版本)。

如果您使用数据绑定来显示图像,您可以尝试两种方法:

  • 绑定OneWay(这对我帮助最大)。
  • 尝试绑定async

唯一的另一件事是预缩放图像 - 最好是单独的线程。您甚至可以在processor is idle 中对可能在未来使用的图像进行预缩放 - 例如,如果您正在开发类似地图的应用程序,您可以在用户最有可能移动的区域中预缩放图像。

【讨论】:

  • 谢谢。将 XAML 中的所有绑定设置为“{Binding ..., Mode=OneWay} 似乎已将主机性能从 8 秒提高到 6 秒。将 ItemsControl 集合绑定设置为异步可能已将延迟减少到 5 秒。太好了,但我们还没有到那里......
  • @avi 您也可以尝试使用 DecodePixelWidth msdn.microsoft.com/en-us/library/… 虽然我不确定它是否适用于绑定。
  • 这就是你所说的“prescale”吗?
  • @avi 不是。我的意思是代码中的某处会有一个例程,它将在单独的线程中运行(甚至可能同时在多个线程中),然后只有缩小的图像会被输入 WPF。当然,WPF 中的多线程并不完全是微不足道的(尽管 IIRC 绑定可以处理它 - 我认为您可以绑定到另一个线程拥有的对象)。
  • @Matej 但是,bacgrkound 任务会使用什么来缩小图像(如果不是 DecodePixelWidth)?
【解决方案2】:

您可以尝试虚拟化进行控制,它在列表视图中加载更多图像时有很大帮助。 VirtualizingStackPanel

<ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel Orientation="Vertical" VirtualizingStackPanel.IsVirtualizing="True"  VirtualizingStackPanel.VirtualizationMode="Recycling"/>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>

如果想使用带有 wrap-panel 的虚拟化,有一些来自 Codeplex,Virtualalizing Wrappanel

我知道这是一个旧线程,但如果有人仍然感兴趣。

【讨论】:

    【解决方案3】:

    您是否尝试过使用不同的目标平台设置? IE。 x86 或 AnyCPU。

    【讨论】:

    • 谢谢。这确实是错误的。现在我在 x64 中运行。但是,主机(即 i750、24G RAM、SSD、5850 HD)仍然需要 8 秒才能前进到下一个 11x11 视图。
    【解决方案4】:

    如果您在虚拟机上运行,​​您可能会遇到硬件(或至少是仿真硬件)图形渲染问题。 WPF 大量使用硬件图形,在图形能力较低的机器上,性能会受到影响。

    您可以通过启用强制关闭硬件加速的注册表设置来解决此问题。这在可能过度报告其功能的机器上特别有用(根据经验,这尤其会影响 VM 和嵌入式图形芯片组)。

    您需要的注册表项是HKEY_CURRENT_USER\SOFTWARE\Microsoft\Avalon.Graphics\DisableHWAcceleration,一个DWORD,您应该设置为1。请注意,这是系统范围的,将影响所有 WPF 应用程序 - 不要将其设置为应用程序的一部分,而是在 VM 环境中使用它,并确保在发布之前在适当的硬件上再次测试。

    延伸阅读here.

    【讨论】:

      猜你喜欢
      • 2012-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-08
      • 1970-01-01
      • 2016-10-14
      相关资源
      最近更新 更多