VVC/JEM代码学习26:xIntraCodingTUBlockTM

26 篇文章 2 订阅

       考虑到帧内和帧间有很多相似的patches,H.266提出了信号独立变换(SDT)技术,利用这样的相关性通过KLT的方法提高编码效率。这个训练的KLT扮演了一个转换的角色,旨在更有效地压缩能量。

      通过本函数来实现SDT技术,在此函数中,首先,获得了一个由重构的左上模板t_b和编码块的预测块p组成的参考patch R。然后,使用参考patch在重建区域搜索N个最相似的patch,得到预测块。最后,基于这些块和预测块训练一维的KLT。然后把训练好的KLT用于残差的变换。此函数在现有JEM中是默认关闭的,此代码只关注KLT的部分。

#if VCEG_AZ08_INTRA_KLT
Bool TEncSearch::xIntraCodingTUBlockTM(TComYuv*    pcOrgYuv,
    TComYuv*    pcPredYuv,
    TComYuv*    pcResiYuv,
    Distortion& ruiDist,
    const ComponentID compID,
    TComTU&     rTu
    DEBUG_STRING_FN_DECLARE(sDebug)
#if COM16_C806_EMT
    , UInt*      puiSigNum
#endif
    , Int tmpred0_tmpredklt1_ori2
    )
{
    if (!rTu.ProcessComponentSection(compID))
    {
        return false; 
    }
    const Bool           bIsLuma = isLuma(compID);
    const TComRectangle &rect = rTu.getRect(compID);
    TComDataCU    *pcCU = rTu.getCU();
    const UInt           uiAbsPartIdx = rTu.GetAbsPartIdxTU();
    const TComSPS       &sps = *(pcCU->getSlice()->getSPS());

#if JVET_C0024_QTBT
    UInt uiWIdx = g_aucConvertToBit[pcCU->getWidth(0)];
    UInt uiHIdx = g_aucConvertToBit[pcCU->getHeight(0)];
    assert(uiWIdx == uiHIdx);
    //const UInt           uiLog2TrSize = ((uiWIdx+uiHIdx)>>1) + MIN_CU_LOG2; 
#else
    const UInt           uiTrDepth = rTu.GetTransformDepthRelAdj(compID);
    const UInt           uiFullDepth = rTu.GetTransformDepthTotal();
    const UInt           uiLog2TrSize = rTu.GetLog2LumaTrSize();
#endif
    const ChannelType    chType = toChannelType(compID);
    const Int            bitDepth = sps.getBitDepth(chType);

    const UInt           uiWidth = rect.width;
    const UInt           uiHeight = rect.height;
    const UInt           uiStride = pcOrgYuv->getStride(compID);
    Pel           *piOrg = pcOrgYuv->getAddr(compID, uiAbsPartIdx);
    Pel           *piPred = pcPredYuv->getAddr(compID, uiAbsPartIdx);
    Pel           *piResi = pcResiYuv->getAddr(compID, uiAbsPartIdx);
    Pel           *piReco = pcPredYuv->getAddr(compID, uiAbsPartIdx);
#if JVET_C0024_QTBT
    Pel           *piRecQt = m_ppcQTTempTComYuv[uiWIdx][uiHIdx].getAddr(compID, uiAbsPartIdx);
    const UInt           uiRecQtStride = m_ppcQTTempTComYuv[uiWIdx][uiHIdx].getStride(compID);
#else
    const UInt           uiQTLayer = sps.getQuadtreeTULog2MaxSize() - uiLog2TrSize;
    Pel           *piRecQt = m_pcQTTempTComYuv[uiQTLayer].getAddr(compID, uiAbsPartIdx);
    const UInt           uiRecQtStride = m_pcQTTempTComYuv[uiQTLayer].getStride(compID);
#endif
    const UInt           uiZOrder = pcCU->getZorderIdxInCtu() + uiAbsPartIdx;
    Pel           *piRecIPred = pcCU->getPic()->getPicYuvRec()->getAddr(compID, pcCU->getCtuRsAddr(), uiZOrder);
    UInt           uiRecIPredStride = pcCU->getPic()->getPicYuvRec()->getStride(compID);
#if JVET_C0024_QTBT
    TCoeff        *pcCoeff = m_pppcQTTempCoeff[compID][uiWIdx][uiHIdx] + rTu.getCoefficientOffset(compID);
#else
    TCoeff        *pcCoeff = m_ppcQTTempCoeff[compID][uiQTLayer] + rTu.getCoefficientOffset(compID);
#endif
    Bool           useTransformSkip = pcCU->getTransformSkip(uiAbsPartIdx, compID);

#if ADAPTIVE_QP_SELECTION
#if JVET_C0024_QTBT
    TCoeff        *pcArlCoeff = m_pppcQTTempArlCoeff[compID][uiWIdx][uiHIdx] + rTu.getCoefficientOffset(compID);
#else
    TCoeff        *pcArlCoeff = m_ppcQTTempArlCoeff[compID][uiQTLayer] + rTu.getCoefficientOffset(compID);
#endif
#endif

#if DEBUG_STRING
    const Int debugPredModeMask = DebugStringGetPredModeMask(MODE_INTRA);
#endif

#if COM16_C806_EMT
    UChar   ucTrIdx = (pcCU->getEmtCuFlag(uiAbsPartIdx) && compID == COMPONENT_Y) ? pcCU->getEmtTuIdx(uiAbsPartIdx) : (pcCU->getSlice()->getSPS()->getUseIntraEMT() ? DCT2_EMT : DCT2_HEVC);
#endif
    //===== init availability pattern =====
    DEBUG_STRING_NEW(sTemp)

#if VCEG_AZ08_INTRA_KLT
    Bool useKLT = false;
    if (tmpred0_tmpredklt1_ori2 != 2 && bIsLuma)//该技术只用于亮度分量
    {
        UInt uiBlkSize = uiWidth;
        UInt uiTarDepth = g_aucConvertToBit[uiBlkSize];
        UInt uiTempSize = g_uiDepth2IntraTempSize[uiTarDepth];
        m_pcTrQuant->getTargetTemplate(pcCU, uiAbsPartIdx, uiBlkSize, uiTempSize);//获取当前块的模板(即包括相邻左,上和左上的重建采样)
        m_pcTrQuant->candidateSearchIntra(pcCU, uiAbsPartIdx, uiBlkSize, uiTempSize);//为每个候选模板计算MSE
	
        Int foundCandiNum;
        Bool bSuccessful = m_pcTrQuant->generateTMPrediction(piPred, uiStride, uiBlkSize, uiTempSize, foundCandiNum);//通过候选模板得到当前块的预测块
        if (bSuccessful == false || foundCandiNum < 1)
        {
            return false;
        }
        if (1 == tmpred0_tmpredklt1_ori2 && bSuccessful)
        {
            useKLT = m_pcTrQuant->calcKLTIntra(piPred, uiStride, uiBlkSize);//训练KLT
        }
    }
#endif

    //===== get residual signal =====
    {
        // get residual
        Pel*  pOrg = piOrg;
        Pel*  pPred = piPred;
        Pel*  pResi = piResi;

        for (UInt uiY = 0; uiY < uiHeight; uiY++)
        {
            for (UInt uiX = 0; uiX < uiWidth; uiX++)
            {
                pResi[uiX] = pOrg[uiX] - pPred[uiX];
            }

            pOrg += uiStride;
            pResi += uiStride;
            pPred += uiStride;
        }
    }

    //===== transform and quantization =====
    //--- init rate estimation arrays for RDOQ ---
#if COM16_C806_EMT
    if ((useTransformSkip ? m_pcEncCfg->getUseRDOQTS() : m_pcEncCfg->getUseRDOQ()) && !(ucTrIdx >= 1 && ucTrIdx <= 3))
#else
    if (useTransformSkip ? m_pcEncCfg->getUseRDOQTS() : m_pcEncCfg->getUseRDOQ())
#endif
    {
      COEFF_SCAN_TYPE scanType = COEFF_SCAN_TYPE(pcCU->getCoefScanIdx(uiAbsPartIdx, uiWidth, uiHeight, compID));
      m_pcEntropyCoder->estimateBit(m_pcTrQuant->m_pcEstBitsSbac, uiWidth, uiHeight, chType, scanType);
    }

    //--- transform and quantization ---
    TCoeff uiAbsSum = 0;
#if !JVET_C0024_QTBT
    if (bIsLuma)
    {
        pcCU->setTrIdxSubParts(uiTrDepth, uiAbsPartIdx, uiFullDepth);
    }
#endif

    const QpParam cQP(*pcCU, compID);

#if RDOQ_CHROMA_LAMBDA
    m_pcTrQuant->selectLambda(compID);
#endif
    m_pcTrQuant->transformNxN(rTu, compID, piResi, uiStride, pcCoeff,
#if ADAPTIVE_QP_SELECTION
        pcArlCoeff,
#endif
        uiAbsSum, cQP
#if VCEG_AZ08_INTRA_KLT
        , useKLT
#endif
        );//如果useKLT为true,则进行KLT量化变换

#if COM16_C806_EMT
    if (ucTrIdx != DCT2_EMT && ucTrIdx != DCT2_HEVC)
    {
        *puiSigNum = 0;
        for (UInt uiX = 0; uiX < uiHeight*uiWidth; uiX++)
        {
            if (pcCoeff[uiX])
            {
                (*puiSigNum)++;
                if (*puiSigNum>g_iEmtSigNumThr)
                {
                    break;
                }
            }
        }

        if (ucTrIdx != 0 && *puiSigNum <= g_iEmtSigNumThr && !useTransformSkip)
        {
            return false;
        }
    }
#endif

    //--- inverse transform ---

#if DEBUG_STRING
    if ((uiAbsSum > 0) || (DebugOptionList::DebugString_InvTran.getInt()&debugPredModeMask))
#else
    if (uiAbsSum > 0)
#endif
    {
        const UInt *scan;
        if (useKLT)//如果使用KLT变换,反量化变换前先进行排序
        {
            TUEntropyCodingParameters codingParameters;
            getTUEntropyCodingParameters(codingParameters, rTu, compID);
            scan = codingParameters.scan;
            recoverOrderCoeff(pcCoeff, scan, uiWidth, uiHeight);
#if ADAPTIVE_QP_SELECTION
            recoverOrderCoeff(pcArlCoeff, scan, uiWidth, uiHeight);
#endif 
        }
        m_pcTrQuant->invTransformNxN(rTu, compID, piResi, uiStride, pcCoeff, cQP, useKLT DEBUG_STRING_PASS_INTO_OPTIONAL(&sDebug, (DebugOptionList::DebugString_InvTran.getInt()&debugPredModeMask)));
        if (useKLT)//如果使用KLT变换,反量化变换后进行逆排序
        {
            reOrderCoeff(pcCoeff, scan, uiWidth, uiHeight);
#if ADAPTIVE_QP_SELECTION
            reOrderCoeff(pcArlCoeff, scan, uiWidth, uiHeight);
#endif 
        }
    }
    else//uiAbsSum == 0
    {
        Pel* pResi = piResi;
        memset(pcCoeff, 0, sizeof(TCoeff)* uiWidth * uiHeight);
        for (UInt uiY = 0; uiY < uiHeight; uiY++)
        {
            memset(pResi, 0, sizeof(Pel)* uiWidth);//残差等于0
            pResi += uiStride;
        }
    }


    //===== reconstruction =====
    {
        Pel* pPred = piPred;
        Pel* pResi = piResi;
        Pel* pReco = piReco;
        Pel* pRecQt = piRecQt;
        Pel* pRecIPred = piRecIPred;

#if DEBUG_STRING
        std::stringstream ss(stringstream::out);
        const Bool bDebugPred = ((DebugOptionList::DebugString_Pred.getInt()&debugPredModeMask) && DEBUG_STRING_CHANNEL_CONDITION(compID));
        const Bool bDebugResi = ((DebugOptionList::DebugString_Resi.getInt()&debugPredModeMask) && DEBUG_STRING_CHANNEL_CONDITION(compID));
        const Bool bDebugReco = ((DebugOptionList::DebugString_Reco.getInt()&debugPredModeMask) && DEBUG_STRING_CHANNEL_CONDITION(compID));

        if (bDebugPred || bDebugResi || bDebugReco)
        {
            ss << "###: " << "CompID: " << compID << " pred mode (ch/fin): " << uiChPredMode << "/" << uiChFinalMode << " absPartIdx: " << rTu.GetAbsPartIdxTU() << "\n";
            for (UInt uiY = 0; uiY < uiHeight; uiY++)
            {
                ss << "###: ";
                if (bDebugPred)
                {
                    ss << " - pred: ";
                    for (UInt uiX = 0; uiX < uiWidth; uiX++)
                    {
                        ss << pPred[uiX] << ", ";
                    }
                }
                if (bDebugResi)
                {
                    ss << " - resi: ";
                }
                for (UInt uiX = 0; uiX < uiWidth; uiX++)
                {
                    if (bDebugResi)
                    {
                        ss << pResi[uiX] << ", ";
                    }
#if JVET_D0033_ADAPTIVE_CLIPPING
                    pReco[uiX] = Pel(ClipA<Int>(Int(pPred[uiX]) + Int(pResi[uiX]), compID));
#else
                    pReco[uiX] = Pel(ClipBD<Int>(Int(pPred[uiX]) + Int(pResi[uiX]), bitDepth));
#endif
                    pRecQt[uiX] = pReco[uiX];
                    pRecIPred[uiX] = pReco[uiX];
                }
                if (bDebugReco)
                {
                    ss << " - reco: ";
                    for (UInt uiX = 0; uiX < uiWidth; uiX++)
                    {
                        ss << pReco[uiX] << ", ";
                    }
                }
                pPred += uiStride;
                pResi += uiStride;
                pReco += uiStride;
                pRecQt += uiRecQtStride;
                pRecIPred += uiRecIPredStride;
                ss << "\n";
            }
            DEBUG_STRING_APPEND(sDebug, ss.str())
        }
        else
#endif
        {

            for (UInt uiY = 0; uiY < uiHeight; uiY++)
            {
                for (UInt uiX = 0; uiX < uiWidth; uiX++)
                {
#if JVET_D0033_ADAPTIVE_CLIPPING
                    pReco[uiX] = Pel(ClipA<Int>(Int(pPred[uiX]) + Int(pResi[uiX]), compID));
#else
                    pReco[uiX] = Pel(ClipBD<Int>(Int(pPred[uiX]) + Int(pResi[uiX]), bitDepth));
#endif
                    pRecQt[uiX] = pReco[uiX];
                    pRecIPred[uiX] = pReco[uiX];
                }
                pPred += uiStride;
                pResi += uiStride;
                pReco += uiStride;
                pRecQt += uiRecQtStride;
                pRecIPred += uiRecIPredStride;
            }
        }
    }
#if JVET_F0096_BILATERAL_FILTER  
    if(pcCU->getSlice()->getSPS()->getUseBilateralFilter())        
    {
      if (isLuma(compID))
      {
        if( uiAbsSum && (pcCU->getQP(COMPONENT_Y) > 17))
        {
          TComBilateralFilter::instance()->bilateralFilterIntra(pcCU, uiWidth, uiHeight, piReco, uiStride, pcCU->getQP(COMPONENT_Y));
          for( UInt uiY = 0; uiY < uiHeight; uiY++ )
          {
            memcpy(piRecQt + uiY * uiRecQtStride, piReco + uiY * uiStride, uiWidth * sizeof(Short));
            memcpy(piRecIPred + uiY * uiRecIPredStride, piReco + uiY * uiStride , uiWidth * sizeof(Short));
          }
        }
      }
    }
#endif
    //===== update distortion =====
#if WCG_LUMA_DQP_CM_SCALE
    if (m_pcEncCfg->getUseLumaDeltaQp() > 0) {
      UInt           iOrgStrideLuma         = pcOrgYuv ->getStride (COMPONENT_Y);
      Pel           *piOrgLuma            = pcOrgYuv ->getAddr( COMPONENT_Y, uiAbsPartIdx );
      ruiDist += m_pcRdCost->getDistPart( bitDepth, piReco, uiStride, piOrg, uiStride, uiWidth, uiHeight, compID, DF_SSE_WTD, piOrgLuma, iOrgStrideLuma);  // use weighted SSE
    }
    else
#endif
    ruiDist += m_pcRdCost->getDistPart(bitDepth, piReco, uiStride, piOrg, uiStride, uiWidth, uiHeight, compID);

    return true;
}
#endif
Void TComTrQuant::getTargetTemplate(TComDataCU *pcCU, UInt uiAbsPartIdx, UInt uiBlkSize, UInt uiTempSize)
{
    const ComponentID compID = COMPONENT_Y;
    UInt uiPatchSize = uiBlkSize + uiTempSize;//patch等于当前块加上当前相邻重建左,左上和上相邻采样模板
    UInt uiTarDepth = g_aucConvertToBit[uiBlkSize];
    Pel **tarPatch = m_pppTarPatch[uiTarDepth];
    UInt  uiZOrder = pcCU->getZorderIdxInCtu() + uiAbsPartIdx;
    Pel   *pCurrStart = pcCU->getPic()->getPicYuvRec()->getAddr(compID, pcCU->getCtuRsAddr(), uiZOrder);//指向当前CU
    UInt  uiPicStride = pcCU->getPic()->getStride(compID);
    UInt uiY, uiX;

    //fill template,填充模板,模板只包含左,左上,上、
    //up-left & up ,左上和上
    Pel  *tarTemp;//指向目标模板
    Pel  *pCurrTemp = pCurrStart - uiTempSize*uiPicStride - uiTempSize;//指向当前块的模板的最左上角
    for (uiY = 0; uiY < uiTempSize; uiY++)//填左上和上
    {
        tarTemp = tarPatch[uiY];
        for (uiX = 0; uiX < uiPatchSize; uiX++)
        {
            tarTemp[uiX] = pCurrTemp[uiX];
        }
        pCurrTemp += uiPicStride;//往下移一行
    }
    //left,左
    for (uiY = uiTempSize; uiY < uiPatchSize; uiY++)//填充左
    {
        tarTemp = tarPatch[uiY];
        for (uiX = 0; uiX < uiTempSize; uiX++)
        {
            tarTemp[uiX] = pCurrTemp[uiX];
        }
        pCurrTemp += uiPicStride;
    }
}
Void  TComTrQuant::searchCandidateFromOnePicIntra(TComDataCU *pcCU, UInt uiPartAddr, TComPic* refPicSrc, TComPicYuv *refPic, Pel **tarPatch, UInt uiPatchSize, UInt uiTempSize, UInt setId)
{
    const ComponentID compID = COMPONENT_Y;
    UInt uiBlkSize = uiPatchSize - uiTempSize;
    UInt uiTarDepth = g_aucConvertToBit[uiBlkSize];
    UInt uiTargetCandiNum = g_uiDepth2MaxCandiNum[uiTarDepth];
    if (TMPRED0_TMPREDKLT1_ORI2 == 0)//如果TMPRED0_TMPREDKLT1_ORI2 == 0,则把候选模板数量限制在8之内
    {
        uiTargetCandiNum = min((UInt)TMPRED_CANDI_NUM, uiTargetCandiNum);
    }
    UInt  uiLibSizeMinusOne = uiTargetCandiNum - 1;

    Int *pX = m_tempLibFast.getX();
    Int *pY = m_tempLibFast.getY();
    DistType *pDiff = m_tempLibFast.getDiff();
    Short *pId = m_tempLibFast.getId();
    Int     refStride = refPic->getStride(compID);
    Int zOrder = pcCU->getZorderIdxInCtu() + uiPartAddr;
    Pel *ref = refPic->getAddr(compID, pcCU->getCtuRsAddr(), zOrder);
    setRefPicUsed(setId, ref); //facilitate the access of each candidate point ,将参考图像设置为当前帧
    setStride(refPic->getStride(compID));

    Int     iSrchRng = SEARCHRANGEINTRA;//搜索范围等于64
    TComMv  cMvSrchRngLT;
    TComMv  cMvSrchRngRB;

    Int  iMvShift = 0;
    TComMv cTmpMvPred;
    cTmpMvPred.setZero();

    UInt uiCUPelY = pcCU->getCUPelY();
    UInt uiCUPelX = pcCU->getCUPelX();
    Int blkX = g_auiRasterToPelX[g_auiZscanToRaster[uiPartAddr]];
    Int blkY = g_auiRasterToPelY[g_auiZscanToRaster[uiPartAddr]];
    Int iCurrY = uiCUPelY + blkY;
    Int iCurrX = uiCUPelX + blkX;
    Int offsetLCUY = g_auiRasterToPelY[g_auiZscanToRaster[zOrder]]; //offset in this LCU
    Int offsetLCUX = g_auiRasterToPelX[g_auiZscanToRaster[zOrder]];

    Int iYOffset, iXOffset;
    DistType diff;
    DistType *pDiffEnd = &pDiff[uiLibSizeMinusOne];
    Pel *refCurr;

#define REGION_NUM 3
    Int mvYMins[REGION_NUM];
    Int mvYMaxs[REGION_NUM];
    Int mvXMins[REGION_NUM];
    Int mvXMaxs[REGION_NUM];
    Int regionNum = REGION_NUM;//3
    Int regionId = 0;

    //1. check the near pixels within LCU,在LCU内检查最近的像素
    //above pixels in LCU,LCU中上方的像素
    Int iTemplateSize = uiTempSize;
    Int iBlkSize = uiBlkSize;
    regionId = 0;
#if JVET_C0024_QTBT
    const UInt maxCUWidth = pcCU->getPic()->getPicSym()->getSPS().getCTUSize();
    const UInt maxCUHeight = pcCU->getPic()->getPicSym()->getSPS().getCTUSize();
#else
    const UInt maxCUWidth = pcCU->getPic()->getPicSym()->getSPS().getMaxCUWidth();
    const UInt maxCUHeight = pcCU->getPic()->getPicSym()->getSPS().getMaxCUHeight();
#endif

    Int iVerMin = max(((iTemplateSize) << iMvShift), (iCurrY - offsetLCUY - iBlkSize + 1) << iMvShift);
    Int iVerMax = (iCurrY - iBlkSize) << iMvShift;
    Int iHorMin = max((iTemplateSize) << iMvShift, (iCurrX - offsetLCUX - iBlkSize + 1) << iMvShift);
    Int iHorMax = min((iCurrX - offsetLCUX + maxCUWidth - iBlkSize) << iMvShift, refPicSrc->getSlice(0)->getSPS()->getPicWidthInLumaSamples() - iBlkSize);

    mvXMins[regionId] = iHorMin - iCurrX;
    mvXMaxs[regionId] = iHorMax - iCurrX;
    mvYMins[regionId] = iVerMin - iCurrY;
    mvYMaxs[regionId] = iVerMax - iCurrY;
    //left pixels in LCU,LCU中左边的像素
    regionId = 1;
    iVerMin = max(((iTemplateSize) << iMvShift), (iCurrY - iBlkSize + 1) << iMvShift);
    iVerMax = min((iCurrY - offsetLCUY + maxCUHeight - iBlkSize) << iMvShift, refPicSrc->getSlice(0)->getSPS()->getPicHeightInLumaSamples() - iBlkSize);

    iHorMin = max((iTemplateSize) << iMvShift, (iCurrX - offsetLCUX - iBlkSize + 1) << iMvShift);
    iHorMax = (iCurrX - iBlkSize) << iMvShift;
    mvXMins[regionId] = iHorMin - iCurrX;
    mvXMaxs[regionId] = iHorMax - iCurrX;
    mvYMins[regionId] = iVerMin - iCurrY;
    mvYMaxs[regionId] = iVerMax - iCurrY;
    Int combinedX = offsetLCUX + iBlkSize - 1;
    Int combinedY = offsetLCUY + iBlkSize - 1;
#if JVET_C0024_QTBT
    Int NumInRow = pcCU->getSlice()->getSPS()->getCTUSize() >> 2;//32
#else
    Int NumInRow = pcCU->getSlice()->getSPS()->getMaxCUHeight() >> 2;
#endif

    //check within LCU pixels
    for (regionId = 0; regionId < 2; regionId++)
    {
        Int mvYMin = mvYMins[regionId];
        Int mvYMax = mvYMaxs[regionId];
        Int mvXMin = mvXMins[regionId];
        Int mvXMax = mvXMaxs[regionId];
        if (mvYMax < mvYMin || mvXMax < mvXMin)
        {
            continue;
        }
        for (iYOffset = mvYMax; iYOffset >= mvYMin; iYOffset--)
        {
            for (iXOffset = mvXMax; iXOffset >= mvXMin; iXOffset--)
            {
                refCurr = ref + iYOffset*refStride + iXOffset;
                Int iLCUX = iXOffset + combinedX;
                Int iLCUY = iYOffset + combinedY;
                Int ZorderTmp = getZorder(iLCUX, iLCUY, NumInRow);
                if (ZorderTmp >= zOrder)
                {
                    //Ignore the blocks that have not been coded.
                    continue;
                }
                diff = calcTemplateDiff(refCurr, refStride, tarPatch, uiPatchSize, uiTempSize, *pDiffEnd);
                if (diff < (*pDiffEnd))
                {
                    insertNode(diff, iXOffset, iYOffset, pDiff, pX, pY, pId, uiLibSizeMinusOne, setId);
                }
            }
        }
    }

    //2. check the pixels outside LCU,check LCU外面的像素
    for (regionId = 0; regionId < regionNum; regionId++)//regionNUM等于3
    {
        pcCU->clipMvIntraConstraint(regionId, mvXMins[regionId], mvXMaxs[regionId], mvYMins[regionId], mvYMaxs[regionId], iSrchRng, uiTempSize, uiBlkSize, iCurrY, iCurrX, offsetLCUY, offsetLCUX);
    }
    for (regionId = 0; regionId < regionNum; regionId++)
    {
        Int mvYMin = mvYMins[regionId];
        Int mvYMax = mvYMaxs[regionId];
        Int mvXMin = mvXMins[regionId];
        Int mvXMax = mvXMaxs[regionId];
        if (mvXMax < mvXMin)
        {
            continue;
        }
        for (iYOffset = mvYMax; iYOffset >= mvYMin; iYOffset--)
        {
            for (iXOffset = mvXMax; iXOffset >= mvXMin; iXOffset--)
            {
                refCurr = ref + iYOffset*refStride + iXOffset;
                diff = calcTemplateDiff(refCurr, refStride, tarPatch, uiPatchSize, uiTempSize, *pDiffEnd);
                if (diff < (*pDiffEnd))
                {
                    insertNode(diff, iXOffset, iYOffset, pDiff, pX, pY, pId, uiLibSizeMinusOne, setId);
                }
            }
        }
    }
}

Bool TComTrQuant::generateTMPrediction(Pel *piPred, UInt uiStride, UInt uiBlkSize, UInt uiTempSize, Int &foundCandiNum)
{
    Bool bSucceedFlag = true;
    UInt uiPatchSize = uiBlkSize + uiTempSize;//patch的大小等于当前块的大小加模板的大小
    UInt uiTarDepth = g_aucConvertToBit[uiBlkSize];
     //count collected candidate number
    DistType *pDiff = m_tempLibFast.getDiff();//得到模板的MSE
    DistType maxDiff = m_tempLibFast.getDiffMax();
    Int k;
    UInt uiInvalidCount = 0;
    UInt uiTargetCandiNum = g_uiDepth2MaxCandiNum[uiTarDepth];

    for (k = uiTargetCandiNum - 1; k >= 0; k--)//遍历所有模板候选
    {
        if (pDiff[k] >= maxDiff)//如果候选模板的MSE大于最大的MSE,则此候选模板无效
        {
            uiInvalidCount++;//累加无效的候选模板数
        }
        else
        {
            break;
        }
    }
    m_uiVaildCandiNum = uiTargetCandiNum - uiInvalidCount;//有效的候选模板数等于候选模板总数-无效的候选模板数
    foundCandiNum = m_uiVaildCandiNum;
    Int iCandiNum;
    iCandiNum = min((UInt)TMPRED_CANDI_NUM, m_uiVaildCandiNum);//有效的候选数量最多可以有8个
    if (iCandiNum < 1)//如果候选模板数为0.则返回
    {
        return false;
    }

    Int *pX = m_tempLibFast.getX();
    Int *pY = m_tempLibFast.getY();
    Short setId;
    Pel *ref;
    Int picStride = getStride();
    Int iOffsetY, iOffsetX;
    Pel *refTarget;
    UInt uiHeight = uiPatchSize - uiTempSize;
    UInt uiWidth = uiHeight;
    TrainDataType *pData;

    //the data center: we use the prediction block as the center now.将预测块作为中心
    Pel predBlk[MAX_1DTRANS_LEN] = { 0 };//MAX_1DTRANS_LEN=1024
    UInt i = 0;
    //collect the candidates
    setId = 0;
    ref = getRefPicUsed(setId);//参考图像为当前帧

    for (k = 0; k < iCandiNum; k++)//遍历有效的候选模板
    {
        pData = m_pData[k];
        iOffsetY = pY[k];
        iOffsetX = pX[k];
        refTarget = ref + iOffsetY*picStride + iOffsetX;//指向当前候选模板对应的预测块
        for (UInt uiY = 0; uiY < uiHeight; uiY++)
        {
            for (UInt uiX = 0; uiX < uiWidth; uiX++)
            {
                *pData++ = refTarget[uiX];//把候选模板对应的块的值赋给pData;
            }
            refTarget += picStride;
        }
    }
    //average of the first several candidates as prediction,将前面几个候选模板对应块的平均作为当前块的预测块
    Int iSize = uiWidth*uiHeight;
    for (k = 0; k < iCandiNum; k++)
    {
        pData = m_pData[k];
        for (i = 0; i < iSize; i++)
        {
            predBlk[i] += pData[i];//累加前iCandiNum个候选对应预测块的值
        }
    }
    Int iShift = iCandiNum >> 1;
    for (i = 0; i < iSize; i++)
    {
        predBlk[i] = (predBlk[i] + iShift) / iCandiNum;//求均值
    }

    Pel*  pPred = piPred;
    i = 0;
    for (UInt uiY = 0; uiY < uiHeight; uiY++)
    {
        for (UInt uiX = 0; uiX < uiWidth; uiX++)
        {
            pPred[uiX] = predBlk[i++];
        }
        pPred += uiStride;
    }
    return bSucceedFlag;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值