帧内预测流程(还有几个小细节)_青椒鸡汤的博客-CSDN博客_帧内预测
H.266/VVC-VTM代码学习-帧内预测01-初始化帧内预测参数IntraPrediction::initPredIntraParams_liaojq2020的博客-CSDN博客
H.266/VVC代码学习:帧内预测之初始化帧内预测参数(initPredIntraParams)_涵小呆的博客-CSDN博客 H.266/VVC代码学习:帧内预测之角度预测函数(predIntraAng、xPredIntraAng)_涵小呆的博客-CSDN博客_vvc 帧内预测
// Function for initialization of intra prediction parameters
void IntraPrediction::initPredIntraParams(const PredictionUnit & pu, const CompArea area, const SPS& sps)
{
//当前area的分量
const ComponentID compId = area.compID;
//色度还是亮度
const ChannelType chType = toChannelType(compId);
//是否使用ISP
const bool useISP = NOT_INTRA_SUBPARTITIONS != pu.cu->ispMode && isLuma( chType );
//cu大小
const Size cuSize = Size( pu.cu->blocks[compId].width, pu.cu->blocks[compId].height );
//pu大小
const Size puSize = Size( area.width, area.height );
//块大小,看是否用ISP
const Size& blockSize = useISP ? cuSize : puSize;
//预测模式
const int dirMode = PU::getFinalIntraMode(pu, chType);
//将预测模式转换为宽角度模式
const int predMode = getModifiedWideAngle( blockSize.width, blockSize.height, dirMode );
//模式标号大于34视作垂直类模式
m_ipaParam.isModeVer = predMode >= DIA_IDX;
//获得参考行索引
m_ipaParam.multiRefIndex = isLuma (chType) ? pu.multiRefIdx : 0 ;
//参考像素滤波初始化为否
m_ipaParam.refFilterFlag = false;
//插值初始化为否
m_ipaParam.interpolationFlag = false;
//是否提供PDPC技术(若PU边长均≥4且使用0号参考行则提供PDPC)
m_ipaParam.applyPDPC = (puSize.width >= MIN_TB_SIZEY && puSize.height >= MIN_TB_SIZEY) && m_ipaParam.multiRefIndex == 0;
const int intraPredAngleMode = (m_ipaParam.isModeVer) ? predMode - VER_IDX : -(predMode - HOR_IDX);
int absAng = 0;
//预测模式是角度模式(即模式号大于DC)且模式号小于LUMA模式总数67
if (dirMode > DC_IDX && dirMode < NUM_LUMA_MODE) // intraPredAngle for directional modes
{
static const int angTable[32] = { 0, 1, 2, 3, 4, 6, 8, 10, 12, 14, 16, 18, 20, 23, 26, 29, 32, 35, 39, 45, 51, 57, 64, 73, 86, 102, 128, 171, 256, 341, 512, 1024 };
static const int invAngTable[32] = {
0, 16384, 8192, 5461, 4096, 2731, 2048, 1638, 1365, 1170, 1024, 910, 819, 712, 630, 565,
512, 468, 420, 364, 321, 287, 256, 224, 191, 161, 128, 96, 64, 48, 32, 16
}; // (512 * 32) / Angle
//模式偏离水平或垂直的值(取绝对值),值范围为0~32
const int absAngMode = abs(intraPredAngleMode);
//模式19~49(模式号大于水平,小于垂直)为-1,其他为1
const int signAng = intraPredAngleMode < 0 ? -1 : 1;
//角度模式对应偏移值offset
absAng = angTable [absAngMode];
// 每种角度对应的投影位置
m_ipaParam.absInvAngle = invAngTable[absAngMode];
//角度偏移值,带正负号
m_ipaParam.intraPredAngle = signAng * absAng;
if (intraPredAngleMode < 0)
{
//模式19~49不用PDPC
m_ipaParam.applyPDPC = false;
}
else if (intraPredAngleMode > 0)
{
//根据预测模式对应侧的长度
const int sideSize = m_ipaParam.isModeVer ? puSize.height : puSize.width;
//缩放的设置
const int maxScale = 2;
m_ipaParam.angularScale = std::min(maxScale, floorLog2(sideSize) - (floorLog2(3 * m_ipaParam.absInvAngle - 2) - 8));
m_ipaParam.applyPDPC &= m_ipaParam.angularScale >= 0;
}
}
predmode:为宽角度模式下当前预测模式的序号。款角度预测模式范围是-14~80
如图,模式2 ~ 66表示传统的帧内预测模式,模式 -1 ~ -14以及模式67 ~ 80表示宽角度预测模式。
intraPredAngle变量指代的是角度偏移值,,即每一种角度模式都相当于在水平方向或者垂直方向上做了一个角度偏移,从角度模式到偏移值的映射如下表所示:
absInvAngle变量表示反角度参数,具体地计算为
在VTM中为了消除除法运算,预先将(512 * 32) /Angle的值存了起来,存在了invAngTable表中。
intraPredAngleMode :先判断当前模式是垂直还是水平然后再根据情况得出值。注意:因为这里将宽角度预测模式也算入,所以范围是-16~32。这个参数在后面通过计算可以查表得出当前模式的偏移值和范角度参数
angTable[32]:这个表里存的是各个角度模式对应的偏移值
invAngTable[32]:这个表里存的是反角度对应的偏移值。目的是避免在运行时的除法运算,预先存入结果。举例,角度模式32的偏移值是-26,512*32/26再求绝对值等于565(上取整).与参考像素的投影有关
举几个例子
2 | 37 | 80 | |
predMode | 2 | 37 | 80 |
intraPredAngleMode | 16 | -13 | 30 |
absAngMode | 16 | 13 | 30 |
signAng | 1 | -1 | 1 |
absAng | 32 | 23 | 512 |
absInvAngle | 512 | 712 | 32 |
intraPredAngle | 32 | -23 | 512 |
这里参考之前写的博客,中的参考像素投影,负角度方向的投影。代码跑这里时详细看一遍
angularScale:角度缩放的设置,之后再看
/********************判断是否对参考像素进行滤波**********************/
// high level conditions and DC intra prediction
//SPS标识不进行参考像素滤波
//不是亮度分量
//使用ISP
//PU块用了MIP
//多参考行
//DC模式
if( sps.getSpsRangeExtension().getIntraSmoothingDisabledFlag()
|| !isLuma( chType )
|| useISP
|| PU::isMIP( pu, chType )
|| m_ipaParam.multiRefIndex
|| DC_IDX == dirMode
)
{
}
***不滤波***
//如果当前块是亮度同时为BDPCM模式
//色度BDPCM模式
else if ((isLuma(chType) && pu.cu->bdpcmMode) || (!isLuma(chType) && pu.cu->bdpcmModeChroma)) // BDPCM
{
m_ipaParam.refFilterFlag = false;
}
//planar模式
//pu的宽*高大于32就滤波
else if (dirMode == PLANAR_IDX) // Planar intra prediction
{
m_ipaParam.refFilterFlag = puSize.width * puSize.height > 32 ? true : false;
}
//不用ISP
else if (!useISP)// HOR, VER and angular modes (MDIS)
{
bool filterFlag = false;
{
//与水平模式或垂直模式的模式标号差
const int diff = std::min<int>( abs( predMode - HOR_IDX ), abs( predMode - VER_IDX ) );
//log2(width)和log2(height)的均值
const int log2Size = ((floorLog2(puSize.width) + floorLog2(puSize.height)) >> 1);
CHECK( log2Size >= MAX_INTRA_FILTER_DEPTHS, "Size not supported" );
//与水平模式或垂直模式的模式标号差是否大于log2(width)和log2(height)的均值对应的值
//log2(width)和log2(height)的均值 对应值
// 0 24
// 1 24
// 2 24
// 3 14
// 4 2
// 5 0
// 6 0
// 7 0
filterFlag = (diff > m_aucIntraFilter[log2Size]);
}
// Selelection of either ([1 2 1] / 4 ) refrence filter OR Gaussian 4-tap interpolation filter
if (filterFlag)
{
//return (0 == (absAng & 0x1F)),即是否为32的整数倍
const bool isRefFilter = isIntegerSlope(absAng);
CHECK( puSize.width * puSize.height <= 32, "DCT-IF interpolation filter is always used for 4x4, 4x8, and 8x4 luma CB" );
m_ipaParam.refFilterFlag = isRefFilter;
m_ipaParam.interpolationFlag = !isRefFilter;
}
}
}
diff :当前块宽角度模式下的模式号与水平,垂直模式号的差取绝对值,然后较小值
m_aucIntraFilter[]:下标从0开始,比如log2Size=6时,对应0
log2(width)和log2(height)的均值 | 对应值 |
---|---|
0 | 24 |
1 | 24 |
2 | 24 |
3 | 14 |
4 | 2 |
5 | 0 |
6 | 0 |
7 | 0 |
const bool isRefFilter = isIntegerSlope(absAng):这里推测是特定预测模式才参考像素滤波。角度偏移值为32的整数倍,才进行参考像素滤波。
这里可参考HEVC的滤波条件,之后再看VVC的标准