原文地址:http://blog.sina.com.cn/s/blog_4b700c4c0100nhgo.html

运动补偿是通过先前的局部图像来预测、补偿当前的局部图像,它是减少帧序列冗余信息的有效方法。运动估计是从视频序列中抽取运动信息的一整套技术。

运动估计与运动补偿技术
    MPEG-4采用I-VOP、P-VOP、B-VOP三种帧格式来表征不同的运动补偿类型。它采用了H.263中的半像素搜索(half pixel searching)技术和重叠运动补偿(overlapped motion compensation)技术,同时又引入重复填充(repetitive padding)技术和修改的块(多边形)匹配(modified block (polygon)matching)技术以支持任意形状的VOP区域。

  

    此外,为提高运动估计算法精度,MPEG-4采用了MVFAST(Motion Vector Field Adaptive Search Technique)和改进的PMVFAST(Predictive MVFAST)方法用于运动估计。对于全局运动估计,则采用了基于特征的快速顽健的FFRGMET(Feature-based Fast and Robust Global Motion Estimation Technique)方法。

  
编解码器用来减少视频序列中的空域冗余。它也可以用来进行去交织(deinterlacing)的操作。

http://wenku.baidu.com/view/10db3c0a79563c1ec5da7164.html

定义
  运动补偿是通过先前的局部图像来预测、补偿当前的局部图像,它是减少帧序列冗余信息的有效方法。
分类
  包括 全局运动补偿 和 分块运动补偿两类。  运动补偿是一种描述相邻帧(相邻在这里表示在编码关系上相邻,在播放顺序上两帧未必相邻) 差别的方法,具体来说是描述前面一帧(相邻在这里表示在编码关系上的前面,在播放顺序上未必在当前帧前面)的每个小块怎样移动到当前帧中的某个位置去。这种方法经常被视频压缩/视频编解码器用来减少视频序列中的空域冗余。它也可以用来进行去交织(deinterlacing)的操作。  一个视频序列包含一定数量的图片--通常称为帧。相邻的图片通常很相似,也就是说,包含了很多冗余。使用运动补偿的目的是通过消除这种冗余,来提高压缩比。
最早的运动补偿
早期解析
  最早的运动补偿的设计只是简单的从当前帧中减去参考帧,从而得到通常含有较少能量(或者成为信息)的"残差",从而可以用较低的码率进行编码。解码器可以通过简单的加法完全恢复编码帧。  一个稍微复杂一点的设计是估计一下整帧场景的移动和场景中物体的移动,并将这些运动通过一定的参数编码到码流中去。这样预测帧上的像素值就是由参考帧上具有一定位移的相应像素值而生成的。这样的方法比简单的相减可以获得能量更小的残差,从而获得更好的压缩比--当然,用来描述运动的参数不能在码流中占据太大的部分,否则就会抵消复杂的运动估计带来的好处。  通常,图像帧是一组一组进行处理的。每组的第一帧(通常是第一帧)在编码的时候不使用运动估计的办法,这种帧称为帧内编码帧(Intra frame)或者I帧。该组中的其它帧使用帧间编码帧(Inter frame),通常是P帧。这种编码方式通常被称为IPPPP,表示编码的时候第一帧是I帧,其它帧是P帧。  在进行预测的时候,不仅仅可以从过去的帧来预测当前帧,还可以使用未来的帧来预测当前帧。当然在编码的时候,未来的帧必须比当前帧更早的编码,也就是说,编码的顺序和播放的顺序是不同的。通常这样的当前帧是使用过去和未来的I帧或者P帧同时进行预测,被称为双向预测帧,即B帧。这种编码方式的编码顺序的一个例子为 IBBPBBPBBPBB。
全局运动补偿
  运动模型基本上就是反映摄像机的各种运动,包括平移,旋转,变焦等等。这种模型特别适合对没有运动物体的静止场景的编码。全局运动补偿有下面的一些优点:  该模型仅仅使用少数的参数对全局的运行进行描述,参数所占用的码率基本上可以忽略不计。  该方法不对帧进行分区编码,这避免了分区造成的块效应。  在时间方向的一条直线的点如果在空间方向具有相等的间隔,就对应了在实际空间中连续移动的点。其它的运动估计算法通常会在时间方向引入非连续性。  但是,缺点是,如果场景中有运动物体的话,全局运动补偿就不足以表示了。这时候应该选用其它的方法。
分块运动补偿
  每帧被分为若干像素块 (在大多数视频编码标准,如MPEG中,是分为16x16的像素块)。从参考帧的某个位置的等大小的块对当前块进行预测,预测的过程中只有平移,平移的大小被称为运动矢量。  对分块运动补偿来说,运动矢量是模型的必要参数,必须一起编码加入码流中。由于运动矢量之间并不是独立的(例如属于同一个运动物体的相邻两块通常运动的相关性很大),通常使用差分编码来降低码率。这意味着在相邻的运动矢量编码之前对它们作差,只对差分的部分进行编码。使用熵编码对运动矢量的成分进行编码可以进一步消除运动矢量的统计冗余(通常运动矢量的差分集中于0矢量附近)。  运动矢量的值可以是非整数的,此时的运动补偿被称为亚像素精度的运动补偿。这是通过对参考帧像素值进行亚像素级插值,而后进行运动补偿做到的。最简单的亚像素精度运动补偿使用半像素精度,也有使用1/4像素和1/8像素精度的运动补偿算法。更高的亚像素精度可以提高运动补偿的精确度,但是大量的插值操作大大增加了计算复杂度。
缺点
  分块运动补偿的一个大缺点在于在块之间引入的非连续性,通常称为块效应。当块效应严重时,解码图像看起来会有像马赛克一样的效果,严重影响视觉质量。另外一个缺点是,当高频分量较大时,会引起振铃效应。关于高频分量,请参见对运动补偿后的残差进行变换的方法: 变换编码。

    在MPEG-4视频编码中,运动估计相当耗时,对编码的实时性影响很大。因此这里特别强调快速算法。运动估计方法主要有像素递归法和块匹配法两大类,前者复杂度很高,实际中应用较少,后者则在H.263和MPEG中广泛采用。在块匹配法中,重点研究块匹配准则及搜索方法。目前有三种常用的匹配准则:

  

    (1)绝对误差和(SAD, Sum of Absolute Difference)准则;

  

    (2)均方误差(MSE, Mean Square Error)准则;

  

    (3)归一化互相关函数(NCCF, Normalized Cross Correlation Function)准则。

  

    在上述三种准则中,SAD准则具有不需乘法运算、实现简单方便的优点而使用最多,但应清楚匹配准则的选用对匹配结果影响不大。

  

    在选取匹配准则后就应进行寻找最优匹配点的搜索工作。最简单、最可靠的方法是全搜索法(FS, Full Search),但计算量太大,不便于实时实现。因此快速搜索法应运而生,主要有交叉搜索法、二维对数法和钻石搜索法,其中钻石搜索法被MPEG-4校验模型(VM, Verification Model)所采纳,下面详细介绍。

  

    钻石搜索(DS, Diamond Search)法以搜索模板形状而得名,具有简单、鲁棒、高效的特点,是现有性能最优的快速搜索算法之一。其基本思想是利用搜索模板的形状和大小对运动估计算法速度及精度产生重要影响的特性。在搜索最优匹配点时,选择小的搜索模板可能会陷入局部最优,选择大的搜索模板则可能无法找到最优点。因此DS算法针对视频图像中运动矢量的基本规律,选用了两种形状大小的搜索模板。

  

    · 大钻石搜索模板(LDSP, Large Diamond Search Pattern),包含9个候选位置;

  

    · 小钻石搜索模板(SDSP, Small Diamond Search Pattern),包含5个候选位置。

  

    DS算法搜索过程如下:开始阶段先重复使用大钻石搜索模板,直到最佳匹配块落在大钻石中心。由于LDSP步长大,因而搜索范围广,可实现粗定位,使搜索不会陷于局部最小,当粗定位结束后,可认为最优点就在LDSP 周围8 个点所围菱形区域中。然后再使用小钻石搜索模板来实现最佳匹配块的准确定位,以不产生较大起伏,从而提高运动估计精度。

  

    此外Sprite视频编码技术也在MPEG-4中应用广泛,作为其核心技术之一。Sprite又称镶嵌图或背景全景图,是指一个视频对象在视频序列中所有出现部分经拼接而成的一幅图像。利用Sprite可以直接重构该视频对象或对其进行预测补偿编码。

  

    Sprite视频编码可视为一种更为先进的运动估计和补偿技术,它能够克服基于固定分块的传统运动估计和补偿技术的不足,MPEG-4正是采用了将传统分块编码技术与Sprite编码技术相结合的策略。

运动估计

两帧之间的物体运动是平移运动,位移量不是很很大,所以会以块作为单位分配运动矢量,在运动估计中采用了大量的参考帧预测来提高精度,当前的待编码块可以在缓存内的所有重建帧中寻找最优的匹配块进行运动补偿,以便很好的去除时间域的冗余度。为每一个块寻求一个运动矢量MV,并进行运动补偿预测编码。在每个分割区域中都有其对应的运动矢量,并对运动矢量以及块的选择方式进行编码和传输。
运动估计ME所表达的运动矢量MV,其研究的内容就是如何加速,有效的获得足够精确的mv,并且把前一帧所得的运动信息通过运动补偿MC来进行变换,量化编码,最后输出。
缩写含义:me得到的是mV
预测得到的是mvp
差值是mvd
MV:运动向量,参考帧中相对于当前帧的偏移
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所采用的运动搜索策略(对应的最后面的程序中有描述):
#define X264_ME_DIA                  0 //钻石搜索
#define X264_ME_HEX                  1 //六边形所搜
#define X264_ME_UMH                  2 //非对称十字六边形网络搜索
#define X264_ME_ESA                  3 //全搜索
#define X264_ME_TESA                 4 //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_ref < h->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 );//下面的有详细的注释1
x264_mb_predict_mv_ref16x16( h, 0, i_ref, mvc, &i_mvc );//注释2
x264_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 );
void x264_mb_predict_mv_16x16( x264_t *h, int i_list, int i_ref, int16_t mvp[2] )
{
int     i_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];
int     i_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];
int     i_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_count > 1 )
{
median:
x264_median_mv( mvp, mv_a, mv_b, mv_c );
}
else if( i_count == 1 )
{
if( i_refa == i_ref )
*(uint32_t*)mvp = *(uint32_t*)mv_a;
else if( i_refb == i_ref )
*(uint32_t*)mvp = *(uint32_t*)mv_b;
else
*(uint32_t*)mvp = *(uint32_t*)mv_c;
}
else if( i_refb == -2 && i_refc == -2 && i_refa != -2 )
*(uint32_t*)mvp = *(uint32_t*)mv_a;
else
goto median;
}
}

//注释2:细化16*16块mv预测

x264_mb_predict_mv_ref16x16( h, 0, i_ref, mvc, &i_mvc );

void x264_mb_predict_mv_ref16x16( x264_t *h, int i_list, int i_ref, int16_t mvc[9][2], int *i_mvc )
{
//设运动补偿
#define SET_MVP(mvp) { \
*(uint32_t*)mvc[i] = *(uint32_t*)mvp; \
i++; \
}
......
//空间预测:获取左边,上边和左上的mb的mvc[i],得到不同的类型的MVC,获得i个mvc
if( h->mb.i_neighbour & MB_LEFT )
{
int i_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 )
{
int i_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_x < h->mb.i_mb_stride - 1 && !IS_SKIP( h->mb.type[i_mb_t + 1] ) )
SET_MVP( mvr[i_mb_t+1] );
}
//时间预测
//dx,dy表示在时间差上的参考帧上对应点的坐标差
#define SET_TMVP(dx, dy) { \
int i_b4 = h->mb.i_b4_xy + dx*4 + dy*4*h->mb.i_b4_stride; \
int i_b8 = h->mb.i_b8_xy + dx*2 + dy*2*h->mb.i_b8_stride; \
int ref_col = l0->ref[0][i_b8]; \
if( ref_col >= 0 ) \
{ \
int scale = (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++; \
} \
}
}

//注释3
x264_me_search_ref( h, &m, mvc, i_mvc, p_halfpel_thresh );
void x264_me_search_ref( x264_t *h, x264_me_t *m, int16_t (*mvc)[2], int i_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_t bmv = pack16to32_mask(bmx,bmy);
COST_MV_HPEL( bmx, bmy );     //对COST_MV_HPEL目的:获得最佳cost的坐标
for( i = 0; i < i_mvc; i++ )
{
if( *(uint32_t*)mvc[i] && (bmv - *(uint32_t*)mvc[i]) )
{
int mx = x264_clip3( mvc[i][0], mv_x_min*4, mv_x_max*4 );
int my = 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; i < i_mvc; i++ )
{
int mx = (mvc[i][0] + 2) >> 2;
int my = (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语句:#define X264_ME_DIA                  0
#define X264_ME_HEX                  1
#define X264_ME_UMH                  2
#define X264_ME_ESA                  3
#define X264_ME_TESA                 4
//switch( h->mb.i_me_method )中的参数 h->mb.i_me_method = h->param.analyse.i_me_method;
//根据用户的命令输入决定运动矢量的精度程度,根据空间相关性,用求出的左,上,左上的编码的宏块的//MV得到当前mb的mv的预测值mvp,以预测向量mvp的为初始原点,进行整数像素的搜索

case X264_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为基点在周围进行其四点的mv cost计算
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 -= (bcost<<28)>>30;//为什么要这么麻烦的同时左移和右移了,何不直接除以4
bmy -= (bcost<<30)>>30;
bcost &= ~15;
if( !CHECK_MVRANGE(bmx, bmy) )
break;
} while( ++i < i_me_range );
........
case X264_ME_HEX:六边形搜索+正方形细化,先进行六边形搜索,计算六个方向的矢量的cost,以最小者为起点,再进行正方形细化,
搜索当前的最佳的mv的头的8个连结点的向量的cost,比较大小得到mv,过程和钻石形类似

case X264_ME_UMH:非对称十字多六边形网格搜索,
具体的搜索步骤引用(http://bbs.chinavideo.org/viewthread.php?tid=7204&highlight=�˶����)
JM中快速整像素运动估计算法 (Unsymmetrical-cross Muti-Hexagon- grid Search)即UMHexagonS,该算法高效的起始点预测和搜索策略,
该算法用四个步骤完成。
第一步:用多种预测模式进行初始搜索点预测。主要对以下运动矢量所指向的点进行搜索,获得当前最优预测起点。
A,中值预测;
B,原点预测;
C,上层块预测;
D,前帧同位置块预测;
E,相邻(多)参考帧预测。
第二步:进行混合搜索,包括如下:
A,非对称十字搜索。
B,5×5 全搜索。
C,扩展的多层次六边形(六角形)格点搜索。
第三步:以当前最优点为中心,用六边形(六角形)进行搜索,直至最优点在六边型的中点为止。
第四步:以当前最优点为中心,用小菱形进行搜索,直至最优点在小菱形的中点为止。

在x264中,对于初始索引点的位置是在x264_mb_predict_mv_16x16中已经获得,在case X264_ME_UMH中主要是进行后面的三步。部分函数解释如下:
...................
DIA1_ITER( pmx, pmy );//在1/4像素出进行小菱形的搜索,并获得最小值
.........
// 若为i_piexl为4*4时,直接进行六边形细化,因为其预测矢量的精度较高,可以跳过十字形搜索和多级六边形搜索,
if(i_pixel == PIXEL_4x4)
goto me_hex2;
............  
// 将获得的1/4像素的cost(ucost2)和整像素的cost进行比较,若果相等就赋值cross_start=3,此时的Bcost//为整像素的cost,ucost1为初始的cost
if( bcost == ucost2 )
cross_start = 3;
................
//cross 函数主要是在进行十字搜索,在垂直和水平方向进行搜索最小的cost
CROSS( 3, range, range );
.............................

case X264_ME_ESA:穷尽搜索法,x264已经取消了这种古老的全搜索法,而是采用下面改进的搜索法
case X264_ME_TESA:hadamard 全搜索法,这个算法和ESA相比主要是在搜索范围上的变化

//在完成了上面的整像素搜索后,由参数设置来进行1/2,1/4像素的搜索
if( bpred_cost < bcost )
{
m->mv[0] = bpred_mx;
m->mv[1] = bpred_my;
m->cost = bpred_cost;
}
else
{
m->mv[0] = bmx << 2;
m->mv[1] = bmy << 2;
m->cost = bcost;
}

m->cost_mv = p_cost_mvx[ m->mv[0] ] + p_cost_mvy[ m->mv[1] ];
if( bmx == pmx && bmy == pmy && h->mb.i_subpel_refine < 3 )
m->cost += m->cost_mv;

if( h->mb.i_subpel_refine >= 2 )
{
int hpel = subpel_iterations[h->mb.i_subpel_refine][2];
int qpel = subpel_iterations[h->mb.i_subpel_refine][3];
refine_subpel( h, m, hpel, qpel, p_halfpel_thresh, 0 );
}
}

以上只是针对16*16帧间的MB的运动估计的跟踪,其他MB类型的ME类似

运动估计

一概述  运动估计的基本思想是将图像序列的每一帧分成许多互不重叠的宏块,并认为宏块内所有象素的位移量都相同,然后对每个宏块到参考帧某一给定特定搜索范围内根据一定的匹配准则找出与当前块最相似的块,即匹配块,匹配块与当前块的相对位移即为运动矢量。视频压缩的时候,只需保存运动矢量和残差数据就可以完全恢复出当前块。

基本概念

  在帧间预测编码中,由于活动图像邻近帧中的景物存在着一定的相关性。因此,可将活动图像分成若干块或宏块,并设法搜索出每个块或宏块在邻近帧图像中的位置,并得出两者之间的空间位置的相对偏移量,得到的相对偏移量就是通常所指的运动矢量,得到运动矢量的过程被称为运动估计。

  运动矢量和经过运动匹配后得到的预测误差共同发送到解码端,在解码端按照运动矢量指明的位置,从已经解码的邻近参考帧图像中找到相应的块或宏块,和预测误差相加后就得到了块或宏块在当前帧中的位置。

  通过运动估计可以去除帧间冗余度,使得视频传输的比特数大为减少,因此,运动估计是视频压缩处理系统中的一个重要组成部分。本节先从运动估计的一般方法入手,重点讨论了运动估计的三个关键问题:将运动场参数化、最优化匹配函数定义以及如何寻找到最优化匹配。

运动估计的方法

  一般的运动估计方法如下: 设 t 时刻的帧图像为当前帧 f (x, y) , t’时刻的帧图像为参考帧 f’(x,y),参考帧在时间上可以超前或者滞后于当前帧,如图1所示,当 t’<t 时,称之为后向运动估计,

  当 t’>t 时,称之为前向运动估计。当在参考帧 t’中搜索到当前帧 t 中的块的最佳匹配时,可以得到相

  应的运动场 d(x; t, t + t △ ) ,即可得到当前帧的运动矢量。

  

图1前向或后向运动估计

H.264 编码标准和以往采用的视频压缩标准很大的不同在于,在运动估计过程中采用了多参考

  帧预测来提高预测精度,多参考帧预测就是在编解码端建一个存储 M个重建帧的缓存,当前的待编

  码块可以在缓存内的所有重建帧中寻找最优的匹配块进行运动补偿,以便更好地去除时间域的冗余

  度。由于视频序列的连续性,当前块在不同的参考帧中的运动矢量也是有一定的相关性的。假定当

  前块所在帧的时间为 t, 则对应前面的多个参考帧的时间分别为:t-1, t-2, ……。则当在帧 t-2 中搜索

  当前块的最优匹配块时,可以利用当前块在帧 t-1 中的运动矢量 MVNR来估测出当前块在帧 t-2 的运

  动矢量。

运动表示法

  由于在成象的场景中一般有多个物体作不同的运动,如果直接按照不同类型的运动将图像分割成复杂的区域是比较困难的。最直接和不受约束的方法是在每个像素都指定运动矢量,这就是所谓基于像素表示法。这种表示法是对任何类型图像都是适用的,但是它需要估计大量的未知量,并且它的解时常在物理上是不正确,除非在估计过程中施加适当的物理约束。这在具体实现时是不可能的,通常采用基于块的物体运动表示法。

4.1 基于块的运动表示法

  一般对于包含多个运动物体的景物,实际中普遍采用的方法是把一个图像帧分成多个块,使得在每个区域中的运动可以很好地用一个参数化模型表征,这被称为块匹配法,即将图像分成若干个n×n 块(典型值:16×16 宏块) ,为每一个块寻找一个运动矢量 MV,并进行运动补偿预测编码。每一个帧间宏块或块都是根据先前已编码的数据预测出的,根据已编码的宏块、块预测的值和当前宏块、块作差值,结果被压缩传送给解码器,与解码器所需要的其他信息如(运动矢量、预测模型等)一起用来重复预测过程。每个分割区域都有其对应的运动矢量,并必须对运动矢量以及块的选择方式进行编码和传输。在细节比较多的帧中如果选择较大的块尺寸,意味着用于表明运动矢量和分割区域类型的比特数会少些,但是运动压缩的冗余度要多一些;如果选择小一点的块尺寸,那么运动压缩后冗余度要少一些,但是所需比特数要比较多。因此必须要权衡块尺寸选择上对压缩效果的影响,一般对于细节比较少、比较平坦的区域选择块尺寸大一些,对于图像中细节比较多的区域选择块尺寸小一些。宏块中的每个色度块(Cb 和 Cr) 尺寸宽高都是亮度块的一半,色度块的分割方法和亮度块同样,只是尺寸上宽高都是亮度块一半(如亮度块是 8×16 块尺寸大小,那么色度块就是 4×8,如果亮度块尺寸为 8×4,那么色度块便是 4×2 等等)。每个色度块的运动矢量的水平和垂直坐标都是亮度块的一半。

4.2 亚像素位置的内插

  帧间编码宏块中的每个块或亚宏块分割区域都是根据参考帧中的同尺寸的区域预测得到的,它

  们之间的关系用运动矢量来表示。

  由于自然物体运动的连续性,相邻两帧之间的块的运动矢量不是以整像素为基本单位的,可能

  真正的运动位移量是以 1/4 像素或者甚至 1/8 像素等亚像素作为为单位的。

  图 3.17 给出了一个视频序列当采用 1/2 像素精度、1/4 像素精度和 1/8 像素精度时编码效率的情

  况,从图中可以看到 1/4像素精度相对于 1/2 像素精度的编码效率有很明显的提高,但是 1/8 像素精

  度相对于 1/4像素精度的编码效率除了在高码率情况下并没有明显的提高, 而且 1/8像素的内插公式

  更为复杂,因此在 H.264的制定过程中 1/8 像素精度的运动矢量模型逐渐被取消而只采用了 1/4 像素

  精度的运动矢量模型。

  

图2

4.3运动矢量在时空域的预测方式

  如果对每个块的运动矢量进行编码,那么将花费相当数目的比特数,特别是如果选择小尺寸的

  块的时候。由于一个运动物体会覆盖多个分块,所以空间域相邻块的运动矢量具有很强的相关性,

  因此,每个运动矢量可以根据邻近先前已编码的块进行预测,预测得到的运动矢量用 MVp 表示,当

  前矢量和预测矢量之间的差值用 MVD 表示。同时由于物体运动的连续性,运动矢量在时间域也存

  在一定相关性,因此也可以用邻近参考帧的运动矢量来预测。

  1) 运动矢量空间域预测方式

  a、运动矢量中值预测(Median Prediction)

  利用与当前块 E 相邻的左边块 A,上边块 B 和右上方的块 C 的运动矢量,取其中值来作为当前

  块的预测运动矢量。

  设 E 为当前宏块、宏块分割或者亚宏块分割, A 在 E 的左侧,B 在 E 的上方、C 在 E 的右上

  方,如果 E 的左侧多于一个块,那么选择最上方的块作为 A,在 E 的上方选择最左侧的块作为 B。

  图 3.18 表示所有的块尺寸相同,图 3.19 表示邻近块尺寸不同时作为预测 E 的运动矢量的块的选择。

  在预测 E 的过程中遵守以下准则:

  1、对于除了块尺寸为 16×8和 8×16 的块来说,MVp是块 A、B 和 C 的运动矢量的中值;

  2、 对于 16×8 块来说, 上方的 16×8 块的MVp 根据B预测得到, 下方的 16×8 块的 MVp 根据 A

  得到;

  3、 对于 8×16 块来说, 左侧的 16×8 块的MVp 根据 A预测得到, 右侧的 16×8 块的 MVp 根据 C

  得到;

  4、对于不用编码的可跳过去的宏块,16×16 矢量MVp 如第一种情况得到。

  2) 运动矢量在时间域预测方式

  a、前帧对应块运动矢量预测(Corresponding-block Prediction)

  利用前一帧的与当前块相同坐标位置的块的运动矢量来作为当前块的预测运动矢量,如图 3.21

  所示。

  b、时间域的邻近参考帧运动运动矢量预测(Neighboring Reference-frame Prediction)

  由于视频序列的连续性,当前块在不同的参考帧中的运动矢量也是有一定的的相干性的。如图

  3.22 所示,假设当前块所在帧的时间为 t,则当在前面的参考帧 t’中搜索当前块的最优匹配块时,可

  以利用当前块在参考帧 t’+1 中的运动矢量来估测出当前块在帧他 t’的运动矢量:

  在上述运动矢量的四种预测方式中,经过实验证明,空间域的预测更为准确,其中上层块预测

  的性能最优,因为其充分利用了不同预测块模式运动矢量之间的相关性。而中值预测性能随着预测

  块尺寸的减小而增加,这是因为当前块尺寸越小,相关性越强。

4.4匹配误差在时空域的预测方式

  H.264 中定义的匹配误差函数如下:

  J(MV,λMOTION)=SAD(s, c (MV))+λMOTION×R(MV-PMV) (3.28)

  其中 SAD(绝对差值和)计算公式如下:

  ,

  1, 1

  (, ( )) | [, ] [ , ]|, , 16,8 4

  xy BB

  xyxy

  xy

  SAD s c MV s x y c x MV y MV B B or

  ==

  =−−− = ∑ (3.29)

  其中 s 是当前进行编码的原始数据,而 c 是已经编码重建的用于进行运动补偿的参考帧的数据。

  MV为候选的运动矢量,λMOTION为拉格朗日常数,PMV 为中值预测矢量,R(MV-PMV)代表了运动矢

  量差分编码可能耗费的比特数,由于在接下来的四种匹配误差预测方式中匹配误差中的

  λMOTION×R(MV-PMV)部分通常很接近而抵消,SAD 部分的预测特性基本上可以反映整个匹配函数的

  预测特性,因此 J(MV,λMOTION)用 SAD来表示。

  匹配误差在时空域的预测方式和运动矢量类似,具体分为:

  1)匹配误差在空间域预测方式

  a、中值预测(Median Prediction)

  与当前块 E相邻的左边块 A,上边块 B 和右上方的块 C 搜索得到的最小 SAD值分别为 SADA,

  SADB,SADC,取当前块的预测 SAD值为:

  SADpred_MD = min (SADx_median,SADy_median) (3.30)

  SADx_median是相邻块中对应运动矢量横坐标为

  x_median=Median(MVA(x),MVB(x)MVC(x)) (3.31)

  的相邻块的最小 SAD值,SADy_median也同理。如图 3.23 所示

  b、上层预测(Uplayer Prediction)

  H.264 标准中提供的块尺寸有 16×16,8×16,16×8,8×8,8×4,4×8,4×4,它们的图象分割区

  域分别定义为搜索模式 Mode1-Mode7。假设当前分割区域的预测模式为 Modecurr,上层模式 Modeup

  定义为

  ,1

  1, 2, 3

  2, 4

  4, 5, 6

  5, 7

  curr

  curr

  Up curr

  curr

  curr

  unavailable if Mode Mode

  Mode if Mode Mode Mode

  Mode Mode if Mode Mode

  Mode if Mode Mode Mode

  Mode if Mode Mode

  == ⎧

  ⎪

  == ⎪ ⎪

  === ⎨

  ⎪ ==

  ⎪

  ⎪ == ⎩

  (3.32)

  利用空间域上层搜索模式的搜索所得的最小 SAD 值作为当前模式下的预测 SAD 值的方法如图

  3.24 所示:

  SADpred_up = SADuplayer/2 (3.33)

  2)匹配函数在时间域预测方式

  a、前帧对应块的预测(Corresponding-block Prediction)

  利用前一帧的与当前块相同坐标位置的块在帧 t’-1 中搜索得到的最小 SAD,作为当前搜索块在

  帧 t’中进行搜索的 SAD的预测值,如图所示。

  b、时间域的邻近参考帧预测(Neighboring Reference-frame Prediction)

  如图 3.26 所示,假设当前块所在帧的时间为 t,则当在前面的参考帧 t’中搜索时,可以利用当前

  块在参考帧t’+1中搜索得到的最小SAD值SADNR作为当前块在帧t’搜索的SAD预测值,即SADpred_NRP

  =SADNR。

  以上所述的匹配误差的四种预测方式中,时间域的预测更为准确,其中邻近参考帧预测方式性

  能最优,这是由于在这种预测方式下当前块相同,邻近参考帧预测方式中,邻近的参考帧之间具有

  比较强的相关性。但是它的性能受量化参数影响比较大,这是由于量化参数大的时候图象细节模糊,

  相邻参考帧图象内容之间的相似度增加,因而用邻近参考帧预测的方式会更为准确一些。

运动估计准则分类

  运动搜索的目的就是在搜索窗内寻找与当前块最匹配的数据块,这样就存在着如何判断两个块

  是否匹配的问题,即如何定义一个匹配准则。而匹配准则的定义与运算复杂度和编码效率都是直接

  相关的,通常有如下几类比较常用的匹配函数的定义:

  设当前帧 f2,参考帧 f1,

  (1)最小均方差函数(MSE)

  MSE (MV) =Σ|f2(x,MV)-f1(x)|

  2

  (3.34)

  (2)最小平均绝对值误差(MAD)等效于常用的绝对差值和(SAD)准则,性能很好,而且相对简单

  的硬件需求,因而得到了最广泛的应用。

  MAD (MV) =Σ|f2(x,MV)-f1(x)| (3.35)

  (3)阈值差别计数(NTD)

  NTD(MV)=ΣG(f2(x,MV)-f1(x)) (3.36)

  其中:

  当 | α-β | >T0 时,G(α,β)=1;

  当 | α-β | <T0 时,G(α,β)=0 (3.37)

  由于在用块匹配算法进行运动估计的过程中,利用匹配准则函数进行匹配误差的计算是最主要

  的计算量,因此,我们可以从这方面进一步减少计算量。由于图象的帧内也具有相关性,在计算误

  差匹配函数时,可以只让图象块中的部分像素参与运算,将块中的所有像素组成一个集合,那么参

  与计算的这部分像素集合就是它的子集,这种误差匹配的方法被称为子集匹配法。实验结果表明,

  在匹配误差无明显增加的情况下,采用子集匹配可以大大减少每帧图象的平均搜索时间。

运动搜索算法

  匹配误差函数,可以用各种优化方法进行最小化,这就需要我们开发出高效的运动搜索算法,

  主要的几种算法归纳如下:

6.1 全局搜索算法

  为当前帧的一个给定块确定最优位移矢量的全局搜索算法方法是:在一个预先定义的搜索区域

  内,把它与参考帧中所有的候选块进行比较,并且寻找具有最小匹配误差的一个。这两个块之间的

  位移就是所估计的 MV,这样做带来的结果必然导致极大的计算量。

  选择搜索区域一般是关于当前块对称的,左边和右边各有 Rx 个像素,上边和下边各有 Ry个像

  素,如图 3.27 所示。

  如果已知在水平和垂直方向运动的动态范围是相同的,那么 Rx=Ry=R。估计的精度是由搜索的

  步长决定的,步长是相邻两个候选块在水平或者垂直方向上的距离。通常,沿着两个方向使用相同

  的步长。在最简单的情况下,步长是一个像素,称为整数像素精度搜索,该种算法也称为无损搜索

  算法。

6.2 分数精度搜索算法

  由于在穷尽块匹配算法中搜索相应块的步长不一定是整数,一般来说,为了实现 1/K像素步长,

  对参考帧必须进行 K倍内插。图 3.28 给出了 K=2 的例子,它被称为半像素精度搜索。根据实验证

  明,与整像素精度搜索相比,半像素精度搜索在估计精度上有很大提高,特别是对于低清晰度视频。

  但是,应用分数像素步长,搜索算法的复杂性大大增加,例如,使用半像素搜索,搜索点的总

  数比整数像素精度搜索大四倍以上。

  那么,如何确定适合运动估计的搜索步长,对于视频编码的帧间编码来说,即使得预测误差最

  小化。预测误差和搜索精度之间的关系的统计分析如图 3.29 所示:

6.3 快速搜索算法

  快速搜索算法和全局搜索算法相比,虽然只能得到次最佳的匹配结果,但在减少运算量方面效

  果显著。

  1)二维对数搜索法

  这种算法的基本思路是采用大菱形搜索模式和小菱形搜索模式,步骤如图 6.4.20 所示,从相应

  于零位移的位置开始搜索,每一步试验菱形排列的五个搜索点。下一步,把中心移到前一步找到的

  最佳匹配点并重复菱形搜索。当最佳匹配点是中心点或是在最大搜索区域的边界上时,就减小搜索

  步长(菱形的半径)。否则步长保持不变。当步长减小到一个像素时就到达了最后一步,并且在这最

  后一步检验九个搜索点。初始搜索步长一般设为最大搜索区域的一半。

  其后这类算法在搜索模式上又做了比较多的改进,在搜索模式上采用了矩形模式,还有六

  边形模式、十字形模式等等。

  2)三步搜索法

  如图 3.31 所示,这种搜索的步长从等于或者略大于最大搜索范围的一半开始。第一步,在起始

  点和周围八个 “1”标出的点上计算匹配误差,如果最小匹配误差在起始点出现,则认为没有运动;

  第二步,以第一步中匹配误差最小的点(图中起始点箭头指向的“1”)为中心,计算以“2”标出的 8

  个点处的匹配误差。注意,在每一步中搜索步长搜都比上一步长减少一半,以得到更准确的估计;

  在第三步以后就能得到最终的估计结果,这时从搜索点到中心点的距离为一个像素。

  但是,上述一些快速算法更适合用于估计运动幅度比较大的场合,对于部分运动幅度小的场

  合,它们容易落入局部最小值而导致匹配精度很差,已经有很多各种各样的视频流证明了这一点。

  现在,针对这一缺点,国内外诸多专家学者也提出了相应的应对措施,特别是针对H.264编

  码标准要求的一些快速算法的改进,并取得卓越的效果。例如[7]中提到的基于全局最小值具有自

  适应性的快速算法,这种算法通过在每一搜索步骤选择多个搜索结果,基于这些搜索结果之间的

  匹配误差的不同得到的最佳搜索点,因而可以很好地解决落入局部最小值的问题。

  [8]中提到一种适用于H.264的基于自适应搜索范围的快速运动估计算法,经过实验证明对于

  如salesman等中小运动序列,其速度可接近全局搜索算法的400倍,接近三步搜索算法的4倍;而对于

  大运动序列,如table tennis,该算法则会自动调节搜索点数以适应复杂的运动。当从总体上考察速度

  方面的性能时,可以看到,该算法平均速度是全局搜索算法的287.4倍,三步搜索的2.8倍。

6.4 分级搜索范围(DSR)算法

  分级搜索算法的基本思想是从最低分辨率开始逐级精度的进行不断优化的运动搜索策略,如图

  3.32 所示,首先取得两个原始图象帧的金子塔表示,从上到下分辨率逐级变细,从顶端开始,选择

  一个尺寸比较大的数据块进行一个比较粗略的运动搜索过程,对在此基础上进行亚抽样(即通过降

  低数据块尺寸(或提高抽样分辨率)和减少搜索范围的办法)进行到下一个较细的级来细化运动矢

  量,而一个新的搜索过程可以在上一级搜索到的最优运动矢量周围进行。在亚抽样的过程中也有着

  不同的抽样方式和抽样滤波器。这种方法的优点是运算量的下降比例比较大,而且搜索的比较全面。

  缺点是由于亚抽样或者滤波器的采用而使内存的需求增加,另外如果场景细节过多可能会容易落入

  局部最小点。

6.5 混合搜索算法

  由于物体的运动千变万化,很难用一种简单的模型去描述,也很难用一种单一的算法来搜索最

  佳运动矢量,因此实际上大多采用多种搜索算法相组合的办法,可以在很大程度上提高预测的有效

  性和鲁棒性。

  事实上,在运动估计时也并不是单一使用上述某一类搜索算法,而是根据各类算法的优点灵活

  组合采纳。在运动幅度比较大的情况下可以采用自适应的菱形搜索法和六边形搜索法,这样可以大

  大节省码率而图象质量并未有所下降。在运动图象非常复杂的情况下,采用全局搜索法在比特数相

  对来说增加不多的情况下使得图象质量得到保证。 H.264 编码标准草案推荐使用 1/4分数像素精度搜

  索。[6]中提到在整像素搜索时采用非对称十字型多层次六边形格点运动搜索算法,然后采用钻石搜

  索模型来进行分数像素精度运动估计。

  解码器要求传送的比特数最小化,而复杂的模型需要更多的比特数来传输运动矢量,而且易受

  噪声影响。因此,在提高视频的编码效率的技术中,运动补偿精度的提高和比特数最小化是相互矛

  盾的,这就需要我们在运动估计的准确性和表示运动所用的比特数之间作出折中的选择。它的效果

  与选用的运动模型是密切相关的。

其他资料

  三常见的运动估计匹配准则有三种:MAD、MSE和NCCF,由于MAD没有乘除操作,不需做乘法运算,实现简单方便,所以使用较多。通常使用求和绝对误差(SAD)代替MAD 。

  运动估计和运动补偿是AVS 中去除时间冗余的主要方法,它采用多种宏块划分方式,1P4 像素插值、双向估计和多参考帧等技术大大提高了编码效率,但同时也给编解码器增加了一定的复杂度。

  运动估计和运动补偿作为视频压缩编码系统的核心算法,占整个系统运算量的60%-80%。研究运动估计算法的DSP实现对整个H.264系统的嵌入式应用具有重要的指导意义。

  运动估计算法

  运动估计算法是视频压缩编码的核心算法之一。高质量的运动估计算法是高效视频编码的前提和基础。其中块匹配法(BMA, Block Match Algorithm)由于算法简单和易于硬件实现,被广泛应用于各视频编码标准中。块匹配法的基本思想是先将图像划分为许多子块,然后对当前帧中的每一块根据一定的匹配准则在相邻帧中找出当前块的匹配块,由此得到两者的相对位移,即当前块的运动矢量。在H.264标准的搜索算法中,图像序列的当前帧被划分成互不重叠16×16大小的子块,而每个子块又可划分成更小的子块,当前子块按一定的块匹配准则在参考帧中对应位置的一定搜索范围内寻找最佳匹配块,由此得到运动矢量和匹配误差。运动估计的估计精度和运算复杂度取决于搜索策略和块匹配准则。这里使用H.264推荐算法UMHexagonS(Unsymmetrical-cross Multi-Hexagon-grid Search)作为DSP实现的算法参考,与FS算法比较,它在保证可靠搜索精度的前提下大幅降低搜索复杂度。同时使用绝对差和(SAD, the Sum of Absolute Difference)标准作为匹配准则,它具有便于硬件实现的优点。

x264运动补偿技术相关推荐

  1. 帧间预测:运动估计和运动补偿

    运动补偿是通过先前的局部图像来预测.补偿当前的局部图像,它是减少帧序列冗余信息的有效方法.运动估计是从视频序列中抽取运动信息的一整套技术. 运动估计与运动补偿技术 MPEG-4采用I-VOP.P-VO ...

  2. HEVC视频编码技术

    HEVC视频编码框架 HEVC编码框架与H.26X标准的编码框架类似,均采用基于块的混合模型. 图1 HEVC编码框架 如上图所示,HEVC编码器的工作过程为: 1.首先,视频编码器将输入视频图像划分 ...

  3. 揭秘视频千倍压缩背后的技术原理之预测技术

    正文字数:3312  阅读时长:4分钟 随着5G的成熟和广泛商用,带宽已经越来越高,传输视频变得更加容易.设备特别是移动设备算力的提升.存储容量的提升,使得视频技术的应用越来越广泛,无论是流媒体.泛娱 ...

  4. HEVC编码技术简介

    HEVC视频编码框架 HEVC编码框架与H.26X标准的编码框架类似,均采用基于块的混合模型. 图1 HEVC编码框架 如上图所示,HEVC编码器的工作过程为: 1.首先,视频编码器将输入视频图像划分 ...

  5. 【Codecs系列】HEVC标准(五):帧间预测技术及x265实现分析

    DATE: 2021.12.27 文章目录 1.帧间关键技术 1.1.Merge/Skip 1.2.AMVP 1.2.1 Inter模式下的AMVP技术 1.2.2 Merge模式下的AMVP技术 1 ...

  6. 深入浅出理解视频编解码技术

    导读:随着移动互联网技术的蓬勃发展,视频已无处不在.视频直播.视频点播.短视频.视频聊天,已经完全融入了每个人的生活.Cisco 发布的最新报告中写道,到 2022 年,在移动互联网流量中,视频数据占 ...

  7. 实时音视频开发理论必备:如何省流量?视频高度压缩背后的预测技术

    本文引用了"拍乐云Pano"的"深入浅出理解视频编解码技术"和"揭秘视频千倍压缩背后的技术原理之本文引用了"拍乐云Pano"的&q ...

  8. 主流视频编码压缩技术基本概念(二) 算法分析

    主流视频编码压缩技术基本概念(二) 算法分析 一.MPEG-1技术介绍 1. MPEG-1的层次及语法结构 ①.运动补偿序列(Sequence) ②.图片组(GOP) ③. 图片(Picture) ④ ...

  9. 主流视频编码压缩技术基本概念(一)

    主流视频编码压缩技术基本概念(一) 一.多媒体技术基本 1.图像的色彩模型 二. 静态图像压缩技术 三.视频编码压缩技术基础 有冗余就有可压缩的数据 图像通用格式 一.多媒体技术基本 1.图像的色彩模 ...

最新文章

  1. linux tunnel 与cisco 三层交换机的tunnel互联
  2. 网络工程中的割接是什么意思?
  3. WIN10系统如何取消任务栏处的窗口缩略图
  4. 面试中说这些话,到手的offer很容易飞
  5. 在emacs里用w3m浏览网页
  6. linux学习笔记1(第一本笔记)
  7. 开源生产排程aps(Advanced Planning and Scheduling)软件介绍
  8. wps启用编辑按钮在哪里_wps页面设置在哪里?wps页面设置使用教程
  9. 【改变键盘上方向键蹩脚的位置】通过autohotkey脚本实现键盘按键重映射【便利码代码】--以上下左右键映射为capslock与hjkl组合的按键 【附源码】
  10. 探索语句和表达式的本质
  11. 不小心删了(或覆盖了)window系统变量的PATH的怎么办?
  12. 软件架构师:走钢索的人
  13. 一文讲解Linux 内核网络协议栈-数据从接收到ip层
  14. 中国丝光棉市场产销需求及未来前景趋势预测报告(2022-2027年)
  15. Activiti进阶(一)——HelloWorld
  16. 慎重推荐十个优秀的网络硬盘(网盘)
  17. 游戏与常用的五大算法---上篇
  18. IT资源汇总全分享,学习资料免费领取处
  19. 【SSA三维路径规划】基于matlab麻雀算法无人机三维路径规划【含Matlab源码 171期】
  20. 解决<tx:attributes>标红,元素tx:attributes不允许在这里

热门文章

  1. 建硬盘分区,pvcreate 报:“Can topen /dev/sdb1 exclusivel...?“;磁盘分区报:设备或资源;RHEL本地存储项目二mkfs.vfat报错
  2. 华为云游戏解决方案助力行业创新
  3. 七夕静态页面html,html5+CSS3+JS实现七夕言情功能代码
  4. python七夕快乐_用python度过一个温馨的单身七夕节-安利篇
  5. HTML与CSS学习笔记(一)
  6. 『深度数据』视频分类数据集·HMDB51介绍
  7. 坚持#第308天~我找到了一种字体非常好,Helvetica,我非常喜欢,写文档专用,昨天晚上加班到1点钟把技术文档写完了,
  8. Match.com被逼做DownToEarth免费交友社群,社群网站也可转战男女交友!
  9. PDF转换成Word文档(记一下,蛮实用)
  10. 怎么给视频去水印,如何一键消除水印