Compresión rápida y sin pérdidas de una transmisión de video

14

Tengo un video proveniente de una cámara estacionaria. Tanto la resolución como el FPS son bastante altos. Los datos que obtengo están en formato Bayer y usan 10 bits por píxel. Como no hay un tipo de datos de 10 bits en mi plataforma, los datos originales se almacenan en la memoria con palabras de 16 bits. Quiero implementar algún tipo de compresión sin pérdida de datos antes de transmitirlos a través de una red.

  • La cámara no se mueve, por lo que gran parte de los cuadros consecutivos son casi idénticos, pero aún no del todo, debido al ruido inevitable (la eliminación de ruido no es una opción, ya que se supone que no tiene pérdidas y no debe "perder" ni siquiera el ruido )
  • Debido al alto FPS, incluso las partes que cambian no cambian mucho entre dos cuadros consecutivos.
  • Sin embargo, parece que la cámara también tiembla un poco. Muy poco, pero aún así, incluso los objetos estacionarios no están completamente en el espacio de la imagen.
  • La compresión tiene que hacerse sobre la marcha, por lo que no puedo reunir muchos cuadros y comprimirlos todos juntos, pero puedo mirar hacia atrás 1 cuadro y usarlo como referencia.

Basado en lo anterior, mi primer pensamiento fue empacar los datos en bits, de modo que esos 6 bits redundantes no se desperdicien en cada palabra. Sin embargo, pensé que si utilizo alguna codificación de entropía (por ejemplo, Huffman, etc.), esa redundancia se tendría en cuenta automáticamente, por lo que no es necesario un embalaje adicional. Así que hice lo siguiente:

  • Tomó la diferencia binaria entre dos cuadros consecutivos. El rango de datos original fue de 0 ~ 1023 (por ejemplo, 10 bits sin signo). Los datos de diferencia se firman y el rango aumenta a -1023 ~ 1023, pero la variación de datos (o cuál es el término matemático correcto) se vuelve mucho menor que en los datos originales, de hecho, la mayoría de los valores son, no sorprendentemente, cercanos a cero .
  • Codificación de arroz aplicada a la diferencia. Por lo que entiendo, parece una buena opción para conjuntos de datos de valores numéricos en su mayoría pequeños.

Esto me da aproximadamente un 60% de reducción de tamaño para cuadros de 1280x720, y mi sistema de prueba (Linux en VirtualBox en un solo núcleo) puede hacer ~ 40 compresiones por segundo (sin mucha optimización). No es genial, pero razonable, supongo (¿o sí?).

¿Hay mejores formas? ¿Algún error común que cometí? ¿Algún paso general que me perdí? Los marcos de mayor resolución se pueden usar más tarde. ¿Debería esperar mejores tasas de compresión para tamaños de marco más grandes?

UPD .:

  • Usé esta biblioteca para la codificación de Rice. La biblioteca es muy lenta (el propio autor la describe como algo para aprender más que para uso real), por ejemplo, lee y escribe bits uno por uno en bucles, lo que mata el rendimiento. Inicialmente solo me dio ~ 20 FPS, después de una optimización muy básica se convirtió en 40 FPS (como se informó anteriormente), luego lo optimicé un poco más, se convirtió en 80. Eso está en un solo núcleo i7 sin vectorización.
  • Sin embargo, en cuanto a la vectorización, desafortunadamente no se me ocurrió una forma de vectorizar el código de Rice (ni siquiera sé si es posible, no pude encontrar ningún dato sobre el código de Rice, lo que pude encontrar sobre el código de Huffman sugiere que es secuencial y no se puede vectorizar de manera eficiente, eso puede aplicarse al código de Rice, así como a otros códigos de longitud variable).
  • También probé un enfoque completamente diferente: dividir los datos en partes pequeñas (por ejemplo, como 64 píxeles por pieza) y usar la supresión de cero simple. Encontramos el número más grande en un bloque, escribimos el número de bits requeridos para representarlo al comienzo del bloque (se requirieron 4 bits adicionales para eso, en mi caso), luego reducimos todos los números en el bloque al mismo número de bits Esperaba que la tasa de compresión fuera mala, pero si las piezas son pequeñas, muchas de ellas no tendrán picos de ruido, por lo tanto, su diferencia binaria se puede reducir a algo así como 4 ~ 6 bits por valor, y de hecho, fue solo aproximadamente un 5% peor que el del código de Rice, mientras que es aproximadamente el doble de rápido (por ejemplo, 160 FPS para mi caso). Intenté vectorizarlo, pero apestaba un poco en la vectorización, así que tal vez por eso solo pude lograr aproximadamente x1.8 de mayor velocidad.

Debido a que los números negativos no tienen ceros a la izquierda, apliqué la codificación en zigzag después de la diferencia binaria y antes de la supresión de Rice / cero.

Headcrab
fuente
Puede usar un códec estándar como h264 que admite un modo de 10 bits. "Establecer -crf o -qp en 0 fuerza x264 en modo sin pérdida, la configuración -preset impacta solo la relación velocidad / tamaño". (Pero no sé si logrará el rendimiento en tiempo real)
CodesInChaos
@CodesInChaos, ¿haría mucho por solo dos cuadros?
Headcrab
Quizás, aún más importante: ¿pueden los códecs estándar incluso codificar imágenes de Bayer? Si no me equivoco, la conversión de Bayer a RGB implica interpolación y, por lo tanto, es irreversible.
Headcrab

Respuestas:

4

Tienes predicción temporal, pero no espacial. Para una mejor compresión a costa de la velocidad, debe poder utilizar los píxeles anteriores y a la izquierda del píxel actual en el cuadro actual como predictores, así como el píxel en la misma ubicación en el cuadro anterior. La razón para mirar solo hacia arriba y hacia la izquierda es la misma que para mirar solo el cuadro anterior; solo desea confiar en los datos que ya ha decodificado y limitar la cantidad de datos que debe conservar.

Los códigos de Rice son probablemente una buena compensación entre eficiencia y velocidad, pero un código Huffman estático (calculado previamente por usted en una muestra de datos de video) podría ser más eficiente e igualmente rápido.

En cuanto a la velocidad, asegúrese de que su código se vectorice , ya sea utilizando los indicadores del compilador y los patrones de código correctos para permitir que el compilador se auto-vectorice, o escribiendo a mano el código para usar intrínsecos o ensamblados de vectores .

Finalmente, ¿es posible bajar a 8 bits por píxel? Obviamente, eso está dejando el reino de "sin pérdidas", pero no solo reduciría el tamaño de su salida comprimida, sino que también, con código vectorizado, posiblemente aumentaría su rendimiento hasta 2 veces.

hobbs
fuente
Supongo que no es posible reducir 10bpp a 8, pero podría ser posible almacenar los deltas en menos bits, de la misma manera que UTF-8 usa 1 o, a veces, 2 bytes para almacenar un carácter. Si los deltas son casi 0 todo el tiempo, entonces sería bastante raro ver que cambien los 10 bits, por lo que vale la pena el esfuerzo de determinar 1 o 2 bytes para almacenarlos.
gbjbaanb
@gbjbaanb eso es lo que logra la codificación Rice. La mayoría de los deltas serán pequeños y, por lo tanto, solo usarán unos pocos bits.
hobbs
@hobbs, ¿por "predicción espacial" quieres decir algo como reemplazar un valor de píxel x5con la diferencia (x5 - x4)?
Headcrab
@Headcrab: un enfoque que he visto antes utilizado es usar el valor medio del píxel anterior y los píxeles arriba y a la izquierda en el cuadro actual.
Julio
@Jules si un píxel se reemplaza por algún tipo de valor medio de los píxeles circundantes, ¿es posible restaurar su valor original?
Headcrab
0

Probablemente le sirva mejor utilizando implementaciones existentes de compresión y descompresión. Su implementación existente parece similar al códec HuffYUV , por lo que podría valer la pena intentarlo para ver si funciona lo suficientemente bien para usted.

Jules
fuente
libx264 "preestablecido ultrarrápida" me ha servido bastante bien históricamente Fwiw ...
rogerdpack
@rogerdpack: vale la pena señalar que la configuración de libx264 para la codificación sin pérdidas da como resultado una salida que no cumple con H.264 y se rompe en algunos reproductores. Pero al menos podría ser útil para la aplicación del OP.
Jules
interesante ¿tienes algún enlace a eso? ¿Informe de error? También tenga en cuenta que un video codificado con HuffyYUV probablemente tampoco sea "apto para jugadores", me imagino :)
rogerdpack