2012-01-22 13 views
9

Estoy escribiendo un visor de imágenes WPF, que muestra una grilla de imágenes. Estoy desconcertado por el rendimiento lento: mostrar incluso una cuadrícula de 11 x 11 hace que una máquina virtual no responda, lenta y lenta durante largos períodos de tiempo. Incluso en el poderoso host el rendimiento en no snappy.¿Cómo puedo hacer que mostrar imágenes en WPF sea más "rápido"?

El programa se basa en el diseño en SO WPF: arranging collection items in a grid: Un ItemsControl está vinculado a Items, una ObservableCollection. Cada elemento contiene un URI absoluto del sistema de archivos. DataTemplate de ItemsControl contiene un elemento de imagen cuyo origen está vinculado al URI.

Parece que el problema no puede ser el disco (SSD), la memoria (8GB VM, host de 24GB) o la CPU (i750). Además, la mayor parte del trabajo lo realiza WPF, por lo que ni siquiera puedo encontrar un problema en mi código: mi código simplemente carga los URI (es decir, las rutas a las imágenes, no a las imágenes) a la colección y vuelve rápidamente. Luego hay una espera, y WPF muestra las imágenes.

El único problema en el que podría pensar es en el procesamiento de imágenes: reducción de escala por WPF. Pero incluso en el host, que tiene una tarjeta 5850 ATI Radeon HD "suficientemente buena", el rendimiento no es rápido.

Entonces, mi pregunta es: ¿Cómo puedo hacer que mostrar imágenes en WPF sea más "ágil"?

Editar: Las imágenes son 1920x1080 HD JPEG de 22 bits capturadas desde HD m2ts de video. Intenté pre escalarlos (usando FFmpeg) a 'ega' 640x350. No fue una mejora en el rendimiento, pero las imágenes a escala reducida de FFmpeg se ven mucho peor que las de WPF.

Editar: Gracias a David Osborne el código ahora se ejecuta como x64. Aún flojo.

Editar Lo que realmente mejoró la situación es lo que Matěj Zábský denominó scalling the images: reduciendo la resolución. Para el beneficio de los lectores futuros:

  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; 
+0

¿Tiene una cuadrícula estática de imágenes "conocidas"? ¿Qué tan grandes son las imágenes? –

+0

Los futuros lectores que enfrentan este problema - vea mi respuesta aquí: http://stackoverflow.com/questions/9265725/wpf-bitmap-performance – Avi

+0

¿Está usando sombras? –

Respuesta

7

He estado en una posición similar (tuve que mostrar versiones en miniatura de imágenes grandes en tiempo real).

Si está utilizando vinculantes para mostrar las imágenes de datos, se puede probar dos cosas:

  • Hacer la unión OneWay (esto me ayudó más).
  • Intente hacer la unión async.

Lo único que se debe hacer es preescalar las imágenes, preferiblemente separarlas. Posiblemente, incluso podría preescanear imágenes que podrían usarse potencialmente en el futuro, mientras que el processor is idle; por ejemplo, si está desarrollando una aplicación similar a un mapa, puede preescalar imágenes en áreas en las que el usuario tiene más probabilidades de moverse.

+0

Gracias. Al configurar todos los enlaces en el XAML en "{Encuadernación ..., Modo = OneWay} parece haber mejorado el rendimiento del host de 8 a 6 segundos. Establecer el enlace de recolección de ItemsControl en asincrónico puede haber reducido la demora a 5 segundos. , pero todavía no estamos allí ... – Avi

+0

@avi También podría intentar jugar con DecodePixelWidth http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapimage.decodepixelwidth%28v = VS.100% 29.aspx No estoy seguro de si funciona con binding. –

+0

¿Es esto lo que quería decir con "preescala"? – Avi

1

¿Ha intentado experimentar con diferentes configuraciones de Target Platform? Es decir. x86 o AnyCPU.

+0

Gracias. Esto fue de hecho defectuoso. Ahora estoy corriendo en x64. Sin embargo, el host (es decir, i750, 24G RAM, SSD, 5850 HD) aún demora 8 segundos para avanzar a la siguiente vista de 11x11. – Avi

2

Puede intentar la virtualización para el control, ayuda considerablemente al cargar más imágenes en la vista de lista. VirtualizingStackPanel

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

Si desea utilizar Viruatalization con una envoltura de pantalla, hay un poco de CodePlex, Virtualalizing Wrappanel

Sé que es un viejo hilo, pero si alguien sigue interesado.

1

Si está ejecutando en una máquina virtual, es probable que tenga problemas con la representación de gráficos de hardware (o hardware al menos emulado). WPF hace un uso intensivo de los gráficos de hardware y, en máquinas con baja capacidad de gráficos, el rendimiento sufrirá.

Puede solucionar esto habilitando una configuración de registro que desactive la aceleración de hardware. Esto es particularmente útil en máquinas que pueden haber informado su capacidad en exceso (por experiencia, esto afecta especialmente a las VM y los conjuntos de chips de gráficos integrados).

La clave de registro que necesita es HKEY_CURRENT_USER\SOFTWARE\Microsoft\Avalon.Graphics\DisableHWAcceleration, DWORD que debe establecer en 1. Tenga en cuenta que esto afecta a todo el sistema y afectará a todas las aplicaciones de WPF; no lo configure como parte de su aplicación, sino úsela en su entorno de VM y asegúrese de volver a probar el hardware adecuado antes de liberarlo.

Lectura adicional here.

Cuestiones relacionadas