Compressione rapida e senza perdita di un flusso video


14

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.


È possibile utilizzare un codec standard come h264 che supporta una modalità a 10 bit. "L'impostazione di -crf o -qp su 0 forza x264 in modalità lossless le impostazioni -preset quindi influiscono solo sul rapporto velocità / dimensioni." (Ma non so se riuscirà a gestire le prestazioni in tempo reale)
CodesInChaos

@CodesInChaos, farebbe molto per solo due frame?
Headcrab

Forse, ancora più importante, i codec standard possono persino codificare le immagini Bayer? Se non sbaglio, la conversione di Bayer in RGB comporta interpolazione ed è quindi irreversibile.
Headcrab,

Risposte:


4

Hai una previsione temporale, ma non spaziale. Per una migliore compressione a costo della velocità, dovresti essere in grado di utilizzare i pixel sopra e a sinistra del pixel corrente nel fotogramma corrente come predittori, nonché il pixel nella stessa posizione nel fotogramma precedente. Il motivo per guardare solo a sinistra e in alto è lo stesso del motivo per guardare solo al fotogramma precedente; vuoi fare affidamento solo sui dati che hai già decodificato e limitare la quantità di dati che devi conservare.

I codici Rice sono probabilmente un buon compromesso tra efficienza e velocità, ma un codice Huffman statico (precompilato da te su un campione di dati video) potrebbe essere più efficiente e altrettanto veloce.

Per quanto riguarda la velocità, assicurati che il tuo codice venga vettorializzato - utilizzando i flag e i modelli di codice corretti per consentire al compilatore di auto-vettorizzare o scrivendo a mano il codice per utilizzare intrinseci vettoriali o assembly.

Infine, è possibile scendere a 8 bit per pixel? Ovviamente questo sta lasciando il regno di "senza perdita", ma non solo ridurrebbe le dimensioni dell'output compresso, ma potrebbe anche, con un codice vettoriale, aumentare il throughput fino a 2 volte.


Immagino che ridurre 10bpp a 8 non sia possibile, ma potrebbe essere possibile memorizzare i delta in meno bit, più o meno allo stesso modo in cui UTF-8 usa 1 o talvolta 2 byte per memorizzare un carattere. Se i delta sono quasi 0 per tutto il tempo, sarebbe piuttosto raro vedere tutti i 10 bit cambiare, e quindi vale la pena di determinare 1 o 2 byte per memorizzarli.
gbjbaanb,

@gbjbaanb è ciò che realizza la codifica Rice. La maggior parte dei delta sarà di piccole dimensioni e quindi utilizzerà solo pochi bit.
Hobbs,

@hobbs, per "previsione spaziale" intendi qualcosa come sostituire un valore di pixel x5con la differenza (x5 - x4)?
Headcrab

@Headcrab - un approccio che ho visto usato prima è quello di utilizzare il valore mediano del pixel precedente e i pixel sopra e a sinistra nel fotogramma corrente.
Jules il

@Jules se un pixel viene sostituito da una sorta di valore mediano dei pixel circostanti, è possibile ripristinare il suo valore originale?
Headcrab,

0

Probabilmente sei meglio servito usando le implementazioni esistenti di compressione e decompressione. L'implementazione esistente sembra simile al codec HuffYUV , quindi potrebbe valere la pena provarlo per vedere se funziona abbastanza bene per te.


libx264 "preset ultrafast" mi è servito abbastanza bene storicamente FWIW ...
rogerdpack

@rogerdpack - Vale la pena notare che l'impostazione di libx264 per la codifica lossless produce un output che non è conforme a H.264 e si rompe su alcuni lettori. Ma potrebbe essere utile almeno per l'applicazione del PO.
Jules

interessante hai qualche link a quello? Riportare un errore? Nota anche che un video codificato con HuffyYUV probabilmente non è "uni player friendly", immagino :)
rogerdpack
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.