VTM3.0代码阅读:xGetLMParameters函数

xGetLMParameters在predIntraChromaLM函数中被调用,来获取MMLM和MDLM模式的线性模型参数。
函数搜寻参考像素中亮度像素的最大最小点,保存两个点的luma和chroma值。
由保存的亮度像素最大最小点的值即可确定线性模型参数a、b、shift。

void IntraPrediction::xGetLMParameters(const PredictionUnit &pu, const ComponentID compID,
                                              const CompArea &chromaArea,
                                              int &a, int &b, int &iShift)
{
  CHECK(compID == COMPONENT_Y, "");

  const SizeType cWidth  = chromaArea.width;
  const SizeType cHeight = chromaArea.height;

  const Position posLT = chromaArea;

  CodingStructure & cs = *(pu.cs);
  const CodingUnit &cu = *(pu.cu);

  const SPS &        sps           = *cs.sps;
  const uint32_t     tuWidth     = chromaArea.width;
  const uint32_t     tuHeight    = chromaArea.height;
  const ChromaFormat nChromaFormat = sps.getChromaFormatIdc();

  const int baseUnitSize = 1 << MIN_CU_LOG2;	//亮度4x4,色度2x2
  const int unitWidth    = baseUnitSize >> getComponentScaleX(chromaArea.compID, nChromaFormat);
  const int unitHeight   = baseUnitSize >> getComponentScaleX(chromaArea.compID, nChromaFormat);

  const int tuWidthInUnits  = tuWidth / unitWidth;
  const int tuHeightInUnits = tuHeight / unitHeight;
  const int aboveUnits      = tuWidthInUnits;
  const int leftUnits       = tuHeightInUnits;		//长和宽包含的2x2基本块的数目
#if JVET_L0338_MDLM
  int topTemplateSampNum = 2 * cWidth; // for MDLM, the template sample number is 2W or 2H;
  int leftTemplateSampNum = 2 * cHeight;				//MDLM模式的参考像素模板的宽长分别为2W、2H
  assert(m_topRefLength >= topTemplateSampNum);
  assert(m_leftRefLength >= leftTemplateSampNum);
  int totalAboveUnits = (topTemplateSampNum + (unitWidth - 1)) / unitWidth;
  int totalLeftUnits = (leftTemplateSampNum + (unitHeight - 1)) / unitHeight;
  int totalUnits = totalLeftUnits + totalAboveUnits + 1;	//左下、左、左上、上、右上   五个区域包含的base块数目
  int aboveRightUnits = totalAboveUnits - aboveUnits;
  int leftBelowUnits = totalLeftUnits - leftUnits;	//右上和左下包含的2x2基本块的数目
  int avaiAboveRightUnits = 0;
  int avaiLeftBelowUnits = 0;
  int avaiAboveUnits = 0;
  int avaiLeftUnits = 0;		//4个区域可用参考小块的数目

  int curChromaMode = pu.intraDir[1];		//色度帧内模式
#endif
  bool neighborFlags[4 * MAX_NUM_PART_IDXS_IN_CTU_WIDTH + 1];
#if JVET_L0338_MDLM
  memset(neighborFlags, 0, totalUnits);
#else
  memset(neighborFlags, 0, 1 + leftUnits + aboveUnits);
#endif

  bool aboveAvailable, leftAvailable;		//上侧和左侧块是否可用

  int availableUnit =
    isAboveAvailable(cu, CHANNEL_TYPE_CHROMA, posLT, aboveUnits, unitWidth, 
#if JVET_L0338_MDLM
    (neighborFlags + leftUnits + leftBelowUnits + 1));
#else
    (neighborFlags + leftUnits + 1));
#endif
  aboveAvailable = availableUnit == tuWidthInUnits;		//上侧2x2小块均可用时,才标记上侧块可用

  availableUnit =
    isLeftAvailable(cu, CHANNEL_TYPE_CHROMA, posLT, leftUnits, unitHeight, 
#if JVET_L0338_MDLM
    (neighborFlags + leftUnits + leftBelowUnits - 1));
#else
    (neighborFlags + leftUnits - 1));
#endif
  leftAvailable = availableUnit == tuHeightInUnits;		//左侧2x2小块均可用时,才标记上侧块可用
#if JVET_L0338_MDLM
  if (leftAvailable) // if left is not available, then the below left is not available
  {					 //如果左侧块不可用,那么左下块也就不可用
    avaiLeftUnits = tuHeightInUnits;
    avaiLeftBelowUnits = isBelowLeftAvailable(cu, CHANNEL_TYPE_CHROMA, chromaArea.bottomLeftComp(chromaArea.compID), leftBelowUnits, unitHeight, (neighborFlags + leftBelowUnits - 1));
  }
  if (aboveAvailable) // if above is not available, then  the above right is not available.
  {					  //如果上侧块不可用,那么右上块也就不可用
    avaiAboveUnits = tuWidthInUnits;
    avaiAboveRightUnits = isAboveRightAvailable(cu, CHANNEL_TYPE_CHROMA, chromaArea.topRightComp(chromaArea.compID), aboveRightUnits, unitWidth, (neighborFlags + leftUnits + leftBelowUnits + aboveUnits + 1));
  }			//这里记录左下、左、上、右上4个区域的分别可用2x2小块的数目
#endif

  Pel *srcColor0, *curChroma0;
  int  srcStride, curStride;

  PelBuf temp;
#if JVET_L0338_MDLM
  if ((curChromaMode == MDLM_L_IDX) || (curChromaMode == MDLM_T_IDX))
  {			// LM_L、LM_T
    srcStride = 2 * MAX_CU_SIZE + 1;
    temp = PelBuf(m_pMdlmTemp + srcStride + 1, srcStride, Size(chromaArea));
  }
  else		// MMLM
  {
#endif
  srcStride = MAX_CU_SIZE + 1;
  temp        = PelBuf(m_piTemp + srcStride + 1, srcStride, Size(chromaArea));
#if JVET_L0338_MDLM
  }		//m_pMdlmTemp和m_piTemp存储参考像素和pu中luma像素的采样值,temp指针指向pu中的第一个采样像素
#endif
  ///以上的代码和xGetLumaRecPixels()函数中一样
  srcColor0 = temp.bufAt(0, 0);			//亮度重建采样像素
  curChroma0 = getPredictorPtr(compID);	//compID的未滤波pu参考像素(色度像素)

  curStride = m_topRefLength + 1;

  curChroma0 += curStride + 1;		//指向pu最开始像素点

  unsigned internalBitDepth = sps.getBitDepth(CHANNEL_TYPE_CHROMA);

  int minLuma[2] = { MAX_INT, 0 };
  int maxLuma[2] = { -MAX_INT, 0 };		//找到亮度最大和最小的像素点,用来构造线性模型

  Pel *src = srcColor0 - srcStride;		//都指向Above的第一个像素点
  Pel *cur = curChroma0 - curStride;	//因为亮度2:1采样过,所以两者长度大小相等
#if JVET_L0338_MDLM
  int minDim = 1;
  int actualTopTemplateSampNum = 0;
  int actualLeftTemplateSampNum = 0;
  if (curChromaMode == MDLM_T_IDX)	//LM_T
  {
    leftAvailable = 0;
    actualTopTemplateSampNum = unitWidth*(avaiAboveUnits + avaiAboveRightUnits);
    minDim = actualTopTemplateSampNum;		//上 右上侧可用像素数
  }
  else if (curChromaMode == MDLM_L_IDX)	//LM_L
  {
    aboveAvailable = 0;
    actualLeftTemplateSampNum = unitHeight*(avaiLeftUnits + avaiLeftBelowUnits);
    minDim = actualLeftTemplateSampNum;		//左 左下侧可用像素数
  }
  else if (curChromaMode == LM_CHROMA_IDX)	//LM
  {
    actualTopTemplateSampNum = cWidth;
    actualLeftTemplateSampNum = cHeight;	//4区域可用像素数
    minDim = leftAvailable && aboveAvailable ? 1 << g_aucPrevLog2[std::min(actualLeftTemplateSampNum, actualTopTemplateSampNum)]
      : 1 << g_aucPrevLog2[leftAvailable ? actualLeftTemplateSampNum : actualTopTemplateSampNum];
  }
#endif

  int numSteps = minDim;

  if (aboveAvailable)		//上
  {
    for (int j = 0; j < numSteps; j++)
    {
#if JVET_L0338_MDLM
      int idx = (j * actualTopTemplateSampNum) / minDim;
#else
      int idx = (j * cWidth) / minDim;
#endif

      if (minLuma[0] > src[idx])		//找亮度最小最大点,存储对应的luma和chroma像素值
      {
        minLuma[0] = src[idx];
        minLuma[1] = cur[idx];
      }
      if (maxLuma[0] < src[idx])
      {
        maxLuma[0] = src[idx];
        maxLuma[1] = cur[idx];
      }
    }
  }

  if (leftAvailable)	//左
  {
    src = srcColor0 - 1;		//指向左上
    cur = curChroma0 - 1;

    for (int i = 0; i < numSteps; i++)
    {
#if JVET_L0338_MDLM
      int idx = (i * actualLeftTemplateSampNum) / minDim;
#else
      int idx = (i * cHeight) / minDim;
#endif

      if (minLuma[0] > src[srcStride * idx])	//找亮度最小最大点,存储对应的luma和chroma像素值
      {
        minLuma[0] = src[srcStride * idx];
        minLuma[1] = cur[curStride * idx];
      }
      if (maxLuma[0] < src[srcStride * idx])
      {
        maxLuma[0] = src[srcStride * idx];
        maxLuma[1] = cur[curStride * idx];
      }
    }
  }

  if ((leftAvailable || aboveAvailable))		//确定线性参数a、b、shift
  {
    a         = 0;
    iShift    = 16;
    int shift = (internalBitDepth > 8) ? internalBitDepth - 9 : 0;
    int add   = shift ? 1 << (shift - 1) : 0;
    int diff  = (maxLuma[0] - minLuma[0] + add) >> shift;
    if (diff > 0)
    {
      int div = ((maxLuma[1] - minLuma[1]) * g_aiLMDivTableLow[diff - 1] + 32768) >> 16;
      a       = (((maxLuma[1] - minLuma[1]) * g_aiLMDivTableHigh[diff - 1] + div + add) >> shift);
    }
    b = minLuma[1] - ((a * minLuma[0]) >> iShift);
  }
  else
  {
    a = 0;

    b = 1 << (internalBitDepth - 1);

    iShift = 0;
  }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值