快速无损压缩视频流


14

我有一个来自固定相机的视频。分辨率和FPS都很高。我得到的数据为拜耳格式,每个像素使用10位。由于我的平台上没有10位数据类型,因此原始数据使用16位字存储在内存中。我想在通过网络传输数据之前对数据进行某种无损压缩

  • 摄像头不会移动,因此连续帧的大部分几乎是相同的-但由于不可避免的噪声,仍不能完全消除(降噪不是一种选择,因为降噪是无损的,即使噪声也不应“丢失” )。
  • 由于FPS高,即使变化的部分在任何两个连续的帧之间也变化不大。
  • 但是,看起来相机也有些晃动。在图像空间中,即使很小,但即使静止的物体也并非完全如此。
  • 压缩必须实时进行,因此我不能收集很多帧并将它们全部压缩在一起,但是我可以向后看一帧并将其用作参考。

基于以上所述,我的第一个想法是对数据进行位打包,以使这6个冗余位不会浪费在每个字上。但是,我认为如果使用某种熵编码(例如Huffman等),则会自动考虑冗余,因此不需要额外的包装。所以我做了以下工作:

  • 取得两个连续帧之间的二进制差异。原始数据范围为0〜1023(例如,无符号10位)。差异数据变为有符号,范围增加到-1023〜1023,但数据变化(或正确的数学术语)变得比原始数据少得多,实际上,大多数值不足为零就不足为奇了。
  • 将Rice编码应用于差异。据我了解,对于大多数数值较小的数据集,这似乎是一个不错的选择。

对于1280x720帧,这使我的尺寸减少了60%,并且我的测试系统(单核上的VirtualBox中的Linux)每秒可以进行约40次此类压缩(无需太多优化)。我猜不是那么好,但是很合理(或者是吗?)。

有更好的方法吗?我有任何常见的错误吗?我错过了任何常规步骤吗?以后可能会使用更高分辨率的帧-对于更大的帧大小,我应该期望更好的压缩率吗?

UPD:

  • 我使用此库进行Rice编码。该库非常慢(作者本人将其描述为学习而不是实际使用),例如,它在循环中一对一地读写位,这会降低性能。最初它只给我约20 FPS,经过一些非常基本的优化后,它变成了40 FPS(如上所述),后来我对其进行了更多优化,变成了80 FPS。这是在没有向量化的单个i7内核上。
  • 至于向量化,不幸的是,我无法想到一种对Rice代码进行向量化的方法(甚至根本不知道它是否可能-在Rice代码上找不到任何数据,我对霍夫曼代码的发现表明:它是顺序的,无法有效地向量化,这可能适用于Rice代码以及其他可变长度代码)。
  • 我还尝试了一种完全不同的方法:将数据分成小块(例如,每个像素为64像素)并使用简单的零抑制。我们找到一个块中最大的数字,将表示它所需的位数写到该块的开头(在我的情况下,这需要再增加4位),然后将该块中的所有数字减少到相同的位数。位。我预计压缩率会很差,但是如果片段很小,那么它们中的许多都不会产生噪声尖峰,因此它们的二进制差异可以减小到每个值4〜6位,实际上只有比Rice代码差5%左右,但速度大约是Rice代码的两倍(例如我的情况下为160 FPS)。我曾尝试对其进行矢量化处理,但对矢量化处理还是有点不满,所以也许正因为如此,我只能实现约1.8倍的进一步加速。

由于负数没有前导零,因此我在二进制差之后和莱斯/零抑制之前应用了之字形编码


您可以使用支持10位模式的标准编解码器(例如h264)。“将-crf或-qp设置为0将强制x264在无损模式下-preset设置然后仅影响速度/尺寸比。” (但我不知道它是否会管理实时性能)
CodesInChaos

@CodesInChaos,仅两帧就能完成很多工作吗?
Headcrab

也许甚至更重要的是-标准编解码器甚至可以对拜耳图像进行编码吗?如果我没记错的话,将Bayer转换为RGB涉及插值,因此是不可逆的。
Headcrab

Answers:


4

您具有时间预测,但没有空间预测。为了以速度为代价进行更好的压缩,您应该能够将当前帧中当前像素上方和左侧的像素用作预测变量,以及前一帧中相同位置的像素。只向上看和左看的原因与只看前一帧的原因相同。您只希望依赖已解码的数据,并限制必须保留的数据量。

莱斯代码可能是效率和速度之间的良好折衷,但是静态霍夫曼代码(由您根据视频数据样本预先计算出)可能更高效且同样快。

至于速度,请确保您的代码已被矢量化 -通过使用正确的编译器标志和代码模式以允许编译器自动矢量化,或通过手写代码以使用矢量内在函数或汇编代码。

最后,是否有可能将每个像素降低到8位?显然,这已成为“无损”领域,但它不仅会减少压缩输出的大小,而且使用矢量化代码还可能使吞吐量提高两倍。


我猜不可能将10bpp减小到8,但是有可能以较少的位存储增量,这与UTF-8使用1个字节或有时2个字节存储字符的方式大致相同。如果增量一直都接近于0,那么很难看到所有10位都发生变化,因此值得花1或2个字节来存储它们。
gbjbaanb

Rice编码完成了@gbjbaanb。大多数增量将很小,因此仅使用一些位。
hobbs

@hobbs,通过“空间预测”,您是说x5要用差异替换像素值(x5 - x4)吗?
Headcrab

@Headcrab-我之前使用过的一种方法是使用前一像素的中值以及当前帧中上方和左侧的像素。
Jules'July

@Jules如果某个像素被周围像素的某种中间值代替,是否可以恢复其原始值?
Headcrab

0

使用现有的压缩和解压缩实现可能会为您提供最佳服务。您现有的实现似乎类似于HuffYUV编解码器,因此可能值得尝试一下,看看它是否对您足够好。


libx264“预设超快速”在历史上对我非常
有用

@rogerdpack-值得注意的是,libx264的无损编码设置导致输出不符合H.264标准,并在某些播放器上中断。但这至少对OP的应用程序有用。
Jules

有趣的是,您有任何链接吗?错误报告?还要注意,用HuffyYUV编码的视频可能也不是“单人播放器友好的”,我想像过:)
rogerdpack
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.