考虑到帧内和帧间有很多相似的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;
}
#endifVoid 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;
}

本文介绍H.266视频编码标准中的信号独立变换(SDT)技术,该技术利用帧内和帧间的相似性提高编码效率。通过KLT方法训练一维变换,实现更有效的能量压缩。文章详细解释了如何实现SDT技术,包括参考patch的选择、最相似patch的搜索以及KLT的训练过程。
461

被折叠的 条评论
为什么被折叠?



