Eu tenho um vídeo vindo de uma câmera estacionária. Tanto a resolução quanto o FPS são bastante altos. Os dados que recebo estão no formato Bayer e usam 10 bits por pixel. Como não há tipo de dados de 10 bits na minha plataforma, os dados originais são armazenados na memória usando palavras de 16 bits. Desejo implementar algum tipo de compactação sem perda de dados antes de transmiti-lo por uma rede.
- A câmera não se move, de modo que grandes partes de quadros consecutivos são quase idênticas - mas ainda não completamente, devido ao ruído inevitável (o denoising não é uma opção, pois deve ser sem perdas e não deve "perder" nem mesmo o ruído )
- Devido ao alto FPS, mesmo as partes que mudam não mudam muito entre dois quadros consecutivos.
- No entanto, parece que a câmera também treme um pouco. Muito pouco, mas ainda assim, mesmo os objetos estacionários não são completamente assim no espaço da imagem.
- A compactação deve ser feita em tempo real, para que eu não possa reunir muitos quadros e compactá-los todos juntos, mas posso olhar 1 quadro para trás e usá-lo como referência.
Com base no exposto, meu primeiro pensamento foi empacotar os dados em bits, para que esses 6 bits redundantes não sejam desperdiçados em todas as palavras. No entanto, pensei que, se eu usar alguma codificação de entropia (por exemplo, Huffman etc.), essa redundância será automaticamente levada em consideração, para que não seja necessário empacotamento extra. Então, eu fiz o seguinte:
- Tomou diferença binária entre dois quadros consecutivos. O intervalo de dados original era de 0 a 1023 (por exemplo, 10 bits não assinados). Os dados de diferença são assinados e o intervalo aumenta para -1023 ~ 1023, mas a variação de dados (ou qual é o termo matemático correto) se torna muito menor do que nos dados originais; na verdade, a maioria dos valores é, sem surpresa, próxima de zero .
- Arroz aplicado codificação à diferença. Pelo que entendi, parece uma boa opção para conjuntos de dados com valores numéricos principalmente pequenos.
Isso me dá cerca de 60% de redução no tamanho dos quadros de 1280x720, e meu sistema de teste (Linux no VirtualBox em um único núcleo) pode fazer ~ 40 dessas compressões por segundo (sem muita otimização). Não é tão bom, mas razoável, eu acho (ou é?).
Existem maneiras melhores? Algum erro comum que cometi? Alguma etapa geral que eu perdi? Quadros com resolução mais alta podem ser usados posteriormente - devo esperar melhores taxas de compactação para tamanhos de quadro maiores?
UPD .:
- Eu usei esta biblioteca para codificação Rice. A biblioteca é muito lenta (o próprio autor a descreve como algo para aprender e não para uso real), por exemplo, lê e grava bits um por um em loops, o que prejudica o desempenho. Inicialmente, ele me deu apenas 20 FPS, depois de uma otimização muito básica, tornou-se 40 FPS (conforme relatado acima), depois eu o otimizei mais, tornou-se 80. Isso é em um único núcleo i7 sem vetorização.
- Quanto à vetorização, infelizmente, não consegui pensar em uma maneira de vetorizar o código Rice (nem sei se é possível - não consegui encontrar nenhum dado sobre o código Rice, o que pude encontrar sobre o código Huffman sugere que é seqüencial e não pode ser vetorizado com eficiência, o que pode se aplicar ao código Rice, bem como a outros códigos de comprimento variável).
- Eu também tentei uma abordagem completamente diferente: divida os dados em pedaços pequenos (por exemplo, como 64 pixels cada) e use a supressão de zero simples. Encontramos o maior número em um bloco, escrevemos o número de bits necessários para representá-lo no início do bloco (4 bits adicionais foram necessários para isso, no meu caso) e reduzimos todos os números no bloco para o mesmo número de bits. bits. Eu esperava que a taxa de compactação fosse ruim, mas se as peças forem pequenas, muitas delas não terão picos de ruído; portanto, sua diferença binária pode ser reduzida para algo entre 4 e 6 bits por valor, e era, de fato, apenas cerca de 5% pior do que o código de Rice, embora seja duas vezes mais rápido (por exemplo, 160 FPS no meu caso). Eu tentei vetorizá-lo, mas eu meio que sou péssimo em vetorização, então talvez por isso eu tenha conseguido apenas cerca de x 1,8 de maior velocidade.
Como os números negativos não têm zeros à esquerda, apliquei a codificação em zigue-zague após a diferença binária e antes da supressão de Rice / zero.