今天看了下xvid的搜索算法,总结一下。
xvid_me_AdvDiamondSearch,顾名思义是高级钻石搜索算法。它所使用的搜索模板是大钻石。
*
* *
* * *
* *
*
(图1)
如图1所示,大钻石搜索模板一共有8个方向:left , right, top, down, left-top, left-down, right-top, right-down
由于图像的坐标系如图2所示:
x -->
y
|
v
(图2)
xvid中将这8个方向分加用以下数字表示
Top(4)
TL(5) TR(6 )
Left(1) Right(2)
DL(9) DR(10)
Down(8)
而这个算法的主要思想是:
bDirection代表sad满足条件的方向,
算法在初始化时,bDirection被设为255,以确保先对left, right, top, down四个方向都进行一遍搜索。然后查看iDirection是否非零,非零则说明有更好的方向,将该方向记录到bDirection中,然后更新坐标(x,y), 再在(x,y)进行与bDirection方向正交的搜索。同样,如果搜到更好的方向,也相应更新bDirection和(x,y)。
如果*iDirection为0
那么说明已经搜索到了一个局部的最小点了。但这个点不一定是全局最小。
所以在退出之前还要在斜线方向上进行搜索(left-top, left-down, right-top, right-down)。
具体搜索哪些方向是要看情况的。
//xvid 高级钻石搜索算法
void xvid_me_AdvDiamondSearch(int x, int y, SearchData * const data,
int bDirection, CheckFunc * const CheckCandidate)
{
/* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
unsigned int * const iDirection = &data->dir;
for(;;) { /* forever */
*iDirection = 0; //记录下一步要搜索的方向
if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1); //left
if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2); //right
if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4); //top
if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8); //down
/* now we're doing diagonal checks near our candidate */
if (*iDirection) { /* if anything found */
bDirection = *iDirection; //先保存一下
*iDirection = 0; //清零以便重新搜索
x = data->currentMV->x; y = data->currentMV->y; //更新搜索坐标
//以下在新的坐标点处搜索正交方向
if (bDirection & 3) { /* our candidate is left or right */
CHECK_CANDIDATE(x, y + iDiamondSize, 8); //down
CHECK_CANDIDATE(x, y - iDiamondSize, 4); //up
} else { /* what remains here is up or down */
CHECK_CANDIDATE(x + iDiamondSize, y, 2);
CHECK_CANDIDATE(x - iDiamondSize, y, 1);
}
if (*iDirection) { //如果该方向的sad也在域值以内
bDirection += *iDirection; //添加上该方向
x = data->currentMV->x; y = data->currentMV->y;
}
} else { /* about to quit, eh? not so fast.... */
switch (bDirection) { //HKY: bDirection: the best direction
//在退出之前分别对上,下,左,右,左上,左下,右上,右下共8个方向进行搜索
case 2:
CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
break;
case 1:
CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
break;
case 2 + 4:
CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
break;
case 4:
CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
break;
case 8:
CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
break;
case 1 + 4:
CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
break;
case 2 + 8:
CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
break;
case 1 + 8:
CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
break;
default: /* 1+2+4+8 == we didn't find anything at all */
CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
break;
}
//8个方向都没有合适的,*iDirection为零值,此时可以结束搜索
if (!*iDirection) break; /* ok, the end. really */
bDirection = *iDirection; //记录下新搜索到的方向
x = data->currentMV->x; y = data->currentMV->y; //更新下一步要搜索的坐标
}
}
}