HEVC- I프레임에서 CU, TU, PU 간의 관계

여기는 주로 HEVC의 디코딩단 I프레임과 결합하여 설명한 것이다. 그 중에서 P, B 프레임은 기본적으로 큰 차이가 없고 주로 PU에 불규칙한 상황이 존재하기 때문에 P 프레임에 대해 아직 파악하지 못했다.
나중에 명확하게 해석한 후에 다시 보충하다
이전의 블로그에서 인코딩 트리 구조와 관련된 개념을 언급했는데 여기서 주로 코드를 결합시켜 진일보한 설명을 한다
프레임 내 모드:
35에서 예측 모델은 PU의 기초 위에서 정의되었지만 구체적인 프레임 내 예측 과정에서TU를 단위로 한다. 표준에 따르면 PU는 네 갈래 나무의 형식으로TU로 나눌 수 있고 같은 PU 내의TU는 하나의 예측 모델을 공유할 수 있다.
실제 예측에서 각 TU는 자신의 예측을 하고 자신의 주위의 화소점을 참고한다
따라서 PU는 예측 방식을 정의할 뿐 실제와 예측 픽셀과 재구성 과정은 TU를 통해 처리된다
다음은 엔트로피 디코딩이 몇 가지 데이터를 읽는 기록 단서입니다.
pCu는 CTU에 대응하는 구조체를 대표한다
uiAbsPartIdx는 현재 CU가 CTU에 있는 위치를 나타냅니다(구성 문서의 최소TU 단위).
마지막 매개변수는 현재 CU 또는 PU의 TU 개수를 나타냅니다.
//memset( pCu->pPuhDepth + uiAbsPartIdx, uiDepth+splitFlag, uiCurNumParts );
//<현재 CU 예측 섹션을 기록합니다. PU는 N*N, or2N*2N이며 현재 CU의 width, height를 기록합니다.
memset(pCu->pPePartSize+uiAbsPartIdx,partSize,uiCurNumParts);
memset(pCu->pPuhWidth+uiAbsPartIdx,pSps->uiMaxCUWidth>>uiDepth,uiCurNumParts);
memset(pCu->pPuhHeight+uiAbsPartIdx,pSps->uiMaxCUHeight>>uiDepth,uiCurNumParts);
//<쓰기 예측 모드, 프레임 내 or 프레임 간
memset(pCu->pPePredMode+uiAbsPartIdx,MODE_INTRA,uiCurNumParts);(현재 모두 프레임에 기록됨)
//memset(pCu->pPuhIntraDir[CHANNEL_TYPE_LUMA]+uiAbsPartIdx+i*partOffset,intraPredMode,uiCurNumParts);
i는 분할을 진행하면 네 번으로 나누어 쓴다는 뜻이다
memset(pCu->pPuhIntraDir[CHANNEL_TYPE_CHROMA]+uiAbsPartIdx,symbol,uiCurNumParts);
////<반복되는 각 프로세스에서 CBF 값
memset(pCu->pPuhCbf[compID]+uiAbsPartIdx,uiCbf,pImg->numPartitionsInCtu>>(uiDepthAdj<<1));
//memset(pCu->pPuhTrIdx + uiAbsPartIdx,uiTrDepth,uiCurNumParts);
//저장 위치:
pCoeff = pCu->pTrCoeff[compID]+pTu->offsets[compID];
Offsets는 CTU에서 현재 TU의 오프셋 위치를 반복적으로 가져오는 것을 나타냅니다.
주의: 매번 최소 디코딩 TU로 나누는 것은 현재 TU가 반드시 설정 정보 중의 최소 TU가 아니라는 것을 의미하지 않으며 이것은 인코딩단에서 결정한 것이다
 
해당 정보를 얻은 후 CTU 디코딩 작업 수행
일단 들어갑니다.
 m_pcCuDecoder->decompressCtu ( pCtu ); 함수.
이후 귀속 과정에 들어가 데이터를 읽을 때와 같은 과정을 거쳐 최소한의 CU를 얻어 디코딩한다.
<span style="font-size:18px;"> case MODE_INTRA:
      xReconIntraQT( m_ppcCU[uiDepth], uiDepth ); //<       </span>

이후 PartSize에 따라 CU를 해당 PU로 구분합니다.
TComTURecurse <span style="color:#ff0000;"><strong>tuRecurseCU</strong></span>(pcCU, 0);
    TComTURecurse tuRecurseWithPU(tuRecurseCU, false, (uiInitTrDepth==0)?TComTU::DONT_SPLIT : TComTU::QUAD_SPLIT);

    do
    {
      xIntraRecQT( m_ppcYuvReco[uiDepth], m_ppcYuvReco[uiDepth], m_ppcYuvResi[uiDepth], chanType, tuRecurseWithPU );
    } while (tuRecurseWithPU.nextSection(tuRecurseCU));

지금은 PU가 예측 모드를 얻었지만 결국은 TU를 통해 디코딩을 하기 때문에 여기에는 TU의 저장 구조를 사용했다
while 순환 내에 PU가 TU를 풀기 시작하는 과정에 들어갔습니다.
4
Void
TDecCu::<strong><span style="color:#ff0000;">xIntraRecQT</span></strong>(TComYuv*    pcRecoYuv,
                    TComYuv*    pcPredYuv,
                    TComYuv*    pcResiYuv,
                    const ChannelType chType,
                    TComTU     &rTu)
{
  UInt uiTrDepth    = rTu.GetTransformDepthRel();
  TComDataCU *pcCU  = rTu.getCU();
  UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU();
  UInt uiTrMode     = pcCU->getTransformIdx( uiAbsPartIdx );
  if( uiTrMode == uiTrDepth )
  {
    if (isLuma(chType))
      xIntraRecBlk( pcRecoYuv, pcPredYuv, pcResiYuv, COMPONENT_Y,  rTu );
    else
    {
      const UInt numValidComp=getNumberValidComponents(rTu.GetChromaFormat());
      for(UInt compID=COMPONENT_Cb; compID<numValidComp; compID++)
      {
        xIntraRecBlk( pcRecoYuv, pcPredYuv, pcResiYuv, ComponentID(compID), rTu );
      }
    }
  }
  else
  {
    TComTURecurse tuRecurseChild(rTu, false);
    do
    {
      xIntraRecQT( pcRecoYuv, pcPredYuv, pcResiYuv, chType, tuRecurseChild );
    } while (tuRecurseChild.nextSection(rTu));
  }
}
이 함수에서 알 수 있듯이 PU에서TU에 들어간 후에도 읽기 매개 변수와 대응하는 귀속 조작을 한다
데이터를 읽고 화해하는 과정을 보면 기본적으로 알 수 있다
CU, TU, PU는 서로 독립적이라고 할 수 있다. 왜냐하면 그들은 각자 일부분의 모듈을 책임지기 때문이다.
그러나 일정한 연관이 있다. 프레임 내 예측에 있어
루트 노드는 모두 CU이고 인코딩 과정에서 CU->PU, CU->TU입니다. 프레임 내 모드에서 PU가 N*N이면 CU->TU는 반드시 한 번 분할됩니다.
디코딩 과정은 프레임 내 상황을 먼저 판단하기 때문에 PU에 따라 CU가 한 번 분할되었는지 판단한 다음에 깊이 정보에 따라 TU를 얻는다
프레임 사이의 경우 이후 추가

좋은 웹페이지 즐겨찾기