Ho un video proveniente da una telecamera fissa. Sia la risoluzione che l'FPS sono piuttosto elevati. I dati che ottengo sono in formato Bayer e usano 10 bit per pixel. Poiché non esiste un tipo di dati a 10 bit sulla mia piattaforma, i dati originali vengono archiviati in memoria utilizzando parole a 16 bit. Voglio implementare una sorta di compressione senza perdita di dati prima di trasmetterli su una rete.
- La fotocamera non si muove, quindi grandi parti di fotogrammi consecutivi sono quasi identiche, ma ancora non del tutto, a causa dell'inevitabile rumore (il denoising non è un'opzione, in quanto si suppone che sia privo di perdite e non dovrebbe "perdere" anche il rumore ).
- A causa dell'elevato FPS, anche le parti che cambiano non cambiano molto tra due fotogrammi consecutivi.
- Tuttavia, sembra che anche la fotocamera scuoti leggermente. Molto poco, ma comunque, anche gli oggetti fissi non sono completamente nello spazio dell'immagine.
- La compressione deve essere eseguita al volo, quindi non riesco a raccogliere molti frame e comprimerli tutti insieme, ma posso guardare 1 frame indietro e usarlo come riferimento.
Sulla base di quanto sopra, il mio primo pensiero è stato di impacchettare i dati in modo che quei 6 bit ridondanti non vengano sprecati in ogni parola. Tuttavia, ho pensato che se avessi usato un po 'di codice entropico (ad es. Huffman ecc.), La ridondanza sarebbe stata automaticamente presa in considerazione, quindi non è necessario alcun imballaggio extra. Quindi ho fatto quanto segue:
- Ha preso la differenza binaria tra due frame consecutivi. L'intervallo di dati originale era 0 ~ 1023 (ad es. 10 bit senza segno). I dati della differenza vengono firmati e l'intervallo aumenta a -1023 ~ 1023, ma la variazione dei dati (o qual è il termine matematico corretto) diventa molto inferiore rispetto ai dati originali, infatti, la maggior parte dei valori sono, non sorprendentemente, vicini allo zero .
- Codifica del riso applicata sulla differenza. Da quello che ho capito, sembra una buona scelta per set di dati con valori numerici prevalentemente piccoli.
Questo mi dà circa il 60% di riduzione delle dimensioni per i frame 1280x720 e il mio sistema di test (Linux in VirtualBox su un singolo core) può fare ~ 40 di tali compressioni al secondo (senza molta ottimizzazione). Non eccezionale, ma ragionevole, suppongo (o è?).
Ci sono modi migliori? Qualche errore comune che ho fatto? Qualche passo generale che ho perso? In futuro è possibile utilizzare frame con risoluzione più elevata: è necessario prevedere tassi di compressione migliori per frame di dimensioni maggiori?
UPD .:
- Ho usato questa libreria per la codifica Rice. La libreria è molto lenta (l'autore stesso la descrive come qualcosa per l'apprendimento piuttosto che per un uso reale), ad esempio legge e scrive bit uno a uno in loop, il che uccide le prestazioni. Inizialmente mi ha dato solo ~ 20 FPS, dopo un po 'di ottimizzazione di base è diventato 40 FPS (come riportato sopra), poi l'ho ottimizzato ancora, è diventato 80. Questo è su un singolo core i7 senza vettorializzazione.
- Per quanto riguarda la vettorializzazione, però, sfortunatamente non riuscivo a pensare a un modo per vettorializzare il codice Rice (non so nemmeno se fosse possibile - non sono riuscito a trovare alcun dato sul codice Rice, ciò che ho trovato sul codice Huffman suggerisce che è sequenziale e non può essere vettorializzato in modo efficiente, che può essere applicato al codice Rice e ad altri codici a lunghezza variabile).
- Ho anche provato un approccio completamente diverso: dividere i dati in piccoli pezzi (ad esempio come 64 pixel ciascuno) e utilizzare la semplice soppressione zero. Troviamo il numero più grande in un blocco, scriviamo il numero di bit richiesti per rappresentarlo all'inizio del blocco (sono stati necessari 4 bit aggiuntivi per questo, nel mio caso), quindi riduciamo tutti i numeri nel blocco allo stesso numero di bit. Mi aspettavo che il tasso di compressione fosse cattivo, ma se i pezzi sono piccoli, molti di loro non avranno picchi di rumore, quindi la loro differenza binaria può essere ridotta a qualcosa come 4 ~ 6 bit per valore, ed era, in effetti, solo circa il 5% peggiore di quello del codice Rice, pur essendo circa il doppio più veloce (ad esempio 160 FPS nel mio caso). Ho provato a vettorializzarlo, ma faccio un po 'schifo alla vettorializzazione, quindi forse per questo ho potuto ottenere solo circa 1,8 di ulteriore accelerazione.
Poiché i numeri negativi non hanno zeri iniziali, ho applicato la codifica a zigzag dopo la differenza binaria e prima della soppressione di Rice / zero.