initIntraMip函數主要是對參考像素進行下采樣併爲MIP矩陣乘法準備輸入數據,函數結構如下:
MIP根據塊尺寸可以分爲以下三種情況:
塊尺寸 |
下采樣後的邊界長度 m_reducedBdrySize |
矩陣乘法輸出邊界長度 m_reducedPredSize |
|
mipSizeId = 0 | 4x4 | 2 | 4 |
mipSizeId = 1 | 4xN、Nx4、8x8 | 4 | 4 |
mipSizeId = 2 | 其餘塊 | 4 | 8 |
initIntraMip函數主要是準備邊界參考像素,並調用prepareInputForPred函數爲MIP預測準備輸入數據
注意:MIP使用的參考像素是未經過濾波的參考像素
initIntraMip函數代碼如下所示:
void IntraPrediction::initIntraMip( const PredictionUnit &pu, const CompArea &area )
{
CHECK( area.width > MIP_MAX_WIDTH || area.height > MIP_MAX_HEIGHT, "Error: block size not supported for MIP" );
// prepare input (boundary) data for prediction
// 準備輸入(邊界)數據進行預測
// MIP使用未濾波的參考像素
CHECK( m_ipaParam.refFilterFlag, "ERROR: unfiltered refs expected for MIP" );
#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
Pel *ptrSrc = getPredictorPtr(area.compID);//獲取參考像素
const int srcStride = m_refBufferStride[area.compID];
const int srcHStride = 2;
m_matrixIntraPred.prepareInputForPred(CPelBuf(ptrSrc, srcStride, srcHStride), area,
pu.cu->slice->getSPS()->getBitDepth(toChannelType(area.compID)), area.compID);
#else
Pel *ptrSrc = getPredictorPtr( COMPONENT_Y );
const int srcStride = m_refBufferStride[COMPONENT_Y];
const int srcHStride = 2;
m_matrixIntraPred.prepareInputForPred( CPelBuf( ptrSrc, srcStride, srcHStride ), area, pu.cu->slice->getSPS()->getBitDepth( CHANNEL_TYPE_LUMA ) );
#endif
}
prepareInputForPred函數主要分爲以下四個步驟:
- Step 1: 保存塊大小並計算MIP相關參數,通過調用initPredBlockParams函數實現
- Step 2: 獲取輸入數據(上一行參考像素和左一列參考像素)
- Step 3: 通過Haar下采樣計算縮減邊界,通過boundaryDownsampling1D函數實現
- Step 4: 推導矩陣乘法輸入向量
prepareInputForPred函數代碼如下所示
#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
void MatrixIntraPrediction::prepareInputForPred(const CPelBuf &pSrc, const Area &block, const int bitDepth,
const ComponentID compId)
{
m_component = compId;
#else
void MatrixIntraPrediction::prepareInputForPred(const CPelBuf &pSrc, const Area& block, const int bitDepth)
{
#endif
// Step 1: Save block size and calculate dependent values
// Step 1: 保存塊大小並計算MIP相關參數
initPredBlockParams(block);
// Step 2: Get the input data (left and top reference samples)
// Step 2: 獲取輸入數據(左上參考像素)
// 獲取上一行參考像素
m_refSamplesTop.resize(block.width);
for (int x = 0; x < block.width; x++)
{
m_refSamplesTop[x] = pSrc.at(x + 1, 0);
}
// 獲取左一列參考像素
m_refSamplesLeft.resize(block.height);
for (int y = 0; y < block.height; y++)
{
m_refSamplesLeft[y] = pSrc.at(y + 1, 1);
}
// Step 3: Compute the reduced boundary via Haar-downsampling (input for the prediction)
// Step 3: 通過Haar下采樣計算縮減邊界(預測輸入)
// 下采樣後輸入向量的尺寸爲4或者8
const int inputSize = 2 * m_reducedBdrySize;
// 不需要轉置時,下采樣像素的順序:先上後左
m_reducedBoundary .resize( inputSize );
// 轉置時,下采樣像素的順序:先左後上
m_reducedBoundaryTransposed.resize( inputSize );
int* const topReduced = m_reducedBoundary.data();
boundaryDownsampling1D( topReduced, m_refSamplesTop.data(), block.width, m_reducedBdrySize );
int* const leftReduced = m_reducedBoundary.data() + m_reducedBdrySize;
boundaryDownsampling1D( leftReduced, m_refSamplesLeft.data(), block.height, m_reducedBdrySize );
int* const leftReducedTransposed = m_reducedBoundaryTransposed.data();
int* const topReducedTransposed = m_reducedBoundaryTransposed.data() + m_reducedBdrySize;
for( int x = 0; x < m_reducedBdrySize; x++ )
{
topReducedTransposed[x] = topReduced[x];
}
for( int y = 0; y < m_reducedBdrySize; y++ )
{
leftReducedTransposed[y] = leftReduced[y];
}
// Step 4: Rebase the reduced boundary
// Step 4: 縮小邊界
// 推導矩陣乘法輸入向量p,mipSizeId=0/1和mipSizeId=2的推導方法不一樣
m_inputOffset = m_reducedBoundary[0];
m_inputOffsetTransp = m_reducedBoundaryTransposed[0];
const bool hasFirstCol = (m_sizeId < 2);
m_reducedBoundary [0] = hasFirstCol ? ((1 << (bitDepth - 1)) - m_inputOffset ) : 0; // first column of matrix not needed for large blocks
m_reducedBoundaryTransposed[0] = hasFirstCol ? ((1 << (bitDepth - 1)) - m_inputOffsetTransp) : 0;
for (int i = 1; i < inputSize; i++)
{
m_reducedBoundary [i] -= m_inputOffset;
m_reducedBoundaryTransposed[i] -= m_inputOffsetTransp;
}
}
1、初始化MIP相關參數
initPredBlockParams函數是用來初始化MIP相關參數,主要是根據當前塊的尺寸來初始化mipSizeId,然後根據mipSizeId初始化下采樣後的邊界長度、矩陣乘法輸出邊界長度和上採樣因子
void MatrixIntraPrediction::initPredBlockParams(const Size& block)
{
//獲得當前塊尺寸
m_blockSize = block;
// init size index
// 根據當前塊尺寸初始化sizeId
m_sizeId = getMipSizeId( m_blockSize );
// init reduced boundary size
// 初始縮減邊界尺寸
// 對於4x4的塊寬度和高度分別縮減爲2個像素
// 對於其餘尺寸的塊寬度和高度分別縮減爲4個像素
m_reducedBdrySize = (m_sizeId == 0) ? 2 : 4;
// init reduced prediction size
// 初始化縮減預測後的尺寸
// 對於mipSizeId = 0、1的塊,MIP預測後輸出4x4的塊
// 對於mipSizeId = 2的塊,MIP預測後輸出8x8的塊
m_reducedPredSize = ( m_sizeId < 2 ) ? 4 : 8;
// init upsampling factors
// 初始上採樣因子
m_upsmpFactorHor = m_blockSize.width / m_reducedPredSize;
m_upsmpFactorVer = m_blockSize.height / m_reducedPredSize;
CHECKD( (m_upsmpFactorHor < 1) || ((m_upsmpFactorHor & (m_upsmpFactorHor - 1)) != 0), "Need power of two horizontal upsampling factor." );
CHECKD( (m_upsmpFactorVer < 1) || ((m_upsmpFactorVer & (m_upsmpFactorVer - 1)) != 0), "Need power of two vertical upsampling factor." );
}
2、下采樣
邊界參考像素的下采樣過程是由boundaryDownsampling1D函數實現的,下采樣過程其實就是對邊界參考像素求平均的過程,以8x8的塊爲例,如下圖所示,上一行存在8個參考像素,通過對兩兩相鄰的參考像素求平均後獲得4個下采樣後的參考像素,左一列參考像素地下采樣過程同理。
/*
一維下采樣
reducedDst表示下采樣後的邊界
fullSrc表示下采樣前的邊界
srcLen表示下采樣前的邊界長度
dstLen表示下采樣後的邊界長度
*/
void MatrixIntraPrediction::boundaryDownsampling1D(int* reducedDst, const int* const fullSrc, const SizeType srcLen, const SizeType dstLen)
{
if (dstLen < srcLen)
{
//當下採樣後的邊界尺寸小於當前塊的邊界尺寸時,需要進行下采樣,下采樣操作即相當於求平均操作
// Create reduced boundary by downsampling 通過下采樣創建縮小邊界
const SizeType downsmpFactor = srcLen / dstLen;
const int log2DownsmpFactor = floorLog2(downsmpFactor);
const int roundingOffset = (1 << (log2DownsmpFactor - 1));
SizeType srcIdx = 0;
for( SizeType dstIdx = 0; dstIdx < dstLen; dstIdx++ )
{
int sum = 0;
for( int k = 0; k < downsmpFactor; k++ )
{
sum += fullSrc[srcIdx++];
}
reducedDst[dstIdx] = (sum + roundingOffset) >> log2DownsmpFactor;
}
}
else
{
// Copy boundary if no downsampling is needed 如果不需要下采樣,則複製邊界
for (SizeType i = 0; i < dstLen; ++i)
{
reducedDst[i] = fullSrc[i];
}
}
}
下采樣過程結束後,根據mipTransposeFlag標誌將下采樣後的上參考像素和左參考像素排列成向量pTemp,排列方式如下:
- mipTransposeFlag = 0時,pTemp = [redTop,redLeft]
- mipTransposeFlag = 1時,pTemp = [redLeft,redTop]
3、推導矩陣乘法輸入向量
矩陣乘法輸入向量的推導方法和mipSizeId有關,輸入向量p的構造過程如下所示,其中inSize = 2*m_reducedBdrySize