运动估计与运动补偿.docx
《运动估计与运动补偿.docx》由会员分享,可在线阅读,更多相关《运动估计与运动补偿.docx(24页珍藏版)》请在冰豆网上搜索。
运动估计与运动补偿
运动估计与运动补偿
运动补偿是通过先前的局部图像来预测、补偿当前的局部图像,它是减少帧序列冗余信息的有效方法。
运动估计是从视频序列中抽取运动信息的一整套技术。
运动估计与运动补偿技术
MPEG-4采用I-VOP、P-VOP、B-VOP三种帧格式来表征不同的运动补偿类型。
它采用了H.263中的半像素搜索(halfpixelsearching)技术和重叠运动补偿(overlappedmotioncompensation)技术,同时又引入重复填充(repetitivepadding)技术和修改的块(多边形)匹配(modifiedblock(polygon)matching)技术以支持任意形状的VOP区域。
此外,为提高运动估计算法精度,MPEG-4采用了MVFAST(MotionVectorFieldAdaptiveSearchTechnique)和改进的PMVFAST(PredictiveMVFAST)方法用于运动估计。
对于全局运动估计,则采用了基于特征的快速顽健的FFRGMET(Feature-basedFastandRobustGlobalMotionEstimationTechnique)方法。
编解码器用来减少视频序列中的空域冗余。
它也可以用来进行去交织(deinterlacing)的操作。
定义
运动补偿是通过先前的局部图像来预测、补偿当前的局部图像,它是减少帧序列冗余信息的有效方法。
分类
包括全局运动补偿和分块运动补偿两类。
运动补偿是一种描述相邻帧(相邻在这里表示在编码关系上相邻,在播放顺序上两帧未必相邻)差别的方法,具体来说是描述前面一帧(相邻在这里表示在编码关系上的前面,在播放顺序上未必在当前帧前面)的每个小块怎样移动到当前帧中的某个位置去。
这种方法经常被视频压缩/视频编解码器用来减少视频序列中的空域冗余。
它也可以用来进行去交织(deinterlacing)的操作。
一个视频序列包含一定数量的图片--通常称为帧。
相邻的图片通常很相似,也就是说,包含了很多冗余。
使用运动补偿的目的是通过消除这种冗余,来提高压缩比。
最早的运动补偿
早期解析
最早的运动补偿的设计只是简单的从当前帧中减去参考帧,从而得到通常含有较少能量(或者成为信息)的"残差",从而可以用较低的码率进行编码。
解码器可以通过简单的加法完全恢复编码帧。
一个稍微复杂一点的设计是估计一下整帧场景的移动和场景中物体的移动,并将这些运动通过一定的参数编码到码流中去。
这样预测帧上的像素值就是由参考帧上具有一定位移的相应像素值而生成的。
这样的方法比简单的相减可以获得能量更小的残差,从而获得更好的压缩比--当然,用来描述运动的参数不能在码流中占据太大的部分,否则就会抵消复杂的运动估计带来的好处。
通常,图像帧是一组一组进行处理的。
每组的第一帧(通常是第一帧)在编码的时候不使用运动估计的办法,这种帧称为帧内编码帧(Intraframe)或者I帧。
该组中的其它帧使用帧间编码帧(Interframe),通常是P帧。
这种编码方式通常被称为IPPPP,表示编码的时候第一帧是I帧,其它帧是P帧。
在进行预测的时候,不仅仅可以从过去的帧来预测当前帧,还可以使用未来的帧来预测当前帧。
当然在编码的时候,未来的帧必须比当前帧更早的编码,也就是说,编码的顺序和播放的顺序是不同的。
通常这样的当前帧是使用过去和未来的I帧或者P帧同时进行预测,被称为双向预测帧,即B帧。
这种编码方式的编码顺序的一个例子为IBBPBBPBBPBB。
全局运动补偿
运动模型基本上就是反映摄像机的各种运动,包括平移,旋转,变焦等等。
这种模型特别适合对没有运动物体的静止场景的编码。
全局运动补偿有下面的一些优点:
该模型仅仅使用少数的参数对全局的运行进行描述,参数所占用的码率基本上可以忽略不计。
该方法不对帧进行分区编码,这避免了分区造成的块效应。
在时间方向的一条直线的点如果在空间方向具有相等的间隔,就对应了在实际空间中连续移动的点。
其它的运动估计算法通常会在时间方向引入非连续性。
但是,缺点是,如果场景中有运动物体的话,全局运动补偿就不足以表示了。
这时候应该选用其它的方法。
分块运动补偿
每帧被分为若干像素块(在大多数视频编码标准,如MPEG中,是分为16x16的像素块)。
从参考帧的某个位置的等大小的块对当前块进行预测,预测的过程中只有平移,平移的大小被称为运动矢量。
对分块运动补偿来说,运动矢量是模型的必要参数,必须一起编码加入码流中。
由于运动矢量之间并不是独立的(例如属于同一个运动物体的相邻两块通常运动的相关性很大),通常使用差分编码来降低码率。
这意味着在相邻的运动矢量编码之前对它们作差,只对差分的部分进行编码。
使用熵编码对运动矢量的成分进行编码可以进一步消除运动矢量的统计冗余(通常运动矢量的差分集中于0矢量附近)。
运动矢量的值可以是非整数的,此时的运动补偿被称为亚像素精度的运动补偿。
这是通过对参考帧像素值进行亚像素级插值,而后进行运动补偿做到的。
最简单的亚像素精度运动补偿使用半像素精度,也有使用1/4像素和1/8像素精度的运动补偿算法。
更高的亚像素精度可以提高运动补偿的精确度,但是大量的插值操作大大增加了计算复杂度。
缺点
分块运动补偿的一个大缺点在于在块之间引入的非连续性,通常称为块效应。
当块效应严重时,解码图像看起来会有像马赛克一样的效果,严重影响视觉质量。
另外一个缺点是,当高频分量较大时,会引起振铃效应。
关于高频分量,请参见对运动补偿后的残差进行变换的方法:
变换编码。
在MPEG-4视频编码中,运动估计相当耗时,对编码的实时性影响很大。
因此这里特别强调快速算法。
运动估计方法主要有像素递归法和块匹配法两大类,前者复杂度很高,实际中应用较少,后者则在H.263和MPEG中广泛采用。
在块匹配法中,重点研究块匹配准则及搜索方法。
目前有三种常用的匹配准则:
(1)绝对误差和(SAD,SumofAbsoluteDifference)准则;
(2)均方误差(MSE,MeanSquareError)准则;
(3)归一化互相关函数(NCCF,NormalizedCrossCorrelationFunction)准则。
在上述三种准则中,SAD准则具有不需乘法运算、实现简单方便的优点而使用最多,但应清楚匹配准则的选用对匹配结果影响不大。
在选取匹配准则后就应进行寻找最优匹配点的搜索工作。
最简单、最可靠的方法是全搜索法(FS,FullSearch),但计算量太大,不便于实时实现。
因此快速搜索法应运而生,主要有交叉搜索法、二维对数法和钻石搜索法,其中钻石搜索法被MPEG-4校验模型(VM,VerificationModel)所采纳,下面详细介绍。
钻石搜索(DS,DiamondSearch)法以搜索模板形状而得名,具有简单、鲁棒、高效的特点,是现有性能最优的快速搜索算法之一。
其基本思想是利用搜索模板的形状和大小对运动估计算法速度及精度产生重要影响的特性。
在搜索最优匹配点时,选择小的搜索模板可能会陷入局部最优,选择大的搜索模板则可能无法找到最优点。
因此DS算法针对视频图像中运动矢量的基本规律,选用了两种形状大小的搜索模板。
·大钻石搜索模板(LDSP,LargeDiamondSearchPattern),包含9个候选位置;
·小钻石搜索模板(SDSP,SmallDiamondSearchPattern),包含5个候选位置。
DS算法搜索过程如下:
开始阶段先重复使用大钻石搜索模板,直到最佳匹配块落在大钻石中心。
由于LDSP步长大,因而搜索范围广,可实现粗定位,使搜索不会陷于局部最小,当粗定位结束后,可认为最优点就在LDSP周围8个点所围菱形区域中。
然后再使用小钻石搜索模板来实现最佳匹配块的准确定位,以不产生较大起伏,从而提高运动估计精度。
此外Sprite视频编码技术也在MPEG-4中应用广泛,作为其核心技术之一。
Sprite又称镶嵌图或背景全景图,是指一个视频对象在视频序列中所有出现部分经拼接而成的一幅图像。
利用Sprite可以直接重构该视频对象或对其进行预测补偿编码。
Sprite视频编码可视为一种更为先进的运动估计和补偿技术,它能够克服基于固定分块的传统运动估计和补偿技术的不足,MPEG-4正是采用了将传统分块编码技术与Sprite编码技术相结合的策略。
运动估计
两帧之间的物体运动是平移运动,位移量不是很很大,所以会以块作为单位分配运动矢量,在运动估计中采用了大量的参考帧预测来提高精度,当前的待编码块可以在缓存内的所有重建帧中寻找最优的匹配块进行运动补偿,以便很好的去除时间域的冗余度。
为每一个块寻求一个运动矢量MV,并进行运动补偿预测编码。
在每个分割区域中都有其对应的运动矢量,并对运动矢量以及块的选择方式进行编码和传输。
运动估计ME所表达的运动矢量MV,其研究的内容就是如何加速,有效的获得足够精确的mv,并且把前一帧所得的运动信息通过运动补偿MC来进行变换,量化编码,最后输出。
缩写含义:
me得到的是mV
预测得到的是mvp
差值是mvdMV:
运动向量,参考帧中相对于当前帧的偏移
MVp:
参考运动向量
MVD:
两个向量间的差别
提高运动估计算法的效率的主要技术有:
初始搜索点的选择,匹配准则,和运动搜索策略。
1.运动估计初始点的搜索:
1)直接选择参考帧对应块的中心位置,这种方法简单,但容易陷入局部最优点,如果初始的步长太大,而原点(指待搜索块的中心点在参考帧中的相同位置的对应点)不是最优点时候,可能使快速搜索跳出原点周围的区域,而去搜索较远的点,导致搜索方向的不确定性,陷入局部最优。
2)选择预测的起点,以预测点作为搜索的起点,
x264采用的将运动估计矢量和参考帧的左边,上边和右上边的MB的中值MV作为起点进行ME。
2.匹配准则,
x264中所采用的匹配准则是SAD,SATD.SAD即绝对误差和,仅反映残差时域差异,影响PSNR值,不能有效反映码流的大小。
SATD即将残差经哈德曼变换的4×4块的预测残差绝对值总和,可以将其看作简单的时频变换,其值在一定程度上可以反映生成码流的大小。
因此,不用率失真最优化时,可将其作为模式选择的依据。
一般帧内要对所有的模式进行检测,帧内预测选用SATD.在做运动估计时,一般而言,离最优匹配点越远,匹配误差值SAD越大,这就是有名的单一平面假设,现有的运动估计快速算法大都利用该特性。
但是,转换后SATD值并不满足该条件,如果在整象素中运用SATD搜索,容易陷入局部最优点。
而在亚象素中,待搜索点不多,各点处的SAD差异相对不大,可以用SATD选择码流较少的匹配位置。
3.运动搜索策略
x264所采用的运动搜索策略(对应的最后面的程序中有描述):
#defineX264_ME_DIA0//钻石搜索
#defineX264_ME_HEX1//六边形所搜
#defineX264_ME_UMH2//非对称十字六边形网络搜索
#defineX264_ME_ESA3//全搜索
#defineX264_ME_TESA4//hadamard全搜索法,这个算法和ESA相比主要是在搜索范围上的变化
下面就在x264中的运动估计所涉及的函数进行跟踪:
ME的分析在函数x264_slice_write(x264_t*h)中的x264_macroblock_analyse(h);中:
进入这个函数:
由于对于I帧类型采用的帧内编码,这部分没有采用ME,所以对于I帧的分析略。
进入帧间类型(P/B)的分析中:
以P帧的16*16MB为例进行跟踪:
进入函数:
x264_mb_analyse_inter_p16x16(x264_t*h,x264_mb_analysis_t*a)
{//对参考帧中的所有16*16块进行分析
for(i_ref=0;i_refh-mb.pic.i_fref[0];i_ref++)
{
.
LOAD_HPELS(&m,h-mb.pic.p_fref[0][i_ref],0,i_ref,0,0);
x264_mb_predict_mv_16x16(h,0,i_ref,m.mvp);//下面的有详细的注释1x264_mb_predict_mv_ref16x16(h,0,i_ref,mvc,&i_mvc);//注释2x264_me_search_ref(h,&m,mvc,i_mvc,p_halfpel_thresh);//注释3
.
}
}
//注释1:
进行16*16的块的mv预测,得到运动估计的起始方向,并将获得的MV赋值给MVP,在下一步中使用
x264_mb_predict_mv_16x16(h,0,i_ref,m.mvp);
voidx264_mb_predict_mv_16x16(x264_t*h,inti_list,inti_ref,int16_tmvp[2])
{
inti_refa=h-mb.cache.ref[i_list][X264_SCAN8_0-1];//亮度左边块
int16_t*mv_a=h-mb.cache.mv[i_list][X264_SCAN8_0-1];
inti_refb=h-mb.cache.ref[i_list][X264_SCAN8_0-8];//亮度上边块
int16_t*mv_b=h-mb.cache.mv[i_list][X264_SCAN8_0-8];
inti_refc=h-mb.cache.ref[i_list][X264_SCAN8_0-8+4];//亮度的右上边块
int16_t*mv_c=h-mb.cache.mv[i_list][X264_SCAN8_0-8+4];
//当i_refc不存在时,就将i_refc赋值为左上边的块
if(i_refc==-2)
{
i_refc=h-mb.cache.ref[i_list][X264_SCAN8_0-8-1];
mv_c=h-mb.cache.mv[i_list][X264_SCAN8_0-8-1];
}
//看i_refa/b/c是否是在参考帧所对应中的那一块,若是i_count++,i_count是用来进行Mvp预测选择何种方式的一种标志
if(i_refa==i_ref)i_count++;
if(i_refb==i_ref)i_count++;
if(i_refc==i_ref)i_count++;
if(i_count1)
{
median:
x264_median_mv(mvp,mv_a,mv_b,mv_c);
}
elseif(i_count==1)
{
if(i_refa==i_ref)
*(uint32_t*)mvp=*(uint32_t*)mv_a;
elseif(i_refb==i_ref)
*(uint32_t*)mvp=*(uint32_t*)mv_b;
else
*(uint32_t*)mvp=*(uint32_t*)mv_c;
}
elseif(i_refb==-2&&i_refc==-2&&i_refa!
=-2)
*(uint32_t*)mvp=*(uint32_t*)mv_a;
elsegotomedian;
}
}
//注释2:
细化16*16块mv预测
x264_mb_predict_mv_ref16x16(h,0,i_ref,mvc,&i_mvc);
voidx264_mb_predict_mv_ref16x16(x264_t*h,inti_list,inti_ref,int16_tmvc[9][2],int*i_mvc)
{
//设运动补偿
#defineSET_MVP(mvp){\
*(uint32_t*)mvc[i]=*(uint32_t*)mvp;\
i++;\
}
.
//空间预测:
获取左边,上边和左上的mb的mvc[i],得到不同的类型的MVC,获得i个mvcif(h-mb.i_neighbour&MB_LEFT)
{
inti_mb_l=h-mb.i_mb_xy-1;
if(!
IS_SKIP(h-mb.type[i_mb_l]))
SET_MVP(mvr[i_mb_l]);
}
if(h-mb.i_neighbour&MB_TOP)
{
inti_mb_t=h-mb.i_mb_top_xy;
if(!
IS_SKIP(h-mb.type[i_mb_t]))
SET_MVP(mvr[i_mb_t]);
if(h-mb.i_neighbour&MB_TOPLEFT&&!
IS_SKIP(h-mb.type[i_mb_t-1]))
SET_MVP(mvr[i_mb_t-1]);
if(h-mb.i_mb_xh-mb.i_mb_stride-1&&!
IS_SKIP(h-mb.type[i_mb_t+1]))
SET_MVP(mvr[i_mb_t+1]);
}
//时间预测
//dx,dy表示在时间差上的参考帧上对应点的坐标差
#defineSET_TMVP(dx,dy){\
inti_b4=h-mb.i_b4_xy+dx*4+dy*4*h-mb.i_b4_stride;\
inti_b8=h-mb.i_b8_xy+dx*2+dy*2*h-mb.i_b8_stride;\
intref_col=l0-ref[0][i_b8];\
if(ref_col=0)\
{\
intscale=(h-fdec-i_poc-h-fdec-ref_poc[0][i_ref])*l0-inv_ref_poc[ref_col];\
mvc[i][0]=(l0-mv[0][i_b4][0]*scale+128)8;\
mvc[i][1]=(l0-mv[0][i_b4][1]*scale+128)8;\
i++;\
}\
}
}
//注释3x264_me_search_ref(h,&m,mvc,i_mvc,p_halfpel_thresh);
voidx264_me_search_ref(x264_t*h,x264_me_t*m,int16_t(*mvc)[2],inti_mvc,int*p_halfpel_thresh)
{
//初始化
.
bmx=x264_clip3(m-mvp[0],mv_x_min*4,mv_x_max*4);
bmy=x264_clip3(m-mvp[1],mv_y_min*4,mv_y_max*4);
//这些变量*4,或者左移2位,是因为要得到分数像素(1/4像素)
pmx=(bmx+2)2;
pmy=(bmy+2)2;
bcost=COST_MAX;
if(h-mb.i_subpel_refine=3)
{
uint32_tbmv=pack16to32_mask(bmx,bmy);
COST_MV_HPEL(bmx,bmy);//对COST_MV_HPEL目的:
获得最佳cost的坐标
for(i=0;ii_mvc;i++)
{
if(*(uint32_t*)mvc[i]&&(bmv-*(uint32_t*)mvc[i]))
{
intmx=x264_clip3(mvc[i][0],mv_x_min*4,mv_x_max*4);
intmy=x264_clip3(mvc[i][1],mv_y_min*4,mv_y_max*4);
COST_MV_HPEL(mx,my);
}
}
bmx=(bpred_mx+2)2;
bmy=(bpred_my+2)2;
COST_MV(bmx,bmy);
}
else
{
COST_MV(pmx,pmy);
bcost-=BITS_MVD(pmx,pmy);
for(i=0;ii_mvc;i++)
{
intmx=(mvc[i][0]+2)2;
intmy=(mvc[i][1]+2)2;
if((mx|my)&&((mx-bmx)|(my-bmy)))
{
mx=x264_clip3(mx,mv_x_min,mv_x_max);
my=x264_clip3(my,mv_y_min,mv_y_max);
COST_MV(mx,my);
}
}
}
COST_MV(0,0);
//下面是对me方式的选择switch语句:
#defineX264_ME_DIA0
#defineX264_ME_HEX1
#defineX264_ME_UMH2
#defineX264_ME_ESA3
#defineX264_ME_TESA4
//switch(h-mb.i_me_method)中的参数h-mb.i_me_method=h-param.analyse.i_me_method;
//根据用户的命令输入决定运动矢量的精度程度,根据空间相关性,用求出的左,上,左上的编码的宏块的//MV得到当前mb的mv的预测值mvp,以预测向量mvp的为初始原点,进行整数像素的搜索
caseX264_ME_DIA:
//钻石形搜索:
在do_while循环中,总是以一个菱形的形式进行搜索,只是原点发生变化,这个变化时有//bcost带来的,而坐标
//原点是有bmx,bmy的变化来获得:
//bmx,bmy的定义:
bmx=x264_clip3(m-mvp[0],mv_x_min*4,mv_x_max*4);
bmy=x264_clip3(m-mvp[1],mv_y_min*4,mv_y_max*4);
bcost=4;//这里的左移是为了和(costs[0]4)+N对应
do
{
//以bmx,bmy为基点在周围进行其四点的mvcost计算
COST_MV_X4_DIR(0,-1,0,1,-1,0,1,0,costs);
COPY1_IF_LT(bcost,(costs[0]4)+1);//cost左移了,还要再加N了,加N时为了区别是哪个点
COPY1_IF_LT(bcost,(costs[1]4)+3);
COPY1_IF_LT(bcost,(costs[2]4)+4);
COPY1_IF_LT(bcost,(costs[3]4)+12);
if(!
(bcost&15))//后4位进行检测,如果后4位是0,就是证明所进行比较的4点都是比原点要大,所以不需要继续搜索了
break;
bmx-=(bcost28)30;//为什么要这么麻烦的同时左移和右移了,何不直接除以4bmy-=(bcost30)30;
bcost&=~15;
if(!
CHECK_MVRANGE(bmx,bmy))
break;
}while(++ii_me_range);
.
caseX264_ME_HEX:
六边形搜索+正方形细化,先进行六边形搜索,计算六个方向的矢量的cost,以最小者为起点,再进行正方形细化,
搜索当前的最佳的mv的头的8个连结点的向量的cost,比较大小得到mv,过程和钻石形类似
caseX264_ME_UMH:
非对称十字多六边形网格搜索,
具体的搜索步骤引用()
JM中快速整像素运动估计算法(Unsymmetrical-crossMuti-Hexagon-gridSearch)即UMHexagonS,该算法高效的起始点预测和搜索策略,
该算法用四个步骤完成。
第一步:
用多种预测模式进行初始搜索点预测。
主要对以下运动矢量所指向的点进行搜索,获得当前最优预测起点。
A,中值预测;
B,原点预测;
C,上层块预测;
D,前帧同位置块预测;
E,相邻(多)参考帧预测。
第二步:
进