En las aplicaciones para trabajar con imágenes, la tarea de cambiar el tamaño de los jeeps (imágenes comprimidas usando el algoritmo JPEG) es bastante común. En este caso, no puede cambiar el tamaño inmediatamente y primero debe decodificar los datos originales. No hay nada complicado y nuevo en esto, pero si necesita hacerlo muchos millones de veces al día, entonces es especialmente importante optimizar el rendimiento de dicha solución, que debería ser muy rápida.

Este problema a menudo se encuentra al organizar el alojamiento remoto para un repositorio de imágenes, ya que la mayoría de las cámaras y teléfonos disparan en formato JPEG. Todos los días, los archivos de fotos de los principales servicios web (redes sociales, foros, alojamiento de fotos y muchos otros) se reponen con un número significativo de tales imágenes, por lo que la cuestión de cómo almacenar esas imágenes es extremadamente importante. Para reducir el tamaño del tráfico saliente y mejorar el tiempo de respuesta a la solicitud de un usuario, muchos servicios web almacenan docenas de archivos para una sola imagen en diferentes resoluciones. La velocidad de respuesta es buena, pero estas copias ocupan mucho espacio. Este es un problema importante, aunque hay otras desventajas en este enfoque.
La idea de resolver este problema no es almacenar en el servidor muchas opciones para la imagen original en diferentes resoluciones, sino crear dinámicamente la imagen deseada con las dimensiones dadas del original previamente preparado, y lo más rápido posible. Por lo tanto, en tiempo real, puede crear una imagen de la resolución deseada e inmediatamente enviarla al usuario. Es muy importante que la resolución de esta imagen se pueda hacer inmediatamente para que el dispositivo del usuario no cambie el tamaño de la pantalla, ya que simplemente no será necesario.
El uso de formatos distintos de JPEG como base para organizar dicho repositorio de imágenes no parece justificado. Por supuesto, existen formatos estándar y ampliamente utilizados que ofrecen una mejor compresión con la misma calidad (JPEG2000, WebP), pero la velocidad de codificación y decodificación de tales imágenes es muy baja en comparación con JPEG, por lo que tiene sentido elegir JPEG como formato base para almacenar fotos originales, que, si es necesario, se ampliará en tiempo real después de recibir una solicitud del usuario.
Por supuesto, además de los jeeps, cada sitio suele tener imágenes PNG y GIF, pero generalmente su número relativo es pequeño y las fotos en estos formatos son extremadamente raras. Por lo tanto, estos formatos no tendrán un impacto significativo en la tarea en cuestión en la mayoría de los casos.
Descripción del algoritmo de cambio de tamaño sobre la marcha
Por lo tanto, los datos de entrada son archivos JPEG, y para lograr una decodificación rápida (esto es cierto tanto para la CPU como para la GPU), las imágenes comprimidas deben tener marcadores de reinicio incorporados. Estos marcadores se describen en el estándar JPEG y parte de los códecs pueden trabajar con ellos, el resto sabe cómo no notarlos. Si los jeeps no tienen dichos marcadores, se pueden agregar por adelantado usando la utilidad jpegtran. Cuando se agregan marcadores, la imagen no cambia, pero el tamaño del archivo se vuelve un poco más grande. Como resultado, obtenemos el siguiente esquema de trabajo:
- Obtener datos de imagen de la memoria de la CPU
- Si hay un perfil de color, consíguelo en la sección EXIF y guárdelo
- Copie la imagen a la tarjeta de video
- Decodificar JPEG
- Hacemos un cambio de tamaño de acuerdo con el algoritmo de Lanczos (disminución)
- Nitidez
- Codificamos la imagen usando JPEG
- Copiar imagen al host
- Agregue el perfil de color original al archivo resultante.
Puede tomar una decisión más precisa cuando, antes de cambiar el tamaño, la gamma inversa se superpone en cada componente del píxel para que el cambio de tamaño esté en un espacio lineal y luego vuelva a aplicar la gamma, pero después de la nitidez. La diferencia real para el usuario es pequeña, pero existe, y el costo computacional para tal modificación es mínimo. Solo es necesario insertar la superposición de la gamma inversa y directa en el esquema general de procesamiento.
También hay una posible solución cuando la decodificación de jeeps se realiza en una CPU multinúcleo utilizando la biblioteca libjpeg-turbo. En este caso, cada imagen se decodifica en un flujo de CPU separado, y todas las demás acciones se realizan en la tarjeta de video. Con una gran cantidad de núcleos de CPU, esto puede suceder aún más rápido, pero habrá una seria pérdida de latencia. Si la latencia al decodificar un jeep en un solo núcleo de CPU es aceptable, entonces esta opción puede ser muy rápida, especialmente en el caso de que los jeeps originales tengan una resolución pequeña. A medida que aumenta la resolución de la imagen original, aumentará el tiempo de decodificación del jeep en un flujo de CPU, por lo que esta opción solo puede ser adecuada para resoluciones pequeñas.
Requisitos básicos para la tarea de redimensionamiento web
- Es aconsejable no almacenar docenas de copias de cada imagen en diferentes resoluciones en el servidor, sino crear rápidamente la imagen deseada con la resolución correcta inmediatamente después de recibir la solicitud. Esto es importante para reducir el tamaño del almacenamiento, ya que de lo contrario tendrá que almacenar muchas copias diferentes de cada imagen.
- El problema debe resolverse lo más rápido posible. Esta es una pregunta sobre la calidad del servicio prestado en términos de reducir el tiempo de respuesta a una solicitud del usuario.
- La calidad de la imagen enviada debe ser alta.
- El tamaño del archivo para la imagen enviada debe ser lo más pequeño posible, y su resolución debe coincidir exactamente con el tamaño de la ventana en la que aparece. Los siguientes puntos son importantes aquí:
a) Si el tamaño de la imagen no coincide con el tamaño de la ventana, el dispositivo del usuario (teléfono, tableta, computadora portátil) cambiará el tamaño del hardware después de la decodificación antes de mostrar la imagen en la pantalla. En OpenGL, este cambio de tamaño de hardware se realiza solo de acuerdo con el algoritmo bilineal, que a menudo causa la aparición de muaré (manchas) y otros artefactos en las imágenes que contienen pequeños detalles.
b) Cambiar el tamaño de la pantalla además consume energía del dispositivo.
c) Si utiliza una serie de imágenes preescaladas para resolver el problema, no siempre es posible obtener exactamente el tamaño correcto, lo que significa que tendrá que enviar una imagen de mayor resolución. El aumento del tamaño de la imagen genera más tráfico, lo que también me gustaría evitar.
Descripción del esquema general de trabajo.
- Recibimos imágenes de los usuarios en cualquier formato y en cualquier resolución. Los originales se almacenan en una base de datos separada (si es necesario).
- Sin conexión, utilizando ImageMagick o un software similar, guarde el perfil de color, convierta las imágenes originales originales al formato BMP o PPM estándar, luego cambie el tamaño a una resolución de 1K o 2K y comprima a JPEG, luego agregamos marcadores de reinicio con el intervalo fijo especificado utilizando la utilidad jpegtran.
- Componemos una base de datos de tales imágenes 1K o 2K.
- Al recibir una solicitud del usuario, obtenemos información sobre la imagen y el tamaño de la ventana donde se debe mostrar esta imagen.
- Encontramos la imagen en la base de datos y la enviamos al redimensionador.
- El redimensionador recibe el archivo de imagen, decodifica, redimensiona, enfoca, codifica e inserta el perfil de color original en el jeep resultante. Después de eso le da la imagen a un programa externo.
- En cada tarjeta de video, puede ejecutar varios subprocesos y puede instalar varias tarjetas de video en su computadora, logrando así una escala de rendimiento.
- Todo esto se puede hacer sobre la base de las tarjetas de video NVIDIA Tesla (por ejemplo, P40 o V100), ya que las tarjetas de video NVIDIA GeForce no están diseñadas para un funcionamiento continuo a largo plazo, y NVIDIA Quadro tiene muchas salidas de video que no son necesarias en este caso. Para resolver este problema, los requisitos para el tamaño de memoria de la GPU son mínimos.
- Además, desde la base de datos con imágenes preparadas, puede asignar dinámicamente un caché para los archivos de uso frecuente. Allí tiene sentido almacenar imágenes de uso frecuente de acuerdo con las estadísticas del período anterior.

Parámetros del programa
- Ancho y alto de la nueva imagen. Pueden ser cualquiera y es mejor configurarlos explícitamente.
- Modo de adelgazamiento JPEG (submuestreo). Hay tres opciones: 4: 2: 0, 4: 2: 2 y 4: 4: 4, pero generalmente usan 4: 4: 4 o 4: 2: 0. La calidad máxima es 4: 4: 4, el tamaño de fotograma mínimo es 4: 2: 0. El adelgazamiento se realiza para componentes de diferencia de color, que la visión de una persona no percibe tan bien como la luminosidad. Cada modo de diezmado tiene su propio intervalo óptimo para que los marcadores de reinicio alcancen la velocidad máxima de codificación o decodificación.
- Calidad de compresión JPEG y modo de diezmado al crear una base de datos de imágenes.
- Sharp se realiza en una ventana de 3x3, se puede controlar sigma (radio).
- Calidad de compresión JPEG y modo de decimación al codificar la imagen final. Típicamente, una calidad de al menos 90% significa que esta compresión es "visualmente sin pérdida", es decir Los usuarios no entrenados no deben ver los artefactos del algoritmo JPEG en condiciones de visualización estándar. Se cree que para un usuario capacitado, se necesita 93-95%. Cuanto mayor sea este valor, mayor será el tamaño de la trama enviada al usuario y mayor será el tiempo de decodificación y codificación.
Limitaciones importantes
Reiniciar marcadores. Podemos decodificar rápidamente imágenes JPEG en una tarjeta de video solo si hay marcadores de reinicio dentro de ella. En el estándar JPEG oficial, se describen estos marcadores, este es un parámetro estándar. Si no hay marcadores de reinicio, entonces es imposible paralelizar la decodificación de la imagen en la tarjeta de video, lo que conducirá a una velocidad muy baja del decodificador. Por lo tanto, necesitamos una base de datos de imágenes preparadas en las que existan estos marcadores.
Algoritmo fijo para códec de imagen. Decodificar y codificar imágenes usando el algoritmo JPEG es, con mucho, la opción más rápida.
La resolución de las imágenes en la base de datos preparada puede ser cualquiera, pero como opciones consideraremos 1K y 2K (puede tomar 4K). También puede hacer no solo una disminución, sino también un aumento de las imágenes al cambiar el tamaño.
Rendimiento de cambio de tamaño rápido
Probamos la aplicación para cambiar rápidamente el tamaño del Fastvideo SDK en la tarjeta de video NVIDIA Tesla V100 (OS Windows Server 2016, 64 bits, controlador 24.21.13.9826) en imágenes de 24 bits 1k_wild.ppm y 2k_wild.ppm con una resolución de 1K y 2K (1280x720 y 1920x1080). Se realizaron pruebas para un número diferente de subprocesos que se ejecutan en la misma tarjeta de video. Esto requiere no más de 110 MB de memoria en la tarjeta de video por transmisión. 4 transmisiones no necesitan más de 440 MB.
Primero, comprimimos la imagen original en JPEG con un 90% de calidad, con un adelgazamiento 4: 2: 0 o 4: 4: 4. Luego decodificamos y redimensionamos 2 veces en ancho y alto, hacemos una nitidez y luego codificamos nuevamente con un 90% de calidad a 4: 2: 0 o 4: 4: 4. Los datos de origen están en RAM, la imagen final se coloca allí.
El tiempo de funcionamiento se cuenta desde el inicio de cargar la imagen original desde la RAM hasta guardar la imagen procesada en la RAM. El tiempo de inicialización del programa y la asignación de memoria en la tarjeta de video no están incluidos en las mediciones.
Ejemplo de línea de comando para una imagen 1K de 24 bits
PhotoHostingSample.exe -i 1k_wild.90.444.jpg -o 1k_wild.640.jpg -outputWidth 640 -q 90 -s 444 -sharp_after 0.95 -repeat 200
Punto de referencia para procesar una imagen 1K en un hilo
Decodificación (incluida la transferencia de datos a la tarjeta de video): 0.70 ms
Cambiar el tamaño dos veces (en ancho y en altura): 0.27 ms
Sharp: 0,02 ms
Codificación JPEG (incluida la transferencia de datos desde la tarjeta de video): 0.20 ms
Tiempo total por trama: 1.2 msRendimiento para 1K
| Calidad | Adelgazamiento | Redimensionar | Corrientes | Velocidad de fotogramas (Hz) |
1 | 90% | 4: 4: 4/4: 2: 0 | 2 veces | 1 | 868/682 |
2 | 90% | 4: 4: 4/4: 2: 0 | 2 veces | 2 | 1039/790 |
3 | 90% | 4: 4: 4/4: 2: 0 | 2 veces | 3 | 993/831 |
4 4 | 90% | 4: 4: 4/4: 2: 0 | 2 veces | 4 4 | 1003/740 |
Rendimiento para 2K
| Calidad | Adelgazamiento | Redimensionar | Corrientes | Velocidad de fotogramas (Hz) |
1 | 90% | 4: 4: 4/4: 2: 0 | 2 veces | 1 | 732/643 |
2 | 90% | 4: 4: 4/4: 2: 0 | 2 veces | 2 | 913/762 |
3 | 90% | 4: 4: 4/4: 2: 0 | 2 veces | 3 | 891/742 |
4 4 | 90% | 4: 4: 4/4: 2: 0 | 2 veces | 4 4 | 923/763 |
El adelgazamiento 4: 2: 0 para la imagen de origen reduce la velocidad, pero el tamaño de los archivos de origen y de destino se reduce. Al cambiar a 4: 2: 0, el grado de paralelismo disminuye 4 veces, ya que ahora el bloque 16x16 se considera como una sola unidad, por lo tanto, en este modo, la velocidad es menor que para 4: 4: 4.
El rendimiento está determinado principalmente por la etapa de decodificación JPEG, porque en esta etapa la imagen tiene la resolución máxima, y la complejidad computacional de esta etapa de procesamiento es más alta que todas las demás.
Resumen
Los resultados de la prueba mostraron que para la tarjeta de video NVIDIA Tesla V100, la velocidad de procesamiento de imágenes de 1K y 2K es máxima cuando se lanzan 2-4 transmisiones al mismo tiempo, y varía de 800 a 1000 cuadros por segundo por tarjeta de video. Procesar imágenes 1K es más rápido que 2K, y trabajar con imágenes 4: 2: 0 siempre es más lento que con 4: 4: 4. Para obtener el resultado final del rendimiento, debe determinar con precisión todos los parámetros del programa y optimizarlo para un modelo específico de la tarjeta de video.
La latencia del orden de un milisegundo es un buen resultado. Hasta donde sabemos, dicha latencia no se puede obtener para una tarea de cambio de tamaño similar en la CPU (incluso si no hay necesidad de codificar y decodificar jeeps), por lo que este es otro argumento importante a favor del uso de tarjetas de video en soluciones de procesamiento de imágenes de alto rendimiento.
Se pueden requerir hasta 16 tarjetas gráficas NVIDIA Tesla V100 para procesar mil millones de jeeps por día con resoluciones de 1K o 2K. Algunos de nuestros clientes ya usan esta solución, mientras que otros la prueban en sus tareas.
Cambiar el tamaño de los jeeps en una tarjeta de video puede ser muy útil no solo para los servicios web. Hay una gran cantidad de aplicaciones de procesamiento de imágenes de alto rendimiento donde dicha funcionalidad puede ser muy solicitada. Por ejemplo, a menudo es necesario un cambio de tamaño rápido para casi cualquier esquema de procesamiento de imágenes recibidas de cámaras antes de mostrar una imagen en un monitor. Esta solución puede funcionar para Windows / Linux en cualquier tarjeta gráfica NVIDIA: Tegra K1 / X1 / X2 / Xavier, GeForce GT / GTX / RTX, Quadro, Tesla.
Ventajas de una solución de cambio de tamaño rápido en una tarjeta gráfica
- Reducción significativa en el tamaño de almacenamiento para imágenes de origen
- Reducción de costos primarios para costos de infraestructura (hardware y software)
- Mejora de la calidad del servicio debido al corto tiempo de respuesta.
- Reducción de tráfico saliente
- Menor consumo de energía en dispositivos de usuario
- Fiabilidad y velocidad de la solución presentada, que ya se ha probado en grandes conjuntos de datos.
- Tiempo de desarrollo reducido para comercializar dichas aplicaciones para Linux y Windows
- Escalabilidad de una solución que puede funcionar tanto en una sola tarjeta de video como como parte de un clúster
- Rápido retorno de la inversión para tales proyectos.
Quien puede estar interesado
La biblioteca para el cambio rápido de tamaño de jeeps se puede utilizar en servicios web altamente cargados, grandes tiendas en línea, redes sociales, sistemas de administración de fotografías en línea, comercio electrónico, en casi cualquier software de administración de grandes empresas.
Los desarrolladores de software pueden usar esta biblioteca, que proporciona una latencia del orden de varios milisegundos para cambiar el tamaño de los jeeps con una resolución de 1K, 2K y 4K en una tarjeta de video.
Aparentemente, este enfoque puede resultar más rápido que la solución NVIDIA DALI para la decodificación rápida de jeeps, el cambio de tamaño y la preparación de imágenes durante la etapa de capacitación de redes neuronales para Deep Learning.
¿Qué más se puede hacer?
- Además de cambiar el tamaño y el enfoque, puede agregar recorte, giros a 90/180/270, superposición de marca de agua, control de brillo y contraste al algoritmo existente.
- Optimización de soluciones para tarjetas gráficas NVIDIA Tesla P40 y V100
- Optimización adicional del rendimiento del decodificador JPEG.
- Modo de ráfaga para decodificar jeeps en una tarjeta de video.