HM代码阅读4:运动估计函数Void TEncSearch::xMotionEstimation()和全搜索Void TEncSearch::xPatternSearch()

本文详细介绍了HEVC编码标准中运动估计的过程,包括小范围全搜索在B帧中的应用和大范围菱形搜索(TZSearch)。在全搜索算法中,首先设定搜索范围,然后计算每个整数点的SAD和运动矢量的bit数,通过比较形成cost,更新最优运动矢量。全搜索的实现关键在于xPatternSearch函数。
摘要由CSDN通过智能技术生成

HEVC中的运动估计采用的方法:
1、小范围内全搜索(主要用于B帧,第二次遍历计算出较小cost的MV)
2、大范围内菱形搜索(TZSearch)

全搜索
1、设置好搜索范围,获取当前PU在参考帧重建帧中的位置,获取重建帧的步幅(包含padding)
2、遍历完范围内的所有整数点,逐像素作差得到SAD,获取编码运动矢量的bit数,加在一起形成cost,如果当前SAD比之前最好的SAD小,那么将当前运动矢量x,y赋给rcMV,cost赋给ruiCost

/*
基于当前最优MVP做运动估计:
Input:
1、当前CU
2、当前原始图像的Yuv数据(对应CU大小)
3、当前PU的索引
4、参考图像列表
5、当前参考帧最优MVP(cMvPred[iRefList][iRefIdxTemp])
6、参考帧索引
7、cMvTemp[iRefList][iRefIdxTemp]的引用,对当前参考帧最优MV会存在这里
8、编码所需bit数、RDcost
9、是不是双向运动估计
Output:
1、针对当前帧最优MV
2、针对当前数据编码的bit数以及RDcost大小
*/
Void TEncSearch::xMotionEstimation( TComDataCU* pcCU, TComYuv* pcYuvOrg, Int iPartIdx, RefPicList eRefPicList, TComMv* pcMvPred, Int iRefIdxPred, TComMv& rcMv, UInt& ruiBits, Distortion& ruiCost, Bool bBi  )
{
   
  UInt          uiPartAddr; //当前PU的起始4x4块的位置
  Int           iRoiWidth;
  Int           iRoiHeight;

  TComMv        cMvHalf, cMvQter; //亚精度、1/4精度
  TComMv        cMvSrchRngLT; // MV搜索范围
  TComMv        cMvSrchRngRB;

  TComYuv*      pcYuv = pcYuvOrg;

  assert(eRefPicList < MAX_NUM_REF_LIST_ADAPT_SR && iRefIdxPred<Int(MAX_IDX_ADAPT_SR));
  m_iSearchRange = m_aaiAdaptSR[eRefPicList][iRefIdxPred]; //cfg文件中会写明Search Range

  Int           iSrchRng      = ( bBi ? m_bipredSearchRange : m_iSearchRange ); //双向搜索范围:默认为4
  TComPattern   tmpPattern;
  TComPattern*  pcPatternKey  = &tmpPattern;

  Double        fWeight       = 1.0;

  pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight );

  if ( bBi ) // Bipredictive ME,用于第二次对cost较大的参考图像列表再搜索获取最优MV
  {
   
    TComYuv*  pcYuvOther = &m_acYuvPred[1-(Int)eRefPicList];
    pcYuv                = &m_cYuvPredTemp;

    pcYuvOrg->copyPartToPartYuv( pcYuv, uiPartAddr, iRoiWidth, iRoiHeight ); //先把原始像素值拷贝到当前pcYuv中

    pcYuv->removeHighFreq( pcYuvOther, uiPartAddr, iRoiWidth, iRoiHeight, pcCU->getSlice()->getSPS()->getBitDepths()
要实现 `CreateBinaryTree` 函数,可以根据给定的先序遍历序列构建二叉树。以下是该函数的实现: ```cpp #include <iostream> #include <queue> using namespace std; // 假设 BTNode 是一个定义好的二叉树节点类 template <class T> class BTNode { public: T data; BTNode<T> *left, *right; BTNode(T d = T(), BTNode<T> *l = nullptr, BTNode<T> *r = nullptr) : data(d), left(l), right(r) {} }; // 假设 BinaryTree 是一个定义好的二叉树类 template <class T> class BinaryTree { private: BTNode<T> *root; public: BinaryTree() : root(nullptr) {} ~BinaryTree() { Destroy(root); } void CreateBinaryTree(); void PreOrder(void (*visit)(const T&)) const; void InOrder(void (*visit)(const T&)) const; void PostOrder(void (*visit)(const T&)) const; void LevelOrder(void (*visit)(const T&)) const; int Width() const; int NodeCount() const; private: void Destroy(BTNode<T> *&node); void PreOrder(BTNode<T> *node, void (*visit)(const T&)) const; void InOrder(BTNode<T> *node, void (*visit)(const T&)) const; void PostOrder(BTNode<T> *node, void (*visit)(const T&)) const; int Width(BTNode<T> *node) const; int NodeCount(BTNode<T> *node) const; }; template <class T> void BinaryTree<T>::CreateBinaryTree() { queue<BTNode<T>*> q; char ch; cin >> ch; if (ch == '#') { root = nullptr; } else { root = new BTNode<T>(ch); q.push(root); } while (!q.empty()) { BTNode<T> *p = q.front(); q.pop(); cin >> ch; if (ch != '#') { p->left = new BTNode<T>(ch); q.push(p->left); } cin >> ch; if (ch != '#') { p->right = new BTNode<T>(ch); q.push(p->right); } } } template <class T> void BinaryTree<T>::PreOrder(void (*visit)(const T&)) const { PreOrder(root, visit); } template <class T> void BinaryTree<T>::InOrder(void (*visit)(const T&)) const { InOrder(root, visit); } template <class T> void BinaryTree<T>::PostOrder(void (*visit)(const T&)) const { PostOrder(root, visit); } template <class T> void BinaryTree<T>::LevelOrder(void (*visit)(const T&)) const { if (root == nullptr) return; queue<BTNode<T>*> q; q.push(root); while (!q.empty()) { BTNode<T> *p = q.front(); q.pop(); visit(p->data); if (p->left) q.push(p->left); if (p->right) q.push(p->right); } } template <class T> int BinaryTree<T>::Width() const { return Width(root); } template <class T> int BinaryTree<T>::NodeCount() const { return NodeCount(root); } template <class T> void BinaryTree<T>::Destroy(BTNode<T> *&node) { if (node) { Destroy(node->left); Destroy(node->right); delete node; node = nullptr; } } template <class T> void BinaryTree<T>::PreOrder(BTNode<T> *node, void (*visit)(const T&)) const { if (node) { visit(node->data); PreOrder(node->left, visit); PreOrder(node->right, visit); } } template <class T> void BinaryTree<T>::InOrder(BTNode<T> *node, void (*visit)(const T&)) const { if (node) { InOrder(node->left, visit); visit(node->data); InOrder(node->right, visit); } } template <class T> void BinaryTree<T>::PostOrder(BTNode<T> *node, void (*visit)(const T&)) const { if (node) { PostOrder(node->left, visit); PostOrder(node->right, visit); visit(node->data); } } template <class T> int BinaryTree<T>::Width(BTNode<T> *node) const { if (node == nullptr) return 0; int maxWidth = 0, thisLevel = 1, nextLevel = 0; queue<BTNode<T>*> q; q.push(node); while (!q.empty()) { BTNode<T> *p = q.front(); q.pop(); thisLevel--; if (p->left) { q.push(p->left); nextLevel++; } if (p->right) { q.push(p->right); nextLevel++; } if (thisLevel == 0) { if (nextLevel > maxWidth) maxWidth = nextLevel; thisLevel = nextLevel; nextLevel = 0; } } return maxWidth; } template <class T> int BinaryTree<T>::NodeCount(BTNode<T> *node) const { if (node == nullptr) return 0; return 1 + NodeCount(node->left) + NodeCount(node->right); } ``` ### 解释 1. **CreateBinaryTree**: - 使用队列来辅助层次遍历。 - 按照先序遍历的顺序读取字符,遇到 '#' 表示空节点。 - 构建根节点并将其加入队列。 - 依次处理队列中的节点,为其创建左右子节点,并将非空子节点加入队列。 2. **其他方法**: - `PreOrder`, `InOrder`, `PostOrder`, 和 `LevelOrder` 分别实现了前序、中序、后序和层序遍历。 - `Width` 计算二叉树的最大宽度。 - `NodeCount` 计算二叉树的节点数。 - `Destroy` 用于销毁二叉树,释放内存。 这样,你可以根据给定的先序遍历序列构建二叉树,并进行各种遍历操作和其他计算。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值