J'ai une vidéo provenant d'une caméra fixe. La résolution et le FPS sont assez élevés. Les données que j'obtiens sont au format Bayer et utilisent 10 bits par pixel. Comme il n'y a pas de type de données 10 bits sur ma plateforme, les données d'origine sont stockées en mémoire à l'aide de mots 16 bits. Je veux implémenter une sorte de compression sans perte des données avant de les transmettre sur un réseau.
- La caméra ne bouge pas, donc de grandes parties d'images consécutives sont presque identiques - mais toujours pas complètement, en raison du bruit inévitable (le débruitage n'est pas une option, car il est censé être sans perte et ne devrait pas "perdre" même le bruit ).
- En raison du FPS élevé, même les parties qui changent ne changent pas beaucoup entre deux images consécutives.
- Cependant, il semble que l'appareil photo tremble également un peu. Très peu, mais quand même, même les objets stationnaires ne le sont pas complètement dans l'espace image.
- La compression doit être effectuée à la volée, donc je ne peux pas rassembler beaucoup d'images et les compresser toutes ensemble, mais je peux regarder 1 image en arrière et l'utiliser comme référence.
Sur la base de ce qui précède, ma première pensée a été de compresser les données en bits, afin que ces 6 bits redondants ne soient pas gaspillés sur chaque mot. Cependant, je pensais que si j'utilisais du codage entropique (par exemple Huffman, etc.), cette redondance serait automatiquement prise en compte, donc aucun emballage supplémentaire n'est nécessaire. J'ai donc fait ce qui suit:
- Pris la différence binaire entre deux images consécutives. La plage de données d'origine était comprise entre 0 et 1023 (par exemple, 10 bits non signés). Les données de différence sont signées et la plage augmente à -1023 ~ 1023, mais la variation des données (ou quel est le terme mathématique correct) devient beaucoup moins que dans les données d'origine, en fait, la plupart des valeurs sont, sans surprise, proches de zéro .
- Codage du riz appliqué à la différence. D'après ce que je comprends, cela semble être un bon choix pour des ensembles de données de valeurs numériques généralement petites.
Cela me donne une réduction d'environ 60% de la taille des images 1280x720, et mon système de test (Linux dans VirtualBox sur un seul cœur) peut effectuer environ 40 compressions de ce type par seconde (sans beaucoup d'optimisation). Pas génial, mais raisonnable, je suppose (ou n'est-ce pas?).
Y a-t-il de meilleures façons? Des erreurs courantes que j'ai faites? Des étapes générales que j'ai manquées? Des images de plus haute résolution peuvent être utilisées plus tard - dois-je m'attendre à de meilleurs taux de compression pour des images plus grandes?
UPD .:
- J'ai utilisé cette bibliothèque pour l'encodage Rice. La bibliothèque est très lente (l'auteur lui-même la décrit comme quelque chose pour l'apprentissage plutôt que pour une utilisation réelle), par exemple, elle lit et écrit les bits un par un en boucle, ce qui tue les performances. Initialement, cela ne m'a donné que ~ 20 FPS, après une optimisation très basique, il est devenu 40 FPS (comme indiqué ci-dessus), plus tard, je l'ai optimisé un peu plus, il est devenu 80. C'est sur un seul cœur i7 sans vectorisation.
- En ce qui concerne la vectorisation, cependant, je ne pouvais malheureusement pas penser à un moyen de vectoriser le code Rice (je ne sais même pas si c'est possible - je n'ai pas trouvé de données sur le code Rice, ce que j'ai pu trouver sur le code Huffman suggère que il est séquentiel et ne peut pas être efficacement vectorisé, ce qui peut s'appliquer au code Rice ainsi qu'à d'autres codes de longueur variable).
- J'ai également essayé une approche complètement différente: diviser les données en petits morceaux (par exemple, comme 64 pixels chacun) et utiliser la suppression du zéro simple. Nous trouvons le plus grand nombre dans un bloc, écrivons le nombre de bits requis pour le représenter au début du bloc (4 bits supplémentaires étaient nécessaires pour cela, dans mon cas), puis réduisons tous les nombres du bloc au même nombre de morceaux. Je m'attendais à ce que le taux de compression soit mauvais, mais si les morceaux sont petits, beaucoup d'entre eux n'auront pas de pics de bruit, donc leur différence binaire peut être réduite à quelque chose comme 4 ~ 6 bits par valeur, et ce n'était, en fait, que environ 5% pire que celui du code Rice, tout en étant environ deux fois plus rapide (par exemple 160 FPS pour mon cas). J'ai essayé de le vectoriser, mais j'aspire un peu à la vectorisation, donc peut-être à cause de cela, je ne pouvais atteindre que x1.8 d'accélération supplémentaire.
Parce que les nombres négatifs n'ont pas de zéros en tête, j'ai appliqué le codage en zigzag après la différence binaire et avant la suppression de Rice / zéro.