h.264全搜索以及快速全搜索算法


Full Search

全搜索算法是最簡單暴力的一種搜索算法,對搜索范圍內的所有像素點都進行匹配對比,選出最合適的運動向量,以下就是一個搜索范圍為4的全搜索范圍(單個像素點)

 

/*!
 ***********************************************************************
 * \brief按照螺旋搜索順序進行全搜索
 *    Full pixel block motion search
 *    目標是得到(mv_x,mv_y)和min_mcost,(mv_x,mv_y)指示從哪里開始做分像素搜索,search center
 *    后者用來跟分像素搜索結果做比較
 ***********************************************************************
 */
int                                               //  ==> minimum motion cost after search
FullPelBlockMotionSearch (pel_t**   orig_pic,     // <--  original pixel values for the AxB block
                          int       ref,          // <--  reference frame (0... or -1 (backward))
                          int       list,
                          int       pic_pix_x,    // <--  absolute x-coordinate of regarded AxB blockAxB宏塊原點在圖像中的絕對坐標
                          int       pic_pix_y,    // <--  absolute y-coordinate of regarded AxB block
                          int       blocktype,    // <--  block type (1-16x16 ... 7-4x4)
                          int       pred_mv_x,    // <--  motion vector predictor (x) in sub-pel units
                          int       pred_mv_y,    // <--  motion vector predictor (y) in sub-pel units
                          int*      mv_x,         // <--> in: search center (x) / out: motion vector (x) - in pel units
                          int*      mv_y,         // <--> in: search center (y) / out: motion vector (y) - in pel units
                          int       search_range, // <--  1-d search range in pel units
                          int       min_mcost,    // <--  minimum motion cost (cost for center or huge value)
                          double    lambda)       // <--  lagrangian parameter for determining motion cost
{
  int   pos, cand_x, cand_y, y, x4, mcost;
  
  pel_t *orig_line, *ref_line;
  pel_t *(*get_ref_line)(int, pel_t*, int, int, int, int);//
//參考幀偏移量 幀場自適應且宏塊地址為偶數=4 幀場自適應宏塊地址為奇數=2 非幀場自適應=0
  int   list_offset   = ((img->MbaffFrameFlag)&&(img->mb_data[img->current_mb_nr].mb_field))? img->current_mb_nr%2 ? 4 : 2 : 0;
  pel_t *ref_pic            = listX[list+list_offset][ref]->imgY_11;
  int   img_width     = listX[list+list_offset][ref]->size_x;
  int   img_height    = listX[list+list_offset][ref]->size_y;

  int   best_pos      = 0;                                        // position with minimum motion cost
  //計算最大需要搜索的位置個數
  int   max_pos       = (2*search_range+1)*(2*search_range+1);    // number of search positions
  int   lambda_factor = LAMBDA_FACTOR (lambda);                   // factor for determining lagragian motion cost
  int   blocksize_y   = input->blc_size[blocktype][1];            // vertical block size
  int   blocksize_x   = input->blc_size[blocktype][0];            // horizontal block size
  int   blocksize_x4  = blocksize_x >> 2;                         // horizontal block size in 4-pel units
  int   pred_x        = (pic_pix_x << 2) + pred_mv_x;       // predicted position x (in sub-pel units)1/4子像素為單位的預測MV
  int   pred_y        = (pic_pix_y << 2) + pred_mv_y;       // predicted position y (in sub-pel units)
  int   center_x      = pic_pix_x + *mv_x;                        // center position x (in pel units)
  int   center_y      = pic_pix_y + *mv_y;                        // center position y (in pel units)
  int   check_for_00  = (blocktype==1 && !input->rdopt && img->type!=B_SLICE && ref==0);

  //===== set function for getting reference picture lines =====
  //通過判斷搜索范圍會不會出界,設置獲取參考像素值的函數
  if ((center_x > search_range) && (center_x < img->width -1-search_range-blocksize_x) &&
      (center_y > search_range) && (center_y < img->height-1-search_range-blocksize_y)   )
  {
     get_ref_line = FastLineX;//未出界
  }
  else
  {
     get_ref_line = UMVLineX;//出界
  }


  //===== loop over all search positions =====
  //max_pos是搜索位置的個數,計算見上面
  for (pos=0; pos<max_pos; pos++)
  {
    //--- set candidate position (absolute position in pel units) ---
    /*(center_x,center_y)是由預測MV估計出來的搜索中心,在以它為中心的范圍內,
    對按照螺旋形順序排列的候選點進行搜索,
    每個候選點都是一個可能參考塊的左上角起始點
  */
    cand_x = center_x + spiral_search_x[pos];//螺旋搜索
    cand_y = center_y + spiral_search_y[pos];

    //--- initialize motion cost (cost for motion vector) and check ---
    //計算MVD的代價,換算成四分之一像素(cand--candidate候選點)
    mcost = MV_COST (lambda_factor, 2, cand_x, cand_y, pred_x, pred_y);
    if (check_for_00 && cand_x==pic_pix_x && cand_y==pic_pix_y)
    {//螺旋搜索到的點為原點,不過為什么是減去16bit?
      mcost -= WEIGHTED_COST (lambda_factor, 16);
    }
    //如果只是MV的代價就已經大於現有的最小代價就舍棄
    if (mcost >= min_mcost)   continue;

    //--- add residual cost to motion cost ---
    //blocksize_y blocksize_x4 是分塊大小16x16 16x8 8x16......
    for (y=0; y<blocksize_y; y++) 
    {
      //(cand_x,cand_y+y)是一行的起始坐標,y++ 遍歷每一行
      ref_line  = get_ref_line (blocksize_x, ref_pic, cand_y+y, cand_x, img_height, img_width);
      orig_line = orig_pic [y];
      //計算當前幀和參考幀的像素殘差
      for (x4=0; x4<blocksize_x4; x4++) //以4個為一組計算
      {
        mcost += byte_abs[ *orig_line++ - *ref_line++ ];
        mcost += byte_abs[ *orig_line++ - *ref_line++ ];
        mcost += byte_abs[ *orig_line++ - *ref_line++ ];
        mcost += byte_abs[ *orig_line++ - *ref_line++ ];
      }

      if (mcost >= min_mcost)  //如果已經比最小代價大,就沒必要計算下面的行了
      {
        break;
      }
    }
    
    //--- check if motion cost is less than minimum cost ---
    //記錄下最小代價和最佳匹配位置
    if (mcost < min_mcost)
    {
      best_pos  = pos;
      min_mcost = mcost;
    }
  }


  //===== set best motion vector and return minimum motion cost =====
  if (best_pos)
  {
    *mv_x += spiral_search_x[best_pos];  //因為螺旋搜索數組中記錄的是該位置的點
    *mv_y += spiral_search_y[best_pos];  //與(center_x,center_y)的差
  }
  return min_mcost;  //返回最小代價
}
View Code
//螺旋搜索(全搜索)位置初始化
 for (k=1, l=1; l<=max(1,search_range); l++)
  {
    for (i=-l+1; i< l; i++)
    {
      spiral_search_x[k] =  i;  spiral_search_y[k++] = -l;
      spiral_search_x[k] =  i;  spiral_search_y[k++] =  l;
      /*
       *                                 
       *                         9  3 5 7 10
       *          1 0 2          11 1 0 2 12
       *                         13 4 6 8 14
       * 
       */
    }
    for (i=-l;   i<=l; i++)
    {
      spiral_search_x[k] = -l;  spiral_search_y[k++] =  i;
      spiral_search_x[k] =  l;  spiral_search_y[k++] =  i;
      /*                             15 17 19  21 23
       *         3 5 7                9  3  5  7  10
       *         1 0 2               11  1  0  2  12
       *         4 6 8               13  4  6  8  14
       *                             16 18 20 22  24 
       */ 
    }
  }
View Code

 

Fast Full Search

由於運動搜索時有多種塊的類型(16x16,8x16,8x8,4x4等)因此,在全搜索時,會由於位置重疊而產生同一處的像素殘差多次計算的情況,為了避免這種情況,可以一次性把搜索范圍內的所有像素殘差計算出來,不同塊類型只需要把殘差進行組合即可得到該類型的SAD

/*!
 ***********************************************************************
 * \brief快速正像素搜索
 *    Fast Full pixel block motion search
 *    目標是得到(mv_x,mv_y)和min_mcost,(mv_x,mv_y)指示從哪里開始做分像素搜索,search center
 *    后者用來跟分像素搜索結果做比較
 ***********************************************************************
 */
int                                                   //  ==> minimum motion cost after search
FastFullPelBlockMotionSearch (pel_t**   orig_pic,     // <--  not used
                              int       ref,          // <--  reference frame (0... or -1 (backward))
                              int       list,
                              int       pic_pix_x,    // <--  absolute x-coordinate of regarded AxB block
                              int       pic_pix_y,    // <--  absolute y-coordinate of regarded AxB block
                              int       blocktype,    // <--  block type (1-16x16 ... 7-4x4)
                              int       pred_mv_x,    // <--  motion vector predictor (x) in sub-pel units
                              int       pred_mv_y,    // <--  motion vector predictor (y) in sub-pel units
                              int*      mv_x,         //  --> motion vector (x) - in pel units
                              int*      mv_y,         //  --> motion vector (y) - in pel units
                              int       search_range, // <--  1-d search range in pel units
                              int       min_mcost,    // <--  minimum motion cost (cost for center or huge value)
                              double    lambda)       // <--  lagrangian parameter for determining motion cost
{
  int   pos, offset_x, offset_y, cand_x, cand_y, mcost;

  int   max_pos       = (2*search_range+1)*(2*search_range+1);              // number of search positions
  int   lambda_factor = LAMBDA_FACTOR (lambda);                             // factor for determining lagragian motion cost
  int   best_pos      = 0;                                                  // position with minimum motion cost
  int   block_index;                                                        // block index for indexing SAD array
  int*  block_sad;                                                          // pointer to SAD array

  block_index   = (pic_pix_y-img->opix_y)+((pic_pix_x-img->opix_x)>>2); // block index for indexing SAD array
  block_sad     = BlockSAD[list][ref][blocktype][block_index];         // pointer to SAD array

  //===== set up fast full integer search if needed / set search center =====
  if (!search_setup_done[list][ref])//對一個參考幀只做一次
  {
    //計算搜索范圍所有位置所有分塊模式的SAD(整像素)
    SetupFastFullPelSearch (ref, list);
  }

  offset_x = search_center_x[list][ref] - img->opix_x; //搜索中心相對原宏塊的偏移
  offset_y = search_center_y[list][ref] - img->opix_y;

  //===== cost for (0,0)-vector: it is done before, because MVCost can be negative =====
  //原點(這里的原點都是是當前塊所在的位置)
  if (!input->rdopt)
  {
    //把剛才計算的SAD 跟mv代價相加得到總代價
    mcost = block_sad[pos_00[list][ref]] + MV_COST (lambda_factor, 2, 0, 0, pred_mv_x, pred_mv_y);
    if (mcost < min_mcost)
    {
      min_mcost = mcost;
      best_pos  = pos_00[list][ref];//每幀搜索中心的位置
    }
  }

  //===== loop over all search positions =====
  for (pos=0; pos<max_pos; pos++, block_sad++)
  {
    //--- check residual cost ---
    if (*block_sad < min_mcost)
    {
      //--- get motion vector cost ---
      //計算出搜索位置,按照螺旋形順序spiral_search_xy
      cand_x = offset_x + spiral_search_x[pos];
      cand_y = offset_y + spiral_search_y[pos];
      mcost  = *block_sad;//在SetupFastFullPelSearch已經做好
      mcost += MV_COST (lambda_factor, 2, cand_x, cand_y, pred_mv_x, pred_mv_y);    //計算 MV 代價

      //--- check motion cost ---
      if (mcost < min_mcost)
      {
        min_mcost = mcost;
        best_pos  = pos;
      }
    }
  }

  //===== set best motion vector and return minimum motion cost =====
  *mv_x = offset_x + spiral_search_x[best_pos];//根據代價最小,計算出最佳MV
  *mv_y = offset_y + spiral_search_y[best_pos];
  return min_mcost;
}
View Code

 

 

Edge Process

通常來說,計算SAD是以一行一行為單位進行,不過在進行搜索時,難免會有運動向量指向圖像外的區域,圖像以外的這些區域的像素取值為圖像邊界的值,即

 

$Pic[x,y]=\left\{\begin{matrix}
Pic[0,y] & x<0\\
Pic[width-1,y] & x\geq width\\
Pic[x,0] & 0\leq x < width,y<0\\
Pic[x,height-1] & 0\leq x < width,y \geq height\\
Pic[x,y] & other
\end{matrix}\right.$

 

/*如果參考塊超出參考幀邊界,用邊界值進行填充*/
pel_t *UMVLineX (int size, pel_t* Pic, int y, int x, int height, int width)
{
  int i, maxx;
  pel_t *Picy;

  Picy = Pic + max(0,min(height-1,y)) * width;  //先把y范圍限制在(0,height-1)內

  if (x < 0)                            // Left edge
  {
    maxx = min(0,x+size);   //搜索范圍可以大於16的,所以x+16是可以小於0的
    for (i = x; i < maxx; i++)  //把出界的部分都賦值為邊界上的值,一畫圖就理解了
    {
      line[i-x] = Picy [0];             // Replicate left edge pixel
    }
    maxx = x+size;                         //把沒出界的像素也拷貝到line數組中    
    for (i = 0; i < maxx; i++)          // Copy non-edge pixels
      line[i-x] = Picy [i];
  }
  else if (x > width-size)         // Right edge  同理
  {
    maxx = width;
    for (i = x; i < maxx; i++)
    {
      line[i-x] = Picy [i];             // Copy non-edge pixels
    }
    maxx = x+size;
    for (i = max(width,x); i < maxx; i++)
    {
      line[i-x] = Picy [width-1];  // Replicate right edge pixel
    }
  }
  else                                  // No edge  ,則返回y行x列的地址
  {
    return Picy + x;
  }

  return line;    //否則,返回line數組的地址
}
View Code


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM