Abstract

该块匹配算法(block matching algorithm BMA)用于运动估计。核心思想就是通过连续不断的消除搜索窗口中的块位置,降低计算量,同时获得较为准确的运动向量,准确度极其接近全搜索算法。它不同于其他递增型的搜索算法,也就是从一点出发,搜索周边块,该性质会导致其陷入局部最优。


Principles of the Algorithm

块匹配算法(BMA)的目的就是在参考帧的搜索窗口中找到一个与当前块的最佳匹配。接下来会讲一个不等关系式,用于限制在搜索窗口中搜索过程,但仍然保留了运动向量的最佳选项。

假设一个像素块,其尺寸为N x N,搜索窗口的尺寸为 (2M + 1) x (2M + 1)。f(i, j, t) 代表像素帧 t 中坐标为 (i, j) 的像素值。平均绝对差 (Mean absolute difference MAD) 用于衡量两个块之间的匹配程度。假设参考帧为 t - 1。我们能得到一个基本的不等式:

(1) ∣ ∣ f ( i , j , t ) ∣ − ∣ f ( i − x , j − y , t − 1 ) ∣ ∣ ≤ ∣ f ( i , j , t ) − f ( i − x , j − y , t − 1 ) ∣ . ||f(i, j, t)| - |f(i - x, j - y, t - 1)|| \leq |f(i, j, t) - f(i - x, j - y, t - 1)|. \tag{1} ∣∣f(i,j,t)∣−∣f(i−x,j−y,t−1)∣∣≤∣f(i,j,t)−f(i−x,j−y,t−1)∣.(1)

该不等式与以下两个不等式等效:

(2) ∣ f ( i , j , t ) ∣ − ∣ f ( i − x , j − y , t − 1 ) ∣ ≤ ∣ f ( i , j , t ) − f ( i − x , j − y , t − 1 ) ∣ . |f(i, j, t)| - |f(i - x, j - y, t - 1)| \leq |f(i, j, t) - f(i - x, j - y, t - 1)|.\tag{2} ∣f(i,j,t)∣−∣f(i−x,j−y,t−1)∣≤∣f(i,j,t)−f(i−x,j−y,t−1)∣.(2)

(3) ∣ f ( i − x , j − y , t − 1 ) ∣ − ∣ f ( i , j , t ) ∣ ≤ ∣ f ( i , j , t ) − f ( i − x , j − y , t − 1 ) ∣ . |f(i - x, j - y, t - 1)| - |f(i, j, t)| \leq |f(i, j, t) - f(i - x, j - y, t - 1)|. \tag{3} ∣f(i−x,j−y,t−1)∣−∣f(i,j,t)∣≤∣f(i,j,t)−f(i−x,j−y,t−1)∣.(3)

在这里x、y表示的是运动向量并且其取值范围为 [-M, M]。然后将(2)和(3)式遍历块中所有像素,并求和得到:

(4) ∑ i = 1 N ∑ j = 1 N ∣ f ( i , j , t ) ∣ − ∑ i = 1 N ∑ j = 1 N ∣ f ( i − x , j − y , t − 1 ) ∣ ≤ ∑ i = 1 N ∑ j = 1 N ∣ f ( i , j , t ) − f ( i − x , j − y , t − 1 ) ∣ . \sum_{i = 1}^{N}\sum_{j = 1}^{N}|f(i, j, t)| - \sum_{i = 1}^{N}\sum_{j = 1}^{N}|f(i - x, j - y, t - 1)| \leq \sum_{i = 1}^{N}\sum_{j = 1}^{N}|f(i, j, t) - f(i - x, j - y, t - 1)|. \tag{4} i=1∑N​j=1∑N​∣f(i,j,t)∣−i=1∑N​j=1∑N​∣f(i−x,j−y,t−1)∣≤i=1∑N​j=1∑N​∣f(i,j,t)−f(i−x,j−y,t−1)∣.(4)

(5) ∑ i = 1 N ∑ j = 1 N ∣ f ( i − x , j − y , t − 1 ) ∣ − ∑ i = 1 N ∑ j = 1 N ∣ f ( i , j , t ) ∣ ≤ ∑ i = 1 N ∑ j = 1 N ∣ f ( i , j , t ) − f ( i − x , j − y , t − 1 ) ∣ . \sum_{i = 1}^{N}\sum_{j = 1}^{N}|f(i - x, j - y, t - 1)| - \sum_{i = 1}^{N}\sum_{j = 1}^{N}|f(i, j, t)| \leq \sum_{i = 1}^{N}\sum_{j = 1}^{N}|f(i, j, t) - f(i - x, j - y, t - 1)|. \tag{5} i=1∑N​j=1∑N​∣f(i−x,j−y,t−1)∣−i=1∑N​j=1∑N​∣f(i,j,t)∣≤i=1∑N​j=1∑N​∣f(i,j,t)−f(i−x,j−y,t−1)∣.(5)

将其用特殊符号表示,得到下式,分别于(4)、(5)两式对应。

(6) R − M ( x , y ) ≤ M A D ( x , y ) . R - M(x, y) \leq MAD(x, y). \tag{6} R−M(x,y)≤MAD(x,y).(6)

(7) M ( x , y ) − R ≤ M A D ( x , y ) . M(x, y) - R \leq MAD(x, y). \tag{7} M(x,y)−R≤MAD(x,y).(7)

假设在块匹配的最开始,我们得到一个起始运动向量 (m, n),对应MAD(m, n)。显然,为获取更佳的匹配坐标,我们需要去关注运动向量 (x, y),其满足下式:

(8) M A D ( x , y ) ≤ M A D ( m , n ) . MAD(x, y) \leq MAD(m, n). \tag{8} MAD(x,y)≤MAD(m,n).(8)

进而得到:

(9) ∣ R − M ( x , y ) ∣ ≤ M A D ( m , n ) . |R - M(x, y)| \leq MAD(m, n). \tag{9} ∣R−M(x,y)∣≤MAD(m,n).(9)

式(9)就是用于SEA算法的不等式。具体详细的计算只会对满足这个不等式的块执行,其数量显然小于搜索窗中所有块的数量。因此,在此基础上,就可以得到一个降低搜索匹配过程复杂度,当并没有将最佳选项排除在外的块匹配算法。但是,该算法的效率也就由不等式中的求和运算速度起始运动向量决定。

应用实例

该算法在x265编码器中有具体的实现。以下是其代码。

case X265_SEA:{// Successive Elimination Algorithm// omv -> current search origin or starting point//mvmin 和 mvmax 表示运动向量的范围//merange 表示搜索范围--搜索窗口的大小const int16_t minX = X265_MAX(omv.x - (int16_t)merange, mvmin.x);  //这里计算出了运动向量的变动范围const int16_t minY = X265_MAX(omv.y - (int16_t)merange, mvmin.y);const int16_t maxX = X265_MIN(omv.x + (int16_t)merange, mvmax.x);const int16_t maxY = X265_MIN(omv.y + (int16_t)merange, mvmax.y);const uint16_t *p_cost_mvx = m_cost_mvx - qmvp.x;const uint16_t *p_cost_mvy = m_cost_mvy - qmvp.y;int16_t* meScratchBuffer = NULL;int scratchSize = merange * 2 + 4;if (scratchSize){meScratchBuffer = X265_MALLOC(int16_t, scratchSize);memset(meScratchBuffer, 0, sizeof(int16_t)* scratchSize);}/* SEA is fastest in multiples of 4 */int meRangeWidth = (maxX - minX + 3) & ~3;int w = 0, h = 0;                    // Width and height of the PUALIGN_VAR_32(pixel, zero[64 * FENC_STRIDE]) = { 0 }; // ALIGN_VAR_32(int, encDC[4]);uint16_t *fpelCostMvX = m_fpelMvCosts[-qmvp.x & 3] + (-qmvp.x >> 2);sizesFromPartition(partEnum, &w, &h);int deltaX = (w <= 8) ? (w) : (w >> 1); //若源矩阵可分离则为width/2,否则为widthint deltaY = (h <= 8) ? (h) : (h >> 1); //同上 height/* Check if very small rectangular blocks which cannot be sub-divided anymore */bool smallRectPartition = partEnum == LUMA_4x4 || partEnum == LUMA_16x12 ||partEnum == LUMA_12x16 || partEnum == LUMA_16x4 || partEnum == LUMA_4x16;/* Check if vertical partition */bool verticalRect = partEnum == LUMA_32x64 || partEnum == LUMA_16x32 || partEnum == LUMA_8x16 ||partEnum == LUMA_4x8;/* Check if horizontal partition */bool horizontalRect = partEnum == LUMA_64x32 || partEnum == LUMA_32x16 || partEnum == LUMA_16x8 ||partEnum == LUMA_8x4;/* Check if assymetric vertical partition */bool assymetricVertical = partEnum == LUMA_12x16 || partEnum == LUMA_4x16 || partEnum == LUMA_24x32 ||partEnum == LUMA_8x32 || partEnum == LUMA_48x64 || partEnum == LUMA_16x64;/* Check if assymetric horizontal partition */bool assymetricHorizontal = partEnum == LUMA_16x12 || partEnum == LUMA_16x4 || partEnum == LUMA_32x24 ||partEnum == LUMA_32x8 || partEnum == LUMA_64x48 || partEnum == LUMA_64x16;int tempPartEnum = 0;/* If a vertical rectangular partition, it is horizontally split into two, for ads_x2() */if (verticalRect)tempPartEnum = partitionFromSizes(w, h >> 1);/* If a horizontal rectangular partition, it is vertically split into two, for ads_x2() */else if (horizontalRect)tempPartEnum = partitionFromSizes(w >> 1, h);/* We have integral planes introduced to account for assymetric partitions.* Hence all assymetric partitions except those which cannot be split into legal sizes,* are split into four for ads_x4() */else if (assymetricVertical || assymetricHorizontal)tempPartEnum = smallRectPartition ? partEnum : partitionFromSizes(w >> 1, h >> 1);/* General case: Square partitions. All partitions with width > 8 are split into four* for ads_x4(), for 4x4 and 8x8 we do ads_x1() */elsetempPartEnum = (w <= 8) ? partEnum : partitionFromSizes(w >> 1, h >> 1);/* Successive elimination by comparing DC before a full SAD,* because sum(abs(diff)) >= abs(diff(sum)). */ primitives.pu[tempPartEnum].sad_x4(zero,fenc,fenc + deltaX,fenc + deltaY * FENC_STRIDE,fenc + deltaX + deltaY * FENC_STRIDE,FENC_STRIDE,encDC);  //fenc为64x64+8的数组,所有stride为64(FENC_STRIDE)//encDC表示当前块的绝对值求和/* Assigning appropriate integral plane */uint32_t *sumsBase = NULL;switch (deltaX){case 32: if (deltaY % 24 == 0)sumsBase = integral[1];else if (deltaY == 8)sumsBase = integral[2];elsesumsBase = integral[0];break;case 24: sumsBase = integral[3];break;case 16: if (deltaY % 12 == 0)sumsBase = integral[5];else if (deltaY == 4)sumsBase = integral[6];elsesumsBase = integral[4];break;case 12: sumsBase = integral[7];break;case 8: if (deltaY == 32)sumsBase = integral[8];elsesumsBase = integral[9];break;case 4: if (deltaY == 16)sumsBase = integral[10];elsesumsBase = integral[11];break;default: sumsBase = integral[11]; //搜索窗口所有尺寸块的绝对值求和break;}if (partEnum == LUMA_64x64 || partEnum == LUMA_32x32 || partEnum == LUMA_16x16 ||partEnum == LUMA_32x64 || partEnum == LUMA_16x32 || partEnum == LUMA_8x16 ||partEnum == LUMA_4x8 || partEnum == LUMA_12x16 || partEnum == LUMA_4x16 ||partEnum == LUMA_24x32 || partEnum == LUMA_8x32 || partEnum == LUMA_48x64 ||partEnum == LUMA_16x64)deltaY *= (int)stride;if (verticalRect)encDC[1] = encDC[2];if (horizontalRect)deltaY = deltaX;/* ADS and SAD */MV tmv;for (tmv.y = minY; tmv.y <= maxY; tmv.y++){int i, xn;int ycost = p_cost_mvy[tmv.y] << 2;if (bcost <= ycost)continue;bcost -= ycost;/* ADS_4 for 16x16, 32x32, 64x64, 24x32, 32x24, 48x64, 64x48, 32x8, 8x32, 64x16, 16x64 partitions* ADS_1 for 4x4, 8x8, 16x4, 4x16, 16x12, 12x16 partitions* ADS_2 for all other rectangular partitions */xn = ads(encDC,sumsBase + minX + tmv.y * stride,deltaY,fpelCostMvX + minX,meScratchBuffer,meRangeWidth,bcost); //bcost表示参考帧和当前帧中对应块的残差//fpelCostMvX表示向量中x元素所需的比特数for (i = 0; i < xn - 2; i += 3)COST_MV_X3_ABS(minX + meScratchBuffer[i], tmv.y,minX + meScratchBuffer[i + 1], tmv.y,minX + meScratchBuffer[i + 2], tmv.y); //fenc和fref的ABS + 向量x元素所需要的比特数 比较更新bcostbcost += ycost; for (; i < xn; i++)COST_MV(minX + meScratchBuffer[i], tmv.y); //fenc和fref的ABS + 向量x y元素所需要的比特数 比较更新bcost}if (meScratchBuffer)x265_free(meScratchBuffer);break;}

x265的实现还是比较复杂,这里就不具体展开了,但其核心代码还是能体现出SEA的思想的。该算法的其他内容可以参考下面这个论文。

[1] W. LI and E. Salari. Successive Elimination Algorithm for Motion Estimation. IEEE TRANSACRTIONS ON IMAGE PROCESSING.

连续消除算法-SEA(Successive Elimination Algorithm)相关推荐

  1. 【Codec系列】连续消除算法-SEA(Successive Elimination Algorithm)

    连续消除算法-SEA(Successive Elimination Algorithm)

  2. 连续投影算法-python版

    连续投影算法 - SPA python版 文章目录 连续投影算法 - SPA python版 原理 连续投影算法大量用于光谱特征波长选择中,翻遍全网,SPA算法只找到了MATLAB版本. 该版本为MA ...

  3. 【转载】(EM算法)The EM Algorithm

    (EM算法)The EM Algorithm EM是我一直想深入学习的算法之一,第一次听说是在NLP课中的HMM那一节,为了解决HMM的参数估计问题,使用了EM算法.在之后的MT中的词对齐中也用到了. ...

  4. 群体智能优化算法之细菌觅食优化算法(Bacterial Foraging Optimization Algorithm,BFOA)

    获取更多资讯,赶快关注上面的公众号吧! 文章目录 第十四章 细菌觅食优化算法 14.1 介绍 14.2 BFOA的基本原理与流程 14.2.1 趋向性操作 14.2.2 复制操作 14.2.3 迁徙操 ...

  5. 滑动窗口算法(Sliding Window Algorithm)

    目录 滑动窗口算法(Sliding Window Algorithm) 一.基本示例 二.经典使用 1. 连续元素最大和 题目 解法及分析 2. 最长无重复子字符串 题目 解法及分析 三.参考资料 滑 ...

  6. 黑寡妇优化算法(Black Widow Optimization Algorithm, BWOA)

    文章目录 一.理论基础 1.数学模型 1.1 移动 1.2 信息素 2.算法伪代码 二.总结 参考文献 一.理论基础 黑寡妇优化算法(Black Widow Optimization Algorith ...

  7. EM算法(Expectation Maximization Algorithm)详解

    EM算法(Expectation Maximization Algorithm)详解 主要内容 EM算法简介 预备知识  极大似然估计 Jensen不等式 EM算法详解  问题描述 EM算法推导 EM ...

  8. 文献记录(part69)--公平性机器学习中基于分类间隔的歧视样本发现和消除算法

    学习笔记,仅供参考,有错必纠 关键词:公平性学习 , 分类间隔 , 目标集 , 加权距离度量 , 歧视性 公平性机器学习中基于分类间隔的歧视样本发现和消除算法 摘要 公平性学习是机器学习领域的研究热点 ...

  9. 感知哈希算法(Perceptual hash algorithm)的OpenCV实现

    1.前言 目前"以图搜图"的引擎越来越多,可参考博文: http://blog.csdn.net/forthcriminson/article/details/8698175 此篇 ...

最新文章

  1. Windows核心编程 第十一章 线程池的使用
  2. unity中单位是米还是厘米_小学数学常用单位换算汇总,收藏起来方便孩子查阅...
  3. LoadRunner参数包含逗号
  4. python enumerate用法总结(转)
  5. 如何在屏幕实时显示自己键盘的输入字符?
  6. matlab mex gcc 支持c99
  7. 海量数据处理的 Top K相关问题
  8. 转--计算几何常用算法概览
  9. jQuery最新1.4 版本的十五个新特性
  10. 鸿蒙系统麒麟970芯片支持,受鸿蒙系统影响,众多华为手机或要说再见,包括麒麟970机型!...
  11. numpy flatten
  12. android 播放视频文件格式,安卓播放exe视频,如何将exe格式视频转换成常用格式视频...
  13. bypass-wts-waf
  14. ai如何旋转画布_ai怎么让一个图形等比旋转
  15. 关于Arduino连接L298N供电问题
  16. 利用springMVC实现购物车结算功能
  17. 飞机大战实现--c++
  18. float double表示的有效位数
  19. 佳能Canon PIXMA MG2550 打印机驱动
  20. Linux内核有没有rootfs,Linux内核rootfs的初始化过程

热门文章

  1. 服务器网线灯闪烁显示未插入,无线路由器的灯都在闪,但是始终显示WAN 未连接,网线没有插好...
  2. iOS(Swift3)中添加通讯录、添加图片到图库、添加视频到图库
  3. 计算机跨界之科技金融
  4. Excel的按钮无法删除怎么办
  5. Linux基础——别名(alias)
  6. 小米手机怎么设置取消默认打开应用?
  7. 脱单盲盒H5版本,配置七牛云教程,脱单盲盒交友2.0.1版教程
  8. Python Unicode入门指南
  9. 按键精灵——For循环浅层理解
  10. 2023最新SSM计算机毕业设计选题大全(附源码+LW)之java网上水果商城s7436