Archive

Posts Tagged ‘视频’

如何写一个视频编码器演示篇

December 24th, 2015 2 comments

先前写过《视频编码原理简介》,有朋友问光代码和文字不太真切,能否补充几张图片,今天我们演示一下:

这是第一帧画面:P1(我们的参考帧)

output1

这是第二帧画面:P2(需要编码的帧)

output2

从视频中截取的两张间隔1-2秒的画面,和实际情况类似,下面我们参考P1进行几次运动搜索:

搜索演示1:搜索P2中车辆的车牌在P1中最接近的位置(上图P1,下图P2)

search1

这是一个演示程序,鼠标选中P2上任意16×16的Block,即可搜索出P1上的 BestMatch 宏块。虽然车辆在运动,从远到近,但是依然找到了最接近的宏块坐标。

(点击 more 阅读剩下内容)

Read more…

Categories: 编程技术 Tags:

视频编码原理简介

November 24th, 2015 2 comments

要彻底理解视频编码原理,看书都是虚的,需要实际动手,实现一个简单的视频编码器:

知识准备:基本图像处理知识,信号的时域和频域问题,熟练掌握傅立叶正反变换,一维、二维傅立叶变换,以及其变种,dct变换,快速dct变换。

来自知乎问题:http://www.zhihu.com/question/22567173/answer/73610451 

第一步:实现有损图像压缩和解压

参考 JPEG原理,将RGB->YUV,然后Y/U/V看成三张不同的图片,将其中一张图片分为 8×8的block进行 dct变换(可以直接进行二维dct变换,或者按一定顺序将8×8的二维数组整理成一个64字节的一维数组),还是得到一个8×8的整数频率数据。于是表示图像大轮廓的低频信号(人眼敏感的信号)集中在 8×8的左上角;表示图像细节的高频信号集中在右下角。

接着将其量化,所谓量化,就是信号采样的步长,8×8的整数频率数据块,每个数据都要除以对应位置的步长,左上角相对重要的低频信号步长是1,也就是说0-255,是多少就是多少。而右下角是不太重要的高频信号,比如步长取10,那么这些位置的数据都要/10,实际解码的时候再将他们*10恢复出来,这样经过编码的时候/10和解码的时候*10,那么步长为10的信号1, 13, 25, 37就会变成规矩的:0, 10, 20, 30, 对小于步长10的部分我们直接丢弃了,因为高频不太重要。

经过量化以后,8×8的数据块左上角的数据由于步长小,都是比较离散的,而靠近右下角的高频数据,都比较统一,或者是一串0,因此图像大量的细节被我们丢弃了,这时候,我们用无损压缩方式,比如lzma2算法(jpeg是rle + huffman)将这64个byte压缩起来,由于后面高频数据步长大,做了除法以后,这些值都比较小,而且比较靠近,甚至右下部分都是一串0,十分便于压缩。

JPEG图像有个问题就是低码率时 block边界比较严重,现代图片压缩技术往往要配合一些de-block算法,比如最简单的就是边界部分几个像素点和周围插值模糊一下。

做到这里我们实现了一个同 jpeg类似的静态图片有损压缩算法。在视频里面用来保存I帧数据。

第二步:实现宏块误差计算

视频由连续的若干图像帧组成,分为 I帧,P帧,所谓I帧,就是不依赖就可以独立解码的视频图像帧,而P帧则需要依赖前面已解码的视频帧,配合一定数据才能生成出来。所以视频中I帧往往都比较大,而P帧比较小,如果播放器一开始收到了P帧那么是无法播放的,只有收到下一个I帧才能开始播放。I帧多了视频就变大,I帧少了,数据量是小了,但视频受到丢包或者数据错误的影响却又会更严重。

那么所谓运动预测编码,其实就是P帧的生成过程:继续将图片分成 16×16的block(为了简单只讨论yuv的y分量压缩)。I帧内部单帧图片压缩我们采用了8×8的block,而这里用16×16的block来提高帧间编码压缩率(当然也会有更多细节损失),我们用 x, y表示像素点坐标,而s,t表示block坐标,那么坐标为(x,y)的像素点所属的block坐标为:

s = x / 16 = x >> 4
t = y / 16 = y >> 4

接着要计算两个block的相似度,即矢量的距离,可以表示为一个256维矢量(16×16)像素点色彩距离的平方,我们先定义两个颜色的误差为:

PixelDiff(c1, c2) = (c1- c2) ^ 2

Read more…

Categories: 编程技术 Tags: