VVC變換編碼(二)低頻不可分離變換LFNST

不出門、不聚集,抗擊疫情不給國家添麻煩。

不可分離變換:整個變換就是一個二維矩陣乘法過程。

可分離變換:將二維矩陣乘法分爲水平和垂直方向兩個一維向量乘法,複雜度較低。

二次變換:就是在主變換(Primary transform)之後對頻域信號進行第二次變換,將信號從一個變換域轉換至另外一個變換域,之後再進行量化,熵編碼等操作,其目的是進一步去除統計冗餘。

在VTM5中低頻不可分離變換 (LFNST,low-frequency non-separable transform)被看作是縮減的二次變換。如下圖所示,在編碼端,LFNST用在變換和量化之間。在解碼端,LFNST用在反量化和反變換之間。根據塊的尺寸不同,LFNST可以選擇4x4和8x8的不可分離變換。例如對小尺寸塊(min (width, height) < 8)使用4x4變換,對大尺寸塊(min (width, height) >4)使用8x8變換。

下面是一個4x4LFNST的例子,輸入X是一個4x4矩陣:

首先將矩陣X拉伸爲一個一維向量:

然後進行不可分離變換計算:

最後將結果16x1的係數向量轉換成4x4的係數矩陣。

縮減的不可分離變換(reduced non-separable transform,RST)

LFNST基於不可分離變換所以只需要一次矩陣乘法就可以完成變換操作。但是爲了降低計算複雜度和變換系數的內存空間需要將不可分離變換矩陣進行縮減。縮減的不可分離變換(reduced non-separable transform,RST)主要思想是將N維向量映射爲另一個空間的R維向量,其中N/R (R<N)是縮減因子。這樣一個NxN的矩陣經過RST處理後變爲一個RxN的矩陣,如下所示。

R是N維空間的R基底。其逆矩陣是正變換矩陣的轉置矩陣

上面有一個4x4LFNST的例子,同樣對於8x8LFNST,輸入X是一個8x8矩陣拉伸爲64x1的向量,矩陣T爲64x64,使用RST縮減因子是4時T變爲16x64,結果是16x1的向量轉換爲4x4矩陣,所以8x8二次變換結果只有左上角4x4其他三個4x4塊變換系數都是0。

void TrQuant::fwdLfnstNxN( int* src, int* dst, const uint32_t mode, const uint32_t index, const uint32_t size, int zeroOutSize )
{
  const int8_t* trMat  = ( size > 4 ) ? g_lfnst8x8[ mode ][ index ][ 0 ] : g_lfnst4x4[ mode ][ index ][ 0 ];
  const int     trSize = ( size > 4 ) ? 48 : 16;	//!<RST對於8x8塊使用左上角3個4x4塊維度爲48
  int           coef;
  int*          out    = dst;

  assert( index < 3 );
  //!<LFNST計算
  for( int j = 0; j < zeroOutSize; j++ )
  {
    int*          srcPtr   = src;
    const int8_t* trMatTmp = trMat;
    coef = 0;
    for( int i = 0; i < trSize; i++ )	//!<矩陣一行乘以一列
    {
      coef += *srcPtr++ * *trMatTmp++;
    }
    *out++ = ( coef + 64 ) >> 7;
    trMat += trSize;	//!<矩陣下一行
  }
  //!<剩餘元素置零
  ::memset( out, 0, ( trSize - zeroOutSize ) * sizeof( int ) );
}
//!<將結果一維向量轉換成二維矩陣
const ScanElement * scanPtr = scan;
int lfnstCoeffNum = ( sbSize == 4 ) ? sbSize * sbSize : 48;
for( y = 0; y < lfnstCoeffNum; y++ )
{
    coeffTemp[ scanPtr->idx ] = *lfnstTemp++;
    scanPtr++;
}

在VTM5中,8x8LFNST變換矩陣進一步縮減從16x64變爲16x48,逆矩陣爲48x16,輸入X只取左上角三個4x4塊展開成48維向量,如下圖所示。由於維度縮減存儲所有LFNST矩陣的空間由10KB減少到8KB而性能未下降太多。

爲了減少TU(4x4或8x8)在方面最壞情況下的乘法運算數量,對8x8和4x4TU分別使用8x

48和8x16矩陣。對於尺寸大於8x8的塊由於不會發生最壞情況所以使用16x48的矩陣。對於8x4或4x8的TU只對其左上角4x4塊使用4x4LFNST(16x16矩陣)。對4xN或Nx4的TU(N≧16)只對其左上角兩個鄰接4x4塊使用4x4LFNST。經過這些簡化,最壞情況下每個像素只需要做8次乘法運算。

LFNST變換選擇

LFNST中預設了4個變換集,每個變換集有2個不可分離變換。

const int8_t g_lfnst8x8[ 4 ][ 2 ][ 16 ][ 48 ]
const int8_t g_lfnst4x4[ 4 ][ 2 ][ 16 ][ 16 ]

使用哪個變換集由其所使用的幀內預測模式決定,幀內預測模式和變換集對應關係如下:

const uint8_t g_lfnstLut[ NUM_INTRA_MODE + NUM_EXT_LUMA_MODE - 1 ] =
{//0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
   0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
};

對於每個變換集還需要傳輸一個標誌位表示使用的不可分離變換矩陣索引。在碼流中這個索引位於變換系數之後,且每個CU都需要一個索引。

LFNST索引的傳輸及與其他工具的交互

8x8 LFNST在前向變換中使用16x48的矩陣,所以在這個8x8塊中只有左上角4x4塊纔有非零值。換句話說,如果8x8塊使用了LFNST那麼除了左上角4x4塊外其他係數都爲0。所以如果在8x8塊除左上角區域外檢測到非零值則表明未使用LFNST則不需要傳輸LFNST index,這種情況下默認LFNST index=0。如果LFNST index=0表示不使用LFNST模式,否則表示使用LFNST模式。此外,LFNST index進行上下文編碼時不依賴於幀內預測模式,且僅第一個bin是上下文編碼。

當滿足以下兩個條件時使用逆LFNST:

  • 塊尺寸大於等於給定閾值(W>=4 && H>=4);

  • 變換跳過模式標誌位等於0;

如果W>4&&H>4,那麼對左上角8x8區域進行8x8LFNST。否則對左上角min(8, W) × min(8, H)區域進行 4x4 LFNST。

LFNST只用於幀內和幀間slice內的幀內CU。對亮度和色度分量都適用。如果允許使用對偶樹亮度和色度的LFNST indices分開傳輸。對於幀間slice(不允許使用對偶樹)亮度和色度使用同一個LFNST indices。

如果使用ISP模式則不允許使用LFNST且RST index也不需要傳輸。因爲即使將RST應用於每個可行的分塊,性能提升也很有限。不對ISP預測殘差使用RST還能減少編碼複雜度。對MIP模式也不允許使用LFNST和傳輸RST index。

參考

JVET-N1002

JVET-N0193

JVET-N0105

感興趣的請關注微信公衆號Video Coding

 

發佈了97 篇原創文章 · 獲贊 174 · 訪問量 26萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章