4 puntos por GN⁺ 2025-05-28 | 1 comentarios | Compartir por WhatsApp
  • Rational Bloom Filter Video Compression implementa un flujo de trabajo sin pérdida que comprime video sin procesar y exige que el resultado restaurado sea idéntico al original bit a bit
  • La clave es una estructura que aplica una cantidad no entera de funciones hash al filtro de Bloom, con el objetivo teórico de lograr una mejor tasa de compresión que los métodos existentes
  • Está orientado a raw video content como Y4M, YUV y HDR, y afirma ofrecer un ahorro de espacio del 40 al 50% en videos comunes
  • La implementación está basada en Python 3.7+ y requiere dependencias como numpy, opencv-python, xxhash, Pillow, scikit-image y pyexr para HDR
  • Incluye benchmarks comparativos con FFV1, HuffYUV y el modo sin pérdida de H.264, por lo que antes de usarlo en la práctica el flujo es revisar los resultados y el procedimiento de reproducción en results.md

Descripción general de Rational Bloom Filter Video Compression

  • Este proyecto implementa un método de compresión de video sin pérdida basado en rational Bloom filter
  • El filtro de Bloom se usa como una estructura de datos probabilística para representar datos binarios de forma eficiente
  • Su diferencia es que usa una rational hash function no entera en el filtro de Bloom
  • El objetivo es que el resultado restaurado tras la compresión coincida con el original de forma bit-exact

Soporte y funciones de compresión

  • El sistema de compresión está orientado a raw video content como Y4M, YUV y HDR
  • Las funciones que ofrece son las siguientes
    • true lossless compression, que garantiza una restauración idéntica bit a bit
    • Ahorro de espacio del 40 al 50% en contenido de video común
    • Codificación y decodificación con soporte multihilo
    • Soporte para varios color space, como RGB, BGR y YUV
    • Soporte para procesar contenido HDR
  • El procesamiento HDR tiene la limitación de que “hace falta más trabajo para que sea rápido y utilizable”

Requisitos de instalación

  • El entorno de ejecución es Python 3.7+
  • Los paquetes necesarios son los siguientes
    • numpy
    • opencv-python
    • matplotlib
    • pandas
    • tqdm
    • requests
    • xxhash
    • Pillow
    • scikit-image
    • pyexr: para soporte HDR
  • Las dependencias se instalan con el siguiente comando
pip install -r requirements.txt

Uso básico

  • En código Python, se importa ImprovedVideoCompressor y se inicializa el compresor
  • La configuración de ejemplo incluye noise_tolerance=10.0, keyframe_interval=30, use_direct_yuv=True y verbose=True
  • compress_video() comprime el video de entrada en un archivo .bfvc
  • decompress_video() restaura el archivo .bfvc
  • Con verify_lossless() se verifica si los frames originales y los restaurados son sin pérdida
from improved_video_compressor import ImprovedVideoCompressor

compressor = ImprovedVideoCompressor(
    noise_tolerance=10.0,
    keyframe_interval=30,
    use_direct_yuv=True,
    verbose=True
)

compressor.compress_video(
    input_file="input_video.y4m",
    output_file="compressed.bfvc"
)

compressor.decompress_video(
    input_file="compressed.bfvc",
    output_file="decompressed.mp4"
)

original_frames = compressor.extract_frames_from_video("input_video.y4m")
decompressed_frames = compressor.decompress_video("compressed.bfvc")
verification = compressor.verify_lossless(original_frames, decompressed_frames)
print(f"Lossless: {verification['lossless']}")

Uso desde la línea de comandos

  • La compresión de video se ejecuta así
python -m improved_video_compressor compress input_video.y4m output.bfvc --max-frames 30
  • Los archivos raw YUV se procesan especificando también ancho, alto y formato
python -m improved_video_compressor process-yuv input.yuv output.bfvc --width 1920 --height 1080 --format YUV444

Benchmarks y comparaciones

  • El proyecto incluye un sistema de benchmarks que compara la compresión Rational Bloom Filter con otros métodos de compresión sin pérdida
  • Los métodos de comparación son FFV1, HuffYUV y el modo sin pérdida de H.264
  • El comando para ejecutar el benchmark completo es el siguiente
python benchmark_compression.py
  • También se puede ejecutar especificando solo ciertos datasets y métodos
python benchmark_compression.py --datasets y4m --methods bloom ffv1 --max-frames 10
  • Los resultados detallados del benchmark y el método de reproducción están en results.md

Flujo de funcionamiento del método de compresión

  • El esquema de compresión funciona con los siguientes pasos
    • Frame Extraction: extrae frames del video de entrada
    • Keyframe Selection: guarda los keyframes como frames comprimidos directamente con zlib
    • Bloom Filter Compression: comprime los interframes como mapas de diferencias mediante rational Bloom filter
    • Lossless Verification: verifica durante la decodificación la restauración bit-exact
  • El rational Bloom filter usa una cantidad no entera de funciones hash k* para optimizar el equilibrio entre espacio y precisión
  • La implementación usa de forma determinista ⌊k*⌋ funciones hash y aplica una función hash adicional con probabilidad k* - ⌊k*⌋

Estructura de archivos del proyecto

  • improved_video_compressor.py: main implementation del algoritmo de compresión
  • verify_true_lossless.py: script que verifica la restauración sin pérdida
  • benchmark_compression.py: sistema de benchmarks que compara varios métodos de compresión
  • download_*.py: scripts para descargar datasets de prueba
  • results.md: resultados detallados y análisis de los benchmarks

Licencia y cita

  • La licencia es MIT License y los detalles se pueden consultar en el archivo LICENSE
  • Si se usa el código en una investigación, se indica usar la cita en formato BibTeX incluida en el README

1 comentarios

 
GN⁺ 2025-05-28
Opiniones en Hacker News
  • Siento que el documento no explica bien una idea bastante simple. Si entendí correctamente, primero se crea un mapa de bits en el que cada bit se ve como un píxel de la imagen, y al pasar del frame 0 al frame 1 se pone 1 si el píxel cambió, o 0 si no
    Luego se hashean los offsets de las posiciones que valen 1 y se meten en un Bloom filter. Así, esos índices y cierto porcentaje de índices falsos positivos salen como positivos
    Después se consulta el Bloom filter para encontrar todos los índices positivos y, para esos píxeles, se guardan los datos de píxel sin procesar que cambiaron; así se puede reconstruir fácilmente el siguiente frame
    Se puede ver como guardar el delta entre dos frames con x,y,r,g,b de todos los píxeles que cambiaron, pero comprimiendo mucho la parte x,y y guardando un poco más de r,g,b de lo necesario
    Como las ubicaciones de los píxeles que cambiaron del frame 0→1 suelen parecerse a las ubicaciones que cambiarán del frame 1→2, parece que habría margen para comprimir más si en el siguiente frame se activa un flag adecuado y se guardan tal cual solo los offsets adicionales que difieren respecto de antes

    • Me da curiosidad saber qué tan buena es la tasa de compresión real. Me recuerda a cuando, hace unos 22 años, experimentaba con wavelets para compresión de imágenes
      La transformada inversa empieza con una imagen pequeña de píxeles y la convierte en una imagen con el doble de ancho o alto usando la misma cantidad de coeficientes, y repite eso
      La clave es que la mayor parte de los datos son coeficientes, y la mayoría están cerca de 0, así que se pueden empujar a 0. Entonces el problema pasa a ser cómo codificar las posiciones que no son 0, y se obtiene una estructura como un mapa de bits y un arreglo de valores no nulos
      Los algoritmos para codificar valores no nulos variaban en qué tan conservadores eran, pero en general aprovechaban la propiedad de que esos valores suelen estar bastante agrupados. Eso es exactamente lo contrario de las funciones hash típicas que se usan en un Bloom filter
      Este tipo de compresión de imágenes era lenta porque tenía muy mala localidad, tanto en la propia transformada como en la compresión de coeficientes, así que se sentía como un callejón sin salida
    • Si se guardan los cambios delta de un frame al siguiente, los píxeles que no cambiaron son simplemente 0. Comprimir secuencias de ceros es una de las tareas más triviales en compresión sin pérdida y, a diferencia de un Bloom filter, no tiene falsos positivos
      Creo que un Bloom filter podría usarse como parte de una estrategia híbrida de compresión compleja. En un compresor así, mientras más herramientas haya, mejor, pero en promedio no parece que vaya a mejorar mucho
    • Me pregunto en qué ayuda un Bloom filter en comparación con algo como una tabla hash
    • Gran parte de la compresión de video consiste en manejar el movimiento. Me pregunto cómo trataría un caso en el que, por un paneo, el mismo píxel se desliza dos píxeles hacia la izquierda
  • Parece funcionar mejor porque el video de entrada ya es un video comprimido y luego reconstruido desde YouTube
    Si la entrada fuera el video original, probablemente se rompería la suposición de que “entre frames consecutivos la mayoría de los píxeles cambia poco o nada, generando una matriz de diferencias dispersa”
    Con una señal muy limpia, por ejemplo un sensor de bajo ruido y una escena bien iluminada, podría ser posible, pero en la mayoría de las señales reales el ruido es mayor que 1 LSB, así que esperaría que al menos la mitad de los bits inferiores cambien
    Si se hace que el video pase una vez por el proceso de compresión y reconstrucción, ese ruido tiende a eliminarse, creando un video artificialmente estático en el que esa suposición sí se cumple

    • A simple vista, esto también parece no ser sin pérdida: https://github.com/ross39/new_bloom_filter_repo/blob/main/vi...
      Parece que no guarda la diferencia para píxeles cuyo cambio promedio en r,g,b es menor que 10. Entonces, aunque un píxel cambie de azul puro (#00ff00) a rojo puro (#ff0000) en frames consecutivos, ambos frames podrían reconstruirse como azul puro
    • Así como no se usa PNG para fotos, no creo que se usen códecs de video sin pérdida para videos filmados reales
      El video sin pérdida encaja mucho mejor con contenido digital como grabaciones de pantalla. La suposición de que pocos píxeles cambian entre frames consecutivos también es más válida ahí
    • Quizá no sea un gran problema porque la gente normal no usa raw. Los teléfonos y las cámaras de todos modos guardan en archivos como MP4 o AV1
      A menos que alguien lo active explícitamente y acepte el tamaño de archivo y la carga de procesamiento, puede que ni siquiera sepa que todavía existe el concepto de datos originales o sin procesar
      Nunca lo había pensado así antes
    • Con el método actual, parecería encajar muy bien con animaciones
    • La forma perezosa sería descargar un video 8K y hacerle downsampling a algo como 720p
      O comprar una cámara y grabar personalmente video 8K original de escenas cotidianas
  • Según el gráfico [1], ¿este nuevo método de compresión no es siempre estrictamente peor que usar simplemente GZIP?
    [1] https://github.com/ross39/new_bloom_filter_repo/blob/main/co...

    • Aunque no aparece en el gráfico, creo que el método con Bloom filter al menos podría ser más rápido que gzip. Pero tampoco encuentro métricas de rendimiento en otra parte
  • “Idea clave: si la densidad de 1 en una cadena binaria es baja, especialmente si está por debajo de p* ≈ 0.32453, es más eficiente codificar solo las posiciones de los 1 que almacenar la cadena original.”
    Gran parte de lo que hacen JPEG/MPEG es reorganizar el problema para poder crear largas secuencias de 0. La forma en que se escanean los bloques DCT según la posición de los componentes AC/DC podría ser una de las partes más innovadoras en varias técnicas de compresión de video e imagen

    • En realidad, este método es bastante malo para la compresión de video. Porque descarta activamente la localidad de los cambios de píxeles que existe en los videos comunes.
      Dicho de una mejor manera, esta técnica no tiene nada específico para cuadros de video. La misma idea podría usarse para comprimir la diferencia entre dos secuencias de bits de la misma longitud.
      Aun así, es poco probable que este problema sea mejor que los métodos de compresión existentes, por ejemplo concatenar dos bloques y aplicarles gzip. Para que haya compresión, la distribución de entrada —en este caso, el conjunto de distintas posiciones de bits— debe ser muy predecible y no aleatoria, pero al pasar los datos por una función hash se rompe esa propiedad. En especial, el objetivo de un hash criptográficamente fuerte es hacer que la salida sea indistinguible de lo aleatorio
    • Creo que esa explicación no es correcta.
      Lo que hacen DCT y la conversión de representación de color es convertir los detalles finos en altas frecuencias, y los detalles principales en bajas frecuencias. Luego, la calidad de imagen y la tasa de compresión se simplifican a cuánto se descarta de la representación de alta frecuencia.
      Además de eso, JPEG usa tablas Huffman para reducir aún más el tamaño de la imagen.
      Hasta donde sé, no hace nada especial para reducir largas secuencias de 0. Por eso alinear los 0 en una fila no ayuda demasiado
  • Esta línea me confunde: https://github.com/ross39/new_bloom_filter_repo/blob/4798d90...
    Con esto, la compresión se vuelve con pérdida, y por ejemplo parecería descartar una transición de #ffffff a #fffffa. La línea justo anterior, donde se promedian los datos de píxeles, también parecería descartar una transición de #ff0000 a #00ff00 independientemente del umbral.
    No sé si estoy entendiendo mal el papel de esa línea de código. Lo que queda en 0 en la máscara resultante parece no codificarse en el Bloom filter

  • Está escrito cómo se calcula la tasa de compresión, pero me pregunto si también hay ejemplos de tasa de compresión en el peor caso, promedio y mejor caso.
    Edit: vi que hay una imagen en el repositorio. Sería útil ponerla en el README

    • Soy el autor. El repositorio está hecho un completo desastre, pero si tienes ganas de meterte en el código, incluye código para generar gráficos y demás.
      Planeo hacerlo mucho más concreto con bastantes pruebas adecuadas. Por ahora se parece más a un trabajo en curso bastante desordenado
  • Soy el autor. Recibí muchos buenos comentarios, así que por un tiempo decidí concentrarme en pruebas más rigurosas con video original y videos con ruido. Voy a seguir actualizando el repositorio con frecuencia.
    Todavía está en una etapa muy temprana, pero en pruebas con video original obtuvo resultados bastante buenos, con algunas pistas: tasa de compresión de 4.8%, es decir, reducción de tamaño de 95.2%, velocidad de compresión de 8.29fps, velocidad de descompresión de 9.16fps, solo se necesitan keyframes para el 4% de los cuadros, y una salida perceptualmente sin pérdida (PSNR 31.10dB).
    Comparado con códecs estándar: Rational Bloom Filter 4.8%, JPEG2000 sin pérdida 3.7%, FFV1 sin pérdida 36.5%, H.265/HEVC con pérdida 9.2%, H.264 con pérdida 0.3%.
    También hay limitaciones actuales y trabajo futuro. Aunque los resultados de compresión son prometedores, el procesamiento de canales de color todavía no es verdaderamente sin pérdida. La implementación actual tiene dificultades en la conversión de espacio de color de YUV a BGR, y debido a la precisión de la conversión de espacio de color se generan pequeños errores de redondeo, dejando una diferencia promedio de alrededor de 4.7 en los valores de píxel.
    Además, la implementación actual procesa los canales de color en formato BGR después de la conversión, lo que provoca pérdida adicional de precisión.
    De aquí en adelante planeo procesar YUV directamente sin conversión a BGR, tratar los datos de color con exactitud a nivel de bits, ajustar los parámetros del Bloom filter según los patrones de submuestreo de croma y crear un sistema dedicado que verifique cada canal de color de forma independiente.
    Quiero demostrar matemáticamente que es sin pérdida, pero todavía falta mucho. Planeo seguir investigando esta idea de compresión sin pérdida, y también tengo algunas ideas para usar Rational Bloom Filter en otras áreas

  • Códecs como H.264 también pueden ejecutarse en un modo verdaderamente sin pérdida. Solo que casi nadie los usa así

    • Una vez hice que incluso funcionara con aceleración por hardware usando NVENC. Pero la reproducción era difícil; ffplay funcionaba, pero otras cosas no
  • Es un concepto simpático, pero si tienes una cadena binaria dispersa, es muy probable que puedas hacerlo mejor con métodos tradicionales

  • Es difícil seguir el repositorio, pero parece que la tasa de compresión se calcula viendo cuántas diferencias de píxeles se pudieron descartar.
    Es interesante, pero la comparación más importante sería el tamaño promedio en bytes de cada cuadro en un video comprimido de YouTube. Sin esa comparación, es difícil juzgar si mejora los métodos actuales.
    Si el algoritmo es con pérdida, es decir, si aplasta a 0 las diferencias pequeñas, entonces no es sin pérdida y creo que habría que compararlo con otros algoritmos con pérdida