1. 程式人生 > >(HEVC)幀內預測:fillReferenceSamples函式講解

(HEVC)幀內預測:fillReferenceSamples函式講解

將自己看到的對我幫助很大的文章轉載於此,方便下次查閱。

今天開始進入實質性內容的討論,主要是從程式碼實現的角度比較深入地研究幀內預測演算法。由於幀內預測涉及到的函式的數量相對於編解碼器複雜部分來說少,但事實上大大小小也牽涉到了十幾二十個函式(沒具體統計過,只是大概估算了下),想要一下子討論完比較困難,所以打算在接下來的若干篇文章裡逐步地儘可能詳盡地分析每一個較為重要的函式。今天所要討論的是fillReferenceSamples這個函式,它主要功能是在真正進行幀內預測之前,使用重建後的Yuv影象對當前PU的相鄰樣點進行賦值,為接下來進行的角度預測提供參考樣點值。

這個函式實際上實現的是官方當前標準(JCTVC-J1003)draft 8.4.4.2.2(Reference sample substitution process for intra sample prediction),具體內容我這裡就不重複了,有興趣的朋友可以自己下下來去看看,我先簡單把該過程複述一遍:(1)如果所有相鄰點均不可用,則參考樣點值均被賦值為DC值;(2)如果所有相鄰點均可用,則參考樣點值都會被賦值為重建Yuv影象中與其位置相同的樣點值;(3)如果不滿足上述兩個條件,則按照從左下往左上,從左上往右上的掃描順序進行遍歷,(如下圖所示),如果第一個點不可用,則使用下一個可用點對應的重建Yuv樣點值對其進行賦值;對於除第一個點外的其它鄰點,如果該點不可用,則使用它的前一個樣點值進行賦值(前一個步驟保證了前一個樣點值一定是存在的),直到遍歷完畢。

在瞭解了演算法的大致流程後,我們就可以看看程式碼是怎麼具體實現的了。我主要把我對程式碼的註釋連同程式碼一起貼出來,以供大家參考,有些地方理解上肯定還是有所欠缺的,望大家不吝賜教。

  1. Void TComPattern::fillReferenceSamples( TComDataCU* pcCU, Pel* piRoiOrigin, Int* piAdiTemp, Bool* bNeighborFlags, Int iNumIntraNeighbor, Int iUnitSize, Int iNumUnitsInCu, Int iTotalUnits, UInt uiCuWidth, UInt uiCuHeight, UInt uiWidth, UInt uiHeight, Int iPicStride, Bool bLMmode )  
  2. {  
  3.   Pel* piRoiTemp; //!< piRoiOrgin指向重建Yuv影象對應於當前PU所在位置的首地址,piRoiTemp用於指向所感興趣的重建Yuv的位置,piAdiTemp
  4.   Int  i, j;  
  5.   Int  iDCValue = ( 1<<( g_uiBitDepth + g_uiBitIncrement - 1) );  
  6.   if (iNumIntraNeighbor == 0) // all samples are not available
  7.   {  
  8.     // Fill border with DC value
  9.     for (i=0; i<uiWidth; i++)  
    //!< AboveLeft + Above + AboveRight
  10.     {  
  11.       piAdiTemp[i] = iDCValue;  
  12.     }  
  13.     for (i=1; i<uiHeight; i++)  //!< Left + BelowLeft
  14.     {  
  15.       piAdiTemp[i*uiWidth] = iDCValue;  
  16.     }  
  17.   }  
  18.   elseif (iNumIntraNeighbor == iTotalUnits) // all samples are available
  19.   {  
  20.     // Fill top-left border with rec. samples
  21.     piRoiTemp = piRoiOrigin - iPicStride - 1;  //!< 左上
  22.     piAdiTemp[0] = piRoiTemp[0];  
  23.     // Fill left border with rec. samples
  24.     piRoiTemp = piRoiOrigin - 1;  //!< 左
  25.     if (bLMmode) //!< bLMmode 預設值為false
  26.     {  
  27.       piRoiTemp --; // move to the second left column
  28.     }  
  29.     for (i=0; i<uiCuHeight; i++)  
  30.     {  
  31.       piAdiTemp[(1+i)*uiWidth] = piRoiTemp[0]; //!< 每個參考樣點賦值為對應位置重建Yuv樣點值
  32.       piRoiTemp += iPicStride; //!< 指向重建Yuv下一行
  33.     }  
  34.     // Fill below left border with rec. samples
  35.     for (i=0; i<uiCuHeight; i++)  //!< 左下
  36.     {  
  37.       piAdiTemp[(1+uiCuHeight+i)*uiWidth] = piRoiTemp[0]; //!< 每個參考樣點賦值為對應位置重建Yuv樣點值
  38.       piRoiTemp += iPicStride;  
  39.     }  
  40.     // Fill top border with rec. samples
  41.     piRoiTemp = piRoiOrigin - iPicStride; //!< 重新指向重建Yuv的上方
  42.     for (i=0; i<uiCuWidth; i++)  
  43.     {  
  44.       piAdiTemp[1+i] = piRoiTemp[i]; //!< 每個參考樣點賦值為對應位置重建Yuv樣點值
  45.     }  
  46.     // Fill top right border with rec. samples
  47.     piRoiTemp = piRoiOrigin - iPicStride + uiCuWidth; //!< 指向右上
  48.     for (i=0; i<uiCuWidth; i++)  
  49.     {  
  50.       piAdiTemp[1+uiCuWidth+i] = piRoiTemp[i]; //!< 每個參考樣點賦值為對應位置重建Yuv樣點值
  51.     }  
  52.   }  
  53.   else// reference samples are partially available
  54.   {  
  55.     Int  iNumUnits2 = iNumUnitsInCu<<1;  
  56.     Int  iTotalSamples = iTotalUnits*iUnitSize;  //!< neighboring samples的總數,iTotalUnits以4x4塊為單位,iUnitSize為塊的大小
  57.     Pel  piAdiLine[5 * MAX_CU_SIZE];  
  58.     Pel  *piAdiLineTemp; //!<臨時儲存用於填充neighboring samples的樣點值
  59.     Bool *pbNeighborFlags;  
  60.     Int  iNext, iCurr;  
  61.     Pel  piRef = 0; //!< 儲存臨時樣點值
  62.     // Initialize
  63.     for (i=0; i<iTotalSamples; i++)  //!< 先將所有樣點值賦值為DC值
  64.     {  
  65.       piAdiLine[i] = iDCValue;  
  66.     }  
  67.     // Fill top-left sample
  68.     piRoiTemp = piRoiOrigin - iPicStride - 1;  //!< 指向重建Yuv左上角
  69.     piAdiLineTemp = piAdiLine + (iNumUnits2*iUnitSize); //!< piAdiLine的掃描順序為左下到左上,再從左到右上
  70.     pbNeighborFlags = bNeighborFlags + iNumUnits2; //!< 標記neighbor可用性的陣列同樣移動至左上角
  71.     if (*pbNeighborFlags) //!< 如果左上角可用,則左上角4個畫素點均賦值為重建Yuv左上角的樣點值
  72.     {  
  73.       piAdiLineTemp[0] = piRoiTemp[0];  
  74.       for (i=1; i<iUnitSize; i++)  
  75.       {  
  76.         piAdiLineTemp[i] = piAdiLineTemp[0];  
  77.       }  
  78.     }  
  79.     // Fill left & below-left samples
  80.     piRoiTemp += iPicStride; //!< piRoiTemp指向重建Yuv的左邊界
  81.     if (bLMmode)  
  82.     {  
  83.       piRoiTemp --; // move the second left column
  84.     }  
  85.     piAdiLineTemp--;  //!< 移動指標置左邊界
  86.     pbNeighborFlags--; //!< 移動指標置左邊界
  87.     for (j=0; j<iNumUnits2; j++) //!< 從左往左下掃描
  88.     {  
  89.       if (*pbNeighborFlags)  //!< 如果可用
  90.       {  
  91.         for (i=0; i<iUnitSize; i++) //!< 每個4x4塊裡的4個樣點分別被賦值為對應位置的重建Yuv的樣點值
  92.         {  
  93.           piAdiLineTemp[-i] = piRoiTemp[i*iPicStride];  
  94.         }  
  95.       }  
  96.       piRoiTemp += iUnitSize*iPicStride; //!< 指標挪到下一個行(以4x4塊為單位,即實際上下移了4行)
  97.       piAdiLineTemp -= iUnitSize; //!< 指標下移
  98.       pbNeighborFlags--; //!< 指標下移
  99.     }  
  100.     // Fill above & above-right samples
  101.     piRoiTemp = piRoiOrigin - iPicStride; //!< piRoiTemp 指向重建Yuv的上邊界
  102.     piAdiLineTemp = piAdiLine + ((iNumUnits2+1)*iUnitSize); //!< 指向上邊界
  103.     pbNeighborFlags = bNeighborFlags + iNumUnits2 + 1; //!< 指向上邊界
  104.     for (j=0; j<iNumUnits2; j++) //!< 從左掃描至右上
  105.     {  
  106.       if (*pbNeighborFlags)  
  107.       {  
  108.         for (i=0; i<iUnitSize; i++)  
  109.         {  
  110.           piAdiLineTemp[i] = piRoiTemp[i]; //!< 每個4x4塊裡的4個樣點分別被賦值為對應位置的重建Yuv的樣點值
  111.         }  
  112.       }  
  113.       piRoiTemp += iUnitSize; //!< 指標右移
  114.       piAdiLineTemp += iUnitSize; //!< 指標右移
  115.       pbNeighborFlags++; //!< 指標右移
  116.     }  
  117.     // Pad reference samples when necessary
  118.     iCurr = 0;  
  119.     iNext = 1;  
  120.     piAdiLineTemp = piAdiLine; //!< 指向左下角(縱座標最大的那個位置,即掃描起點)
  121.     while (iCurr < iTotalUnits) //!< 遍歷所有neighboring samples
  122.     {  
  123.       if (!bNeighborFlags[iCurr]) //!< 該點不可用
  124.       {  
  125.         if(iCurr == 0) //!< 第一個點就不可用
  126.         {  
  127.           while (iNext < iTotalUnits && !bNeighborFlags[iNext]) //!< 找到第1個可用點
  128.           {  
  129.             iNext++;  
  130.           }  
  131.           piRef = piAdiLine[iNext*iUnitSize]; //!< 儲存該可用點的樣點值
  132.           // Pad unavailable samples with new value
  133.           while (iCurr < iNext) //!< 使用儲存下來的第一個可用點的樣點值賦值給在其之前被標記為不可用的點
  134.           {  
  135.             for (i=0; i<iUnitSize; i++)  
  136.             {  
  137.               piAdiLineTemp[i] = piRef;  
  138.             }  
  139.             piAdiLineTemp += iUnitSize;  
  140.             iCurr++;  
  141.           }  
  142.         }  
  143.         else//!< 當前點不可用且其不是第一個點,則使用該點的前一個可用點的樣點值進行賦值
  144.         {  
  145.           piRef = piAdiLine[iCurr*iUnitSize-1];  
  146.           for (i=0; i<iUnitSize; i++)  
  147.           {  
  148.             piAdiLineTemp[i] = piRef;  
  149.           }  
  150.           piAdiLineTemp += iUnitSize;  
  151.           iCurr++;  
  152.         }  
  153.       }  
  154.       else//!< 當前點可用,繼續檢查下一點
  155.       {  
  156.         piAdiLineTemp += iUnitSize;  
  157.         iCurr++;  
  158.       }  
  159.     }  
  160.     // Copy processed samples
  161.     piAdiLineTemp = piAdiLine + uiHeight + iUnitSize - 2;  //!< piAdiLineTemp = (piAdiLine + 128) + 3,跳過之前對左上角擴充的3個畫素點
  162.     for (i=0; i<uiWidth; i++)  //!< 將最終結果拷貝到左上、上、右上邊界
  163.     {  
  164.       piAdiTemp[i] = piAdiLineTemp[i];  
  165.     }  
  166.     piAdiLineTemp = piAdiLine + uiHeight - 1; //!< uiHeight = uiCUHeight2 + 1
  167.     for (i=1; i<uiHeight; i++)  //!< 將最終結果拷貝到左和左下邊界
  168. 相關推薦

    HEVC預測fillReferenceSamples函式講解

    將自己看到的對我幫助很大的文章轉載於此,方便下次查閱。 今天開始進入實質性內容的討論,主要是從程式碼實現的角度比較深入地研究幀內預測演算法。由於幀內預測涉及到的函式的數量相對於編解碼器複雜部分來說少,但事實上大大小小也牽涉到了十幾二十個函式(沒具體統計過,只是大概估

    HEVC學習 —— 預測系列之一

    今天開始進入實質性內容的討論,主要是從程式碼實現的角度比較深入地研究幀內預測演算法。由於幀內預測涉及到的函式的數量相對於編解碼器複雜部分來說少,但事實上大大小小也牽涉到了十幾二十個函式(沒具體統計過,只是大概估算了下),想要一下子討論完比較困難,所以打算在接下來的若干篇文章

    HEVC學習 —— 預測系列之三

    今天主要介紹幀內預測一個很重要的函式initAdiPattern,它的主要功能有三個,(1)檢測當前PU的相鄰樣點包括左上、上、右上、左、左下鄰域樣點值的可用性,或者說檢查這些點是否存在;(2)參考樣點的替換過程,主要實現的是JCTVC-J1003即draft 8.4.4.

    HEVC預測1

    HEVC的幀內預測(intra prediction),即intra塊的預測過程,為intra塊解碼提供預測值(predSamples[ x ][ y ])。 首先要確定當前塊和鄰塊的關係。

    HEVC函式入門2——編碼一個CU

    這裡依然整理自http://blog.csdn.net/shaqoneal/article/details/37500715 且閱讀CU這部分主要對我而言是為了QP。另外一個方向是Tile不要迷失啦!!! 提醒我自己看http://blog.csdn.net

    HEVC學習-預測-initAdiPattern函式

    #define MAX_CU_DEPTH 6 // log2(LCUSize) 最大CU深度為6 #define MAX_CU_SIZE (1&l

    HEVC中的預測模式選擇Intra prediction mode selection in HEVC

    HEVC標準提供35個幀內預測模式,包括一個DC模式, 一個Planar模式,以及33個Angular模式。   在HEVC的test model HM10.0中,對於幀內預測的模式選擇可以總結為:35個預測模式首先根據STAD的方式,利用Hadamard變換,選擇RD-c

    33、編碼一個CU部分2、預測各種模式的實現

    HEVC中一共定義了35中幀內編碼預測模式,編號分別以0-34定義。其中模式0定義為平面模式(INTRA_PLANAR),模式1定義為均值模式(INTRA_DC),模式2~34定義為角度預測模式(INTRA_ANGULAR2~INTRA_ANGULAR34),分別代表了不同

    HEVC/預測Cross-Component Prediction (CCP)

    Cross-Component Prediction (CCP)跨元件預測是通過消除顏色元件的相關性,在保證顏色高保真度的同時,實現對視訊內容的高效壓縮,被HEVC RExt採納。其核心思想是使用亮度

    岡薩雷斯數字影象處理第二章數字圖形基礎——影象插,相鄰畫素,鄰接性,距離度量

    1.影象內插:從根本上看,內插是用已知資料來估計未知位置的數值的處理。 例如,假設一幅大小為500500畫素的影象要放大1.5倍到75075畫素,一種簡單的放大方法是建立一個假想的750750網格,它與原始影象有相同的間隔,然後將其收縮,使它準確的與原影象匹配。顯然,收縮後的750750網格

    VVC程式碼 BMS 預測學習之四xFillReferenceSamples()

    xFillReferenceSamples()函式是參考畫素的獲取過程。 主要步驟: 1、分析臨近的畫素是否可獲取 2、進行參考樣本的填充:若臨近的畫素全部可獲取,則賦值;全部不可獲取,則賦預設值;若部分可獲取,則對可獲取的賦對應的值,不可獲取的用預設值填充。

    VVC程式碼 BMS 預測學習之六Planar、DC及角度模式下預測值的計算

    1、Planar模式,函式xPredIntraPlanar(): 預測畫素是水平、垂直兩個方向上4個參考畫素的平均值。 left, top為預測畫素正左,正上方參考畫素值; right = leftColumn[height]- left, bottom =

    HEVC 預測

    幀內預測使用TU塊。利用當前圖片已經編碼的畫素進行預測。 預測模式 幀內預測可用塊大小為幀內預測分成35種預測模式,其中33種角度預測(2-34),Planar預測(0)和DC預測(1)。支援塊大小從4x4到64x64。 MPM選擇 亮度預測 當進行亮度預測時

    HEVC/H.265——預測

    轉載至:https://blog.csdn.net/NB_vol_1/article/details/53288626 感謝一下作者一、幀內預測,利用當前影象內已經編碼的畫素生成預測值二、生成預測值之後,和原始的值相減,得到殘差,後續的變換量化等操作就是基於殘差進行處理的三、

    HEVC亮度分量預測模式程式碼詳解

    作者:66 (轉載請註明出處) 從我自身的學習歷程來看,建議大家先把理論紮實了再去理解程式碼,程式碼裡也有註釋,與理論的地方一對應加上一點C程式設計基礎很容易就能理解。 按從內到外的順序,能夠更清晰地理解程式碼實現。 1. HEVC幀內Planar模式預測-預測畫素計算

    search16- elastic4s-嵌檔案nested and join

       從SQL領域來的使用者,對於ES的檔案關係維護方式會感到很不習慣。畢竟,ES是分散式資料庫只能高效處理獨個扁平型別檔案,無法支援關係式資料庫那樣的檔案拼接。但是,任何資料庫應用都無法避免樹型檔案關係,因為這是業務模式需要的表現形式。在ES裡,無論nested或join型別的資料,父-

    虛擬存與存映射文件區別與聯系

    程序 指令 ref 知識庫 緩沖 網站架構 文件的 計算機 聯系   虛擬內存與內存映射文件是操作系統內存管理的重要部分,二者有相似也有不同的地方,本文是作者學習與應用中得到的一些體會,有錯誤的地方,請提點。 二者的聯系:虛擬內存與內存映射文件都是將一部分內容加載的內存,另

    mysql學習筆記—— MySQL連接和外連接

    聚集函數 信息 _id left tro 做了 學習 作用 group MySQL內連接(inner join on) MySQL的內連接使用inner join on,它的效果跟使用where是一樣的,如果聯結的是兩個表,那麽需要左右的條件或者說字段是

    Java基礎異常處理關鍵字try catch finally throw throws

    cut main 5.1 模型 指針 str control 情況 實例   嗨咯,大家晚上好,我的博客首篇開始了 ,我們一起加油吧! 都說java 語言是非常健壯性 如:垃圾回收機制、內存模型、異常處理,強類型轉換、跨平臺,等等,使得Java語言的受到青睞。今天我們先來聊

    linux4.10.8 核移植---裁剪

    conf .cn 需要 正常 多少 分享 內核 col make 一、裁剪內核 1.1 第一次修改   現在的內核大小為2.8M左右,要裁剪到2.0M以下,畢竟給內核分區就只有2.0M。         這兩個設備我們沒有,裁剪掉。   進入make menuconfig中