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 el formato Bayer y utiliza 10 bits por píxel. Como no hay ningún 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 los datos antes de transmitirlos a través de una red.
- La cámara no se mueve, por lo que grandes partes de fotogramas consecutivos son casi idéntico, pero aún no completamente, debido a lo inevitable ruido (la eliminación de ruidos no es una opción, ya que se supone que no tiene pérdidas) y no debería "perder" ni 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 se sacude 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 debe realizarse sobre la marcha, por lo que no puedo reunir mucho de fotogramas y comprimirlos todos juntos, pero puedo mirar 1 fotograma hacia atrás y usarlo como referencia.
Basándome en lo anterior, mi primer pensamiento fue empaquetar los datos en bits, para que esos 6 bits redundantes no se desperdicien en cada palabra. Sin embargo, pensé que si uso alguna codificación de entropía (por ejemplo, Huffman, etc.), esa redundancia se tomaría en cuenta automáticamente, por lo que no es necesario un empaquetado adicional. Así que he hecho lo siguiente:
- Tomó la diferencia binaria entre dos cuadros consecutivos. El original el rango de datos fue de 0 ~ 1023 (por ejemplo, 10 bits sin signo). Datos de diferencia se firma y el rango aumenta a -1023 ~ 1023, pero los datos la variación (o cuál es el término matemático correcto) se vuelve mucho menos que en los datos originales, de hecho, la mayoría de los valores son, no Sorprendentemente, cerca de cero.
- Codificación de arroz aplicada a la diferencia. Por lo que yo entiendo, Parece una buena opción para conjuntos de datos de en su mayoría pequeños números valores.
Esto me da un 60% de reducción en el 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 tan bueno, pero razonable, supongo (¿o no?).
¿Hay mejores maneras? ¿Algún error común que hice? ¿Algún paso general que haya perdido? Los marcos de mayor resolución se pueden usar más adelante. ¿Debería esperar mejores tasas de compresión para tamaños de marco más grandes?
UPD .:
- Utilicé esta biblioteca para la codificación de Rice. La biblioteca es muy lenta (el propio autor lo describe como algo para aprender en lugar de 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, luego 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 es 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, qué podría encontrar sobre Huffman el código sugiere que es secuencial y no se puede vectorizar de manera eficiente, lo que puede aplicarse al código de Rice así como a otros códigos de longitud variable).
- También probé un enfoque completamente diferente: divida los datos en partes pequeñas (p. ej., como 64 píxeles cada uno) y use el simple supresión cero . Encontramos el número más grande en un bloque, escribimos el número de bits necesarios para representarlo al comienzo del bloque (para mi caso se requerían 4 bits adicionales, luego reduzcamos todos los números en el bloque al mismo número de bloques). pedacitos 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 puede reducirse a algo así como 4 ~ 6 bits por valor, y, de hecho, fue solo aproximadamente un 5% peor que el código de Rice, mientras que es aproximadamente el doble de rápido (por ejemplo, 160 FPS para mi caso). Intenté vectorizarlo, pero apesto un poco en la vectorización, así que tal vez debido a eso solo pude lograr alrededor de x1.8 de mayor aceleración.
Debido a que los números negativos no tienen ceros iniciales, apliqué codificación en zigzag después de la diferencia binaria y antes de la supresión de Rice / cero .