4 pontos por GN⁺ 2025-05-28 | 1 comentários | Compartilhar no WhatsApp
  • O Rational Bloom Filter Video Compression implementa um fluxo de trabalho sem perdas que comprime vídeo bruto e exige que o resultado restaurado seja idêntico ao original bit a bit
  • O ponto central é uma estrutura que aplica um número não inteiro de funções hash ao filtro de Bloom, buscando teoricamente uma taxa de compressão melhor que a dos métodos existentes
  • É voltado a conteúdo de vídeo bruto, como Y4M, YUV e HDR, e afirma oferecer economia de espaço de 40% a 50% em vídeos comuns
  • A implementação é baseada em Python 3.7+ e exige dependências como numpy, opencv-python, xxhash, Pillow, scikit-image e pyexr para HDR
  • Inclui benchmarks comparando com FFV1, HuffYUV e o modo sem perdas do H.264; antes do uso prático, o fluxo é conferir os resultados e os procedimentos de reprodução em results.md

Visão geral do Rational Bloom Filter Video Compression

  • Este projeto implementa um método de compressão de vídeo sem perdas baseado em rational Bloom filter
  • O filtro de Bloom é usado como uma estrutura de dados probabilística para representar dados binários de forma eficiente
  • O diferencial é usar uma rational hash function no filtro de Bloom, em vez de uma quantidade inteira
  • O objetivo é que o resultado restaurado após a compressão corresponda ao original de forma bit-exact

Alvos suportados e recursos de compressão

  • O sistema de compressão é voltado a conteúdo de vídeo bruto, como Y4M, YUV e HDR
  • Os recursos oferecidos são os seguintes
    • true lossless compression, garantindo restauração idêntica bit a bit
    • economia de espaço de 40% a 50% em conteúdos de vídeo comuns
    • Codificação e decodificação com suporte a multithreading
    • Suporte a vários color spaces, como RGB, BGR e YUV
    • Suporte ao processamento de conteúdo HDR
  • O processamento HDR tem a limitação de que “é preciso mais trabalho para torná-lo rápido e utilizável”

Requisitos de instalação

  • O ambiente de execução é Python 3.7+
  • Os pacotes necessários são os seguintes
    • numpy
    • opencv-python
    • matplotlib
    • pandas
    • tqdm
    • requests
    • xxhash
    • Pillow
    • scikit-image
    • pyexr: para suporte a HDR
  • As dependências são instaladas com o seguinte comando
pip install -r requirements.txt

Modo básico de uso

  • No código Python, importa-se ImprovedVideoCompressor e inicializa-se o compressor
  • A configuração de exemplo inclui noise_tolerance=10.0, keyframe_interval=30, use_direct_yuv=True e verbose=True
  • compress_video() comprime o vídeo de entrada em um arquivo .bfvc
  • decompress_video() restaura o arquivo .bfvc
  • verify_lossless() verifica se os frames originais e restaurados são sem perdas
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 pela linha de comando

  • A compressão de vídeo é executada assim
python -m improved_video_compressor compress input_video.y4m output.bfvc --max-frames 30
  • Arquivos raw YUV são processados especificando também largura, altura e formato
python -m improved_video_compressor process-yuv input.yuv output.bfvc --width 1920 --height 1080 --format YUV444

Benchmarks e métodos comparados

  • O projeto inclui um sistema de benchmarks que compara a compressão Rational Bloom Filter com outros métodos de compressão sem perdas
  • Os métodos comparados são FFV1, HuffYUV e o modo sem perdas do H.264
  • O comando para executar o benchmark completo é o seguinte
python benchmark_compression.py
  • Também é possível executar especificando apenas um dataset e métodos específicos
python benchmark_compression.py --datasets y4m --methods bloom ffv1 --max-frames 10
  • Os resultados detalhados dos benchmarks e o método de reprodução estão em results.md

Fluxo de funcionamento do método de compressão

  • O esquema de compressão opera nas seguintes etapas
    • Frame Extraction: extrai frames do vídeo de entrada
    • Keyframe Selection: os keyframes são armazenados diretamente como frames comprimidos com zlib
    • Bloom Filter Compression: os inter frames têm seus mapas de diferença comprimidos com um rational Bloom filter
    • Lossless Verification: verifica a restauração bit-exact durante a decodificação
  • O rational Bloom filter usa um número não inteiro de funções hash k* para otimizar o equilíbrio entre espaço e precisão
  • A implementação usa deterministamente ⌊k*⌋ funções hash, e uma função hash adicional é aplicada com probabilidade k* - ⌊k*⌋

Estrutura de arquivos do projeto

  • improved_video_compressor.py: main implementation do algoritmo de compressão
  • verify_true_lossless.py: script que verifica a restauração sem perdas
  • benchmark_compression.py: sistema de benchmarks que compara vários métodos de compressão
  • download_*.py: scripts para baixar datasets de teste
  • results.md: resultados detalhados dos benchmarks e análise

Licença e citação

  • A licença é MIT License, e os detalhes podem ser conferidos no arquivo LICENSE
  • Se o código for usado em pesquisa, a orientação é usar a citação em formato BibTeX incluída no README

1 comentários

 
GN⁺ 2025-05-28
Comentários do Hacker News
  • Acho que o documento não explicou muito bem uma ideia bastante simples. Se entendi corretamente, primeiro se cria um bitmap vendo cada bit como um pixel da imagem e, ao ir do frame 0 para o frame 1, pixels que mudaram ficam com 1; caso contrário, 0.
    Depois, os offsets das posições que são 1 são hasheados e inseridos em um Bloom filter. Assim, esses índices e uma certa proporção de índices falso-positivos passam a ser positivos.
    Em seguida, consulta-se o Bloom filter para encontrar todos os índices positivos e, para esses pixels, salvam-se os dados brutos dos pixels alterados, permitindo reconstruir facilmente o próximo frame.
    Dá para ver isso como armazenar o delta entre dois frames como x,y,r,g,b de todos os pixels alterados, mas comprimindo bastante a parte x,y e armazenando um pouco mais de r,g,b do que o necessário.
    Como as posições dos pixels alterados do frame 0→1 muitas vezes são parecidas com as posições que mudarão do frame 1→2, parece haver espaço para comprimir ainda mais no frame seguinte, marcando uma flag adequada e armazenando literalmente apenas os offsets que mudaram adicionalmente em relação ao anterior.

    • Fico curioso para saber quão boa é a taxa de compressão real. Isso me lembra quando, uns 22 anos atrás, eu experimentava wavelets para compressão de imagens.
      A transformação inversa começava com uma imagem pequena em pixels e a convertia em uma imagem com o dobro da largura ou da altura usando o mesmo número de coeficientes, repetindo isso.
      O ponto principal é que a maior parte dos dados são coeficientes, e a maioria deles fica perto de 0, podendo ser empurrada para 0. A questão então passa a ser como codificar as posições não zero, virando algo como um bitmap e um array de valores não zero.
      Os algoritmos para codificar valores não zero variavam no grau de conservadorismo, mas em geral aproveitavam o fato de esses valores ficarem bastante agrupados. Isso é exatamente o oposto das funções de hash normalmente usadas em um Bloom filter.
      Esse tipo de compressão de imagem era lento porque a localidade era muito ruim tanto na transformação em si quanto na compressão dos coeficientes, então parecia um beco sem saída.
    • Se você armazena a mudança delta de um frame para o próximo, pixels que não mudaram são simplesmente 0. Comprimir sequências de zeros é a tarefa mais trivial em compressão sem perdas e, diferentemente de um Bloom filter, não tem falsos positivos.
      Consigo imaginar um Bloom filter sendo usado como parte de uma estratégia híbrida de compressão complexa. Nesse tipo de compressor, quanto mais ferramentas, melhor, mas não acho que em média traga uma grande melhoria.
    • Fico curioso para saber em que um Bloom filter ajuda em comparação com algo como uma tabela hash.
    • Uma boa parte da compressão de vídeo lida com movimento. Fico curioso para saber como ele trata o caso em que, por causa de um pan, o mesmo pixel desliza dois pixels para a esquerda.
  • Parece funcionar melhor porque o vídeo de entrada já é um vídeo comprimido e depois restaurado pelo YouTube.
    Se a entrada fosse o vídeo original, a premissa de que “entre frames consecutivos, a maioria dos pixels muda só um pouco ou não muda nada, gerando uma matriz de diferenças esparsa” provavelmente cairia por terra.
    Com um sinal muito limpo, por exemplo um sensor de baixo ruído e uma cena bem iluminada, talvez seja possível; mas, na maioria dos sinais reais, o ruído é maior que 1 LSB, então eu esperaria que pelo menos cerca de metade dos bits inferiores mudasse.
    Quando o vídeo passa uma vez por compressão e restauração, esse ruído tende a ser removido, criando um vídeo artificialmente estático no qual essa premissa vale.

    • Pelo que parece, isto também não é sem perdas: https://github.com/ross39/new_bloom_filter_repo/blob/main/vi...
      Parece que pixels cuja mudança média nos valores r,g,b é menor que 10 não têm a diferença armazenada. Assim, mesmo que um pixel mude de azul puro (#00ff00) para vermelho puro (#ff0000) em frames consecutivos, ambos os frames poderiam ser restaurados como azul puro.
    • Assim como não se usa PNG para fotos, não acho que se usaria um codec de vídeo sem perdas para filmagens reais.
      Vídeo sem perdas combina muito mais com conteúdo digital, como gravações de tela. A suposição de que poucos pixels mudam entre frames consecutivos também é mais plausível nesse contexto.
    • Talvez isso não seja um grande problema, já que as pessoas normalmente não usam raw. Celulares e câmeras, de todo modo, salvam em arquivos como MP4 ou AV1.
      A menos que você ative isso diretamente e assuma o tamanho dos arquivos e a carga de processamento, talvez nem saiba que ainda existe o conceito de dados originais ou não processados.
      Eu nunca tinha pensado nisso dessa forma antes.
    • Do jeito que está agora, parece que combinaria muito bem com animações.
    • Um método preguiçoso seria baixar vídeo em 8K e fazer downsampling para algo como 720p.
      Ou então comprar uma câmera e gravar você mesmo vídeos 8K brutos de cenas do dia a dia.
  • Pelo gráfico [1], esse novo método de compressão não é sempre estritamente pior do que simplesmente usar GZIP?
    [1] https://github.com/ross39/new_bloom_filter_repo/blob/main/co...

    • Não aparece no gráfico, mas acho que o método com Bloom filter poderia pelo menos ser mais rápido que gzip. Porém, também não consigo encontrar métricas de desempenho em outros lugares.
  • “Insight central: se a densidade de 1s em uma string binária for baixa, especialmente abaixo de p* ≈ 0,32453, é mais eficiente codificar apenas as posições dos 1s do que armazenar a string bruta.”
    Boa parte do que JPEG/MPEG fazem é reorganizar o problema para conseguir criar longas sequências de 0s. A forma como blocos DCT são varridos conforme a posição dos componentes AC/DC talvez seja uma das partes mais inovadoras de várias técnicas de compressão de vídeo e imagem

    • Essa abordagem, na prática, é bem ruim para compressão de vídeo. Isso porque ela descarta ativamente a localidade das mudanças de pixels que existe em vídeos comuns
      Para dizer de forma mais favorável, não há nada nessa técnica que seja específico para quadros de vídeo. A mesma ideia poderia ser usada para comprimir a diferença entre duas sequências de bits de mesmo tamanho
      Ainda assim, é pouco provável que esse problema seja melhor do que métodos de compressão existentes, por exemplo concatenar dois blocos e passar gzip. Para que haja compressão, a distribuição de entrada — aqui, o conjunto de diferentes posições de bits — precisa ser muito previsível e não aleatória, mas passar os dados por uma função hash destrói essa propriedade. Em especial, o objetivo de um hash criptograficamente forte é tornar a saída indistinguível de aleatória
    • Acho que essa explicação não está certa
      O que a DCT e a conversão de representação de cores fazem é transformar detalhes finos em altas frequências e detalhes essenciais em baixas frequências. Depois disso, a qualidade da imagem e a taxa de compressão se reduzem a quanto da representação de altas frequências você descarta
      Além disso, o JPEG usa tabelas de Huffman para reduzir ainda mais o tamanho da imagem
      Até onde sei, ele não faz nada especial para reduzir longas sequências de 0s. Por isso, alinhar 0s em sequência não ajuda tanto assim
  • Esta linha me confundiu: https://github.com/ross39/new_bloom_filter_repo/blob/4798d90...
    Isso tornaria a compressão com perdas e, por exemplo, parece que descartaria uma transição de #ffffff para #fffffa. A linha logo acima, que calcula a média dos dados dos pixels, também parece descartar uma transição de #ff0000 para #00ff00 independentemente do limiar
    Talvez eu esteja entendendo mal o papel dessa linha de código. O que vira 0 na máscara resultante parece não ser codificado no Bloom filter

  • Está descrito como calcular a taxa de compressão, mas fiquei curioso se há exemplos de taxa de compressão no pior caso, média e melhor caso
    Edit: vi que há imagens no repositório. Seria útil colocá-las no README

    • Sou o autor. O repositório está uma bagunça completa, mas, se você estiver disposto a fuçar no código, há código para gerar gráficos e coisas do tipo
      Pretendo deixá-lo muito mais concreto depois de fazer bastante teste adequado. Por enquanto, ainda está mais para um trabalho em andamento bem bagunçado
  • Sou o autor. Recebi muito feedback bom, então decidi me concentrar por enquanto em testes mais rigorosos com vídeo original e vídeos com ruído. Vou continuar atualizando o repositório com frequência
    Ainda está em estágio muito inicial, mas nos testes com vídeo original obtive resultados bem razoáveis, com algumas ressalvas. Taxa de compressão de 4,8%, ou seja, redução de 95,2% no tamanho, velocidade de compressão de 8,29 fps, velocidade de descompressão de 9,16 fps, keyframes necessários em apenas 4% dos quadros e saída perceptualmente sem perdas (PSNR de 31,10 dB)
    Comparando com codecs padrão: Rational Bloom Filter 4,8%, JPEG2000 sem perdas 3,7%, FFV1 sem perdas 36,5%, H.265/HEVC com perdas 9,2%, H.264 com perdas 0,3%
    Também há limitações atuais e trabalhos futuros. Embora os resultados de compressão sejam promissores, o tratamento dos canais de cor ainda não é verdadeiramente sem perdas. A implementação atual tem dificuldades na conversão de espaço de cores de YUV para BGR, e a precisão dessa conversão gera pequenos erros de arredondamento, deixando uma diferença média de cerca de 4,7 nos valores dos pixels
    Além disso, a implementação atual processa os canais de cor no formato BGR depois da conversão, causando perda adicional de precisão
    Daqui em diante, planejo processar YUV diretamente sem conversão para BGR, tratar os dados de cor com exatidão em nível de bit, ajustar os parâmetros do Bloom filter aos padrões de subamostragem de croma e criar um sistema dedicado que valide cada canal de cor de forma independente
    Quero provar matematicamente que é sem perdas, mas ainda há um longo caminho. Pretendo continuar explorando essa ideia de compressão sem perdas e também tenho algumas ideias para usar o Rational Bloom Filter em outras áreas

  • Codecs como H.264 também podem ser executados em modo realmente sem perdas. Só que quase ninguém usa assim

    • Já fiz isso funcionar até com aceleração por hardware via NVENC. Mas a reprodução era difícil; funcionava no ffplay, mas não em outras coisas
  • É um conceito simpático, mas, se você tem uma string binária esparsa, é bem provável que métodos tradicionais façam melhor

  • É difícil acompanhar o repositório, mas a taxa de compressão parece ser calculada observando quantas diferenças de pixels puderam ser descartadas
    É interessante, mas a comparação mais importante provavelmente seria o tamanho médio em bytes de cada quadro em um vídeo comprimido do YouTube. Sem essa comparação, é difícil avaliar se há melhora em relação aos métodos atuais
    Se o algoritmo for com perdas, isto é, se ele zera pequenas diferenças, então não é sem perdas e acho que deveria ser comparado com outros algoritmos com perdas