文件位置
openh264/codec/processing/src/BackgroundDetection.cpp
代码流程
核心函数
从代码流程可以看到实现背景检测的核心功能主要是CBackgroundDetection类中ForegroundBackgroundDivision
函数和ForegroundDilationAndBackgroundErosion
函数。
原理
参数开关控制 :(bool)bEnableBackgroundDetection
ForegroundBackgroundDivision 函数
功能 :前景和背景粗略区分原理过程 :
计算以宏块为单位的图像宽iPicWidthInOU和高iPicHeightInOU; 计算每行的宏块个数iPicWidthInMb; 声明并初始化指向Background OU数组的指针,该数组内部是宏块级OU 的数据信息; 双层for 循环遍历所有宏块级 OU单元;
调用GetOUParameters函数获取 OU 参数,主要是iSD、iSAD、ISD、iMAD、iMinSubMad、iMaxDiffSubSd; 当前 OU背景标志iBackgroundFlag赋值 0; 如果当前OU的平均绝对偏差(Mean Absolute Difference,MAD)大于63,则跳过当前OU;移动到下一个 OU; 如果当前 OU 的iMaxDiffSubSd小于等于iSAD / 8或者iMaxDiffSubSd小于等于16x8,且iSAD小于2x16x16x2;
如果iSAD小于16*8,则当前OU背景标志iBackgroundFlag 赋值 1; 否则,当前OU背景标志iBackgroundFlag 的计算公式如下:
如果当前 OU 的iSAD 小于2x16x16,判断当前 OU 的iSD是否小于iSADx3 / 4,将大小关系结果赋值给iBackgroundFlag; 否则,判断当前 OU 的iSDx2 是否小于当前 OU 的iSAD,将大小关系结果赋值给iBackgroundFlag; 移动到下一个宏块级OU;
原理图 : 相关源码 :
ForegroundBackgroundDivision
函数
void CBackgroundDetection :: ForegroundBackgroundDivision ( vBGDParam* pBgdParam) {
int32_t iPicWidthInOU = pBgdParam-> iBgdWidth >> LOG2_BGD_OU_SIZE;
int32_t iPicHeightInOU = pBgdParam-> iBgdHeight >> LOG2_BGD_OU_SIZE;
int32_t iPicWidthInMb = ( 15 + pBgdParam-> iBgdWidth) >> 4 ;
SBackgroundOU* pBackgroundOU = pBgdParam-> pOU_array;
for ( int32_t j = 0 ; j < iPicHeightInOU; j ++ ) {
for ( int32_t i = 0 ; i < iPicWidthInOU; i++ ) {
GetOUParameters ( pBgdParam-> pCalcRes, ( j * iPicWidthInMb + i) << ( LOG2_BGD_OU_SIZE - LOG2_MB_SIZE) , iPicWidthInMb,
pBackgroundOU) ;
pBackgroundOU-> iBackgroundFlag = 0 ;
if ( pBackgroundOU-> iMAD > 63 ) {
pBackgroundOU++ ;
continue ;
}
if ( ( pBackgroundOU-> iMaxDiffSubSd <= pBackgroundOU-> iSAD >> 3
|| pBackgroundOU-> iMaxDiffSubSd <= ( BGD_OU_SIZE * Q_FACTOR) )
&& pBackgroundOU-> iSAD < ( BGD_THD_SAD << 1 ) ) {
if ( pBackgroundOU-> iSAD <= BGD_OU_SIZE * Q_FACTOR) {
pBackgroundOU-> iBackgroundFlag = 1 ;
} else {
pBackgroundOU-> iBackgroundFlag = pBackgroundOU-> iSAD < BGD_THD_SAD ?
( pBackgroundOU-> iSD < ( pBackgroundOU-> iSAD * 3 ) >> 2 ) :
( pBackgroundOU-> iSD << 1 < pBackgroundOU-> iSAD) ;
}
}
pBackgroundOU++ ;
}
}
}
void CBackgroundDetection :: GetOUParameters ( SVAACalcResult* sVaaCalcInfo, int32_t iMbIndex, int32_t iMbWidth,
SBackgroundOU* pBgdOU) {
int32_t iSubSD[ 4 ] ;
uint8_t iSubMAD[ 4 ] ;
int32_t iSubSAD[ 4 ] ;
uint8_t ( * pMad8x8) [ 4 ] ;
int32_t ( * pSad8x8) [ 4 ] ;
int32_t ( * pSd8x8) [ 4 ] ;
pSad8x8 = sVaaCalcInfo-> pSad8x8;
pMad8x8 = sVaaCalcInfo-> pMad8x8;
pSd8x8 = sVaaCalcInfo-> pSumOfDiff8x8;
iSubSAD[ 0 ] = pSad8x8[ iMbIndex] [ 0 ] ;
iSubSAD[ 1 ] = pSad8x8[ iMbIndex] [ 1 ] ;
iSubSAD[ 2 ] = pSad8x8[ iMbIndex] [ 2 ] ;
iSubSAD[ 3 ] = pSad8x8[ iMbIndex] [ 3 ] ;
iSubSD[ 0 ] = pSd8x8[ iMbIndex] [ 0 ] ;
iSubSD[ 1 ] = pSd8x8[ iMbIndex] [ 1 ] ;
iSubSD[ 2 ] = pSd8x8[ iMbIndex] [ 2 ] ;
iSubSD[ 3 ] = pSd8x8[ iMbIndex] [ 3 ] ;
iSubMAD[ 0 ] = pMad8x8[ iMbIndex] [ 0 ] ;
iSubMAD[ 1 ] = pMad8x8[ iMbIndex] [ 1 ] ;
iSubMAD[ 2 ] = pMad8x8[ iMbIndex] [ 2 ] ;
iSubMAD[ 3 ] = pMad8x8[ iMbIndex] [ 3 ] ;
pBgdOU-> iSD = iSubSD[ 0 ] + iSubSD[ 1 ] + iSubSD[ 2 ] + iSubSD[ 3 ] ;
pBgdOU-> iSAD = iSubSAD[ 0 ] + iSubSAD[ 1 ] + iSubSAD[ 2 ] + iSubSAD[ 3 ] ;
pBgdOU-> iSD = WELS_ABS ( pBgdOU-> iSD) ;
pBgdOU-> iMAD = WELS_MAX ( WELS_MAX ( iSubMAD[ 0 ] , iSubMAD[ 1 ] ) , WELS_MAX ( iSubMAD[ 2 ] , iSubMAD[ 3 ] ) ) ;
pBgdOU-> iMinSubMad = WELS_MIN ( WELS_MIN ( iSubMAD[ 0 ] , iSubMAD[ 1 ] ) , WELS_MIN ( iSubMAD[ 2 ] , iSubMAD[ 3 ] ) ) ;
pBgdOU-> iMaxDiffSubSd = WELS_MAX ( WELS_MAX ( iSubSD[ 0 ] , iSubSD[ 1 ] ) , WELS_MAX ( iSubSD[ 2 ] , iSubSD[ 3 ] ) ) -
WELS_MIN ( WELS_MIN ( iSubSD[ 0 ] , iSubSD[ 1 ] ) , WELS_MIN ( iSubSD[ 2 ] , iSubSD[ 3 ] ) ) ;
}
ForegroundDilationAndBackgroundErosion 函数
功能 :前景膨胀和背景腐蚀函数关系图 : 过程 :
定义iPicStrideUV变量存储 图像UV 分量步长; 计算宏块级OU 的宽iPicWidthInOU和高iPicHeightInOU; 计算宏块级OU 的 UV 步长iOUStrideUV; 计算每行宏块个数iPicWidthInMb; 定义了一个指向SBackgroundOU结构体的指针pBackgroundOU,用来访问背景检测单元数组; 定义了一个指向int8_t的指针pVaaBackgroundMbFlag,用来访问背景宏块标志数组; 定义了一个长度为4的指针数组pOUNeighbours,用来存储当前OU的四个邻居OU的指针; 将pOUNeighbours[2](即顶部OU)初始化为pBackgroundOU; 外层 for 循环 遍历每一列宏块级OU;
初始化pRowSkipFlag指针,指向当前行的宏块标志; 初始化 pOUNeighbours[0] (左OU) 为pBackgroundOU; 计算pOUNeighbours[3](底OU); 内存 for 循环遍历每一行宏块级OU;
计算pOUNeighbours[1](即右OU); 如果当前 OU pBackgroundOU的iBackgroundFlag为真;
调用ForegroundDilation函数进行前景膨胀; 否则;
调用BackgroundErosion函数进行背景腐蚀; 调用UpperOUForegroundCheck函数检测上方 OU是否为前景; 调用SetBackgroundMbFlag函数设置背景宏块标志; 更新pRowSkipFlag,pOUNeighbours、pBackgroundOU为下一个 宏块级OU 做准备; 更新pOUNeighbours[2]和pVaaBackgroundMbFlag指针,为下一行OU的处理做准备。
原理图 : 相关源码 :
ForegroundDilationAndBackgroundErosion
函数
void CBackgroundDetection :: ForegroundDilationAndBackgroundErosion ( vBGDParam* pBgdParam) {
int32_t iPicStrideUV = pBgdParam-> iStride[ 1 ] ;
int32_t iPicWidthInOU = pBgdParam-> iBgdWidth >> LOG2_BGD_OU_SIZE;
int32_t iPicHeightInOU = pBgdParam-> iBgdHeight >> LOG2_BGD_OU_SIZE;
int32_t iOUStrideUV = iPicStrideUV << ( LOG2_BGD_OU_SIZE - 1 ) ;
int32_t iPicWidthInMb = ( 15 + pBgdParam-> iBgdWidth) >> 4 ;
SBackgroundOU* pBackgroundOU = pBgdParam-> pOU_array;
int8_t * pVaaBackgroundMbFlag = ( int8_t * ) pBgdParam-> pBackgroundMbFlag;
SBackgroundOU* pOUNeighbours[ 4 ] ;
pOUNeighbours[ 2 ] = pBackgroundOU;
for ( int32_t j = 0 ; j < iPicHeightInOU; j ++ ) {
int8_t * pRowSkipFlag = pVaaBackgroundMbFlag;
pOUNeighbours[ 0 ] = pBackgroundOU;
pOUNeighbours[ 3 ] = pBackgroundOU + ( iPicWidthInOU & ( ( j == iPicHeightInOU - 1 ) - 1 ) ) ;
for ( int32_t i = 0 ; i < iPicWidthInOU; i++ ) {
pOUNeighbours[ 1 ] = pBackgroundOU + ( i < iPicWidthInOU - 1 ) ;
if ( pBackgroundOU-> iBackgroundFlag)
ForegroundDilation ( pBackgroundOU, pOUNeighbours, pBgdParam, j * iOUStrideUV + ( i << LOG2_BGD_OU_SIZE_UV) ) ;
else
BackgroundErosion ( pBackgroundOU, pOUNeighbours) ;
if ( j > 1 && i > 0 && i < iPicWidthInOU - 1 && pOUNeighbours[ 2 ] -> iBackgroundFlag == 1 ) {
UpperOUForegroundCheck ( pOUNeighbours[ 2 ] , pRowSkipFlag - OU_SIZE_IN_MB * iPicWidthInMb, iPicWidthInOU, iPicWidthInMb) ;
}
SetBackgroundMbFlag ( pRowSkipFlag, iPicWidthInMb, pBackgroundOU-> iBackgroundFlag) ;
pRowSkipFlag += OU_SIZE_IN_MB;
pOUNeighbours[ 0 ] = pBackgroundOU;
pOUNeighbours[ 2 ] ++ ;
pOUNeighbours[ 3 ] ++ ;
pBackgroundOU++ ;
}
pOUNeighbours[ 2 ] = pBackgroundOU - iPicWidthInOU;
pVaaBackgroundMbFlag += OU_SIZE_IN_MB * iPicWidthInMb;
}
}
inline void CBackgroundDetection :: ForegroundDilation ( SBackgroundOU* pBackgroundOU, SBackgroundOU* pOUNeighbours[ ] ,
vBGDParam* pBgdParam, int32_t iChromaSampleStartPos) {
int32_t iPicStrideUV = pBgdParam-> iStride[ 1 ] ;
int32_t iSumNeighBackgroundFlags = pOUNeighbours[ 0 ] -> iBackgroundFlag + pOUNeighbours[ 1 ] -> iBackgroundFlag +
pOUNeighbours[ 2 ] -> iBackgroundFlag + pOUNeighbours[ 3 ] -> iBackgroundFlag;
if ( pBackgroundOU-> iSAD > BGD_OU_SIZE * Q_FACTOR) {
switch ( iSumNeighBackgroundFlags) {
case 0 :
case 1 :
pBackgroundOU-> iBackgroundFlag = 0 ;
break ;
case 2 :
case 3 :
pBackgroundOU-> iBackgroundFlag = ! ForegroundDilation23Luma ( pBackgroundOU, pOUNeighbours) ;
if ( pBackgroundOU-> iBackgroundFlag == 1 ) {
int8_t iNeighbourForegroundFlags = ( ! pOUNeighbours[ 0 ] -> iBackgroundFlag) | ( ( ! pOUNeighbours[ 1 ] -> iBackgroundFlag) << 1 )
| ( ( ! pOUNeighbours[ 2 ] -> iBackgroundFlag) << 2 ) | ( ( ! pOUNeighbours[ 3 ] -> iBackgroundFlag) << 3 ) ;
pBackgroundOU-> iBackgroundFlag = ! ForegroundDilation23Chroma ( iNeighbourForegroundFlags, iChromaSampleStartPos,
iPicStrideUV, pBgdParam) ;
}
break ;
default :
break ;
}
}
}
inline void CBackgroundDetection :: BackgroundErosion ( SBackgroundOU* pBackgroundOU, SBackgroundOU* pOUNeighbours[ ] ) {
if ( pBackgroundOU-> iMaxDiffSubSd <= ( BGD_OU_SIZE * Q_FACTOR) ) {
int32_t iSumNeighBackgroundFlags = pOUNeighbours[ 0 ] -> iBackgroundFlag + pOUNeighbours[ 1 ] -> iBackgroundFlag +
pOUNeighbours[ 2 ] -> iBackgroundFlag + pOUNeighbours[ 3 ] -> iBackgroundFlag;
int32_t sumNbrBGsad = ( pOUNeighbours[ 0 ] -> iSAD & ( - pOUNeighbours[ 0 ] -> iBackgroundFlag) ) + ( pOUNeighbours[ 2 ] -> iSAD &
( - pOUNeighbours[ 2 ] -> iBackgroundFlag) )
+ ( pOUNeighbours[ 1 ] -> iSAD & ( - pOUNeighbours[ 1 ] -> iBackgroundFlag) ) + ( pOUNeighbours[ 3 ] -> iSAD &
( - pOUNeighbours[ 3 ] -> iBackgroundFlag) ) ;
if ( pBackgroundOU-> iSAD * iSumNeighBackgroundFlags <= ( 3 * sumNbrBGsad) >> 1 ) {
if ( iSumNeighBackgroundFlags == 4 ) {
pBackgroundOU-> iBackgroundFlag = 1 ;
} else {
if ( ( pOUNeighbours[ 0 ] -> iBackgroundFlag & pOUNeighbours[ 1 ] -> iBackgroundFlag)
|| ( pOUNeighbours[ 2 ] -> iBackgroundFlag & pOUNeighbours[ 3 ] -> iBackgroundFlag) ) {
pBackgroundOU-> iBackgroundFlag = ! ForegroundDilation23Luma ( pBackgroundOU, pOUNeighbours) ;
}
}
}
}
}
inline void CBackgroundDetection :: UpperOUForegroundCheck ( SBackgroundOU* pCurOU, int8_t * pBackgroundMbFlag,
int32_t iPicWidthInOU, int32_t iPicWidthInMb) {
if ( pCurOU-> iSAD > BGD_OU_SIZE * Q_FACTOR) {
SBackgroundOU* pOU_L = pCurOU - 1 ;
SBackgroundOU* pOU_R = pCurOU + 1 ;
SBackgroundOU* pOU_U = pCurOU - iPicWidthInOU;
SBackgroundOU* pOU_D = pCurOU + iPicWidthInOU;
if ( pOU_L-> iBackgroundFlag + pOU_R-> iBackgroundFlag + pOU_U-> iBackgroundFlag + pOU_D-> iBackgroundFlag <= 1 ) {
SetBackgroundMbFlag ( pBackgroundMbFlag, iPicWidthInMb, 0 ) ;
pCurOU-> iBackgroundFlag = 0 ;
}
}
}
ForegroundDilation23Luma
函数
inline bool CBackgroundDetection :: ForegroundDilation23Luma ( SBackgroundOU* pBackgroundOU,
SBackgroundOU* pOUNeighbours[ ] ) {
SBackgroundOU* pOU_L = pOUNeighbours[ 0 ] ;
SBackgroundOU* pOU_R = pOUNeighbours[ 1 ] ;
SBackgroundOU* pOU_U = pOUNeighbours[ 2 ] ;
SBackgroundOU* pOU_D = pOUNeighbours[ 3 ] ;
if ( pBackgroundOU-> iMAD > pBackgroundOU-> iMinSubMad << 1 ) {
int32_t iMaxNbrForegroundMad;
int32_t iMaxNbrBackgroundMad;
int32_t aBackgroundMad[ 4 ] ;
int32_t aForegroundMad[ 4 ] ;
aForegroundMad[ 0 ] = ( pOU_L-> iBackgroundFlag - 1 ) & pOU_L-> iMAD;
aForegroundMad[ 1 ] = ( pOU_R-> iBackgroundFlag - 1 ) & pOU_R-> iMAD;
aForegroundMad[ 2 ] = ( pOU_U-> iBackgroundFlag - 1 ) & pOU_U-> iMAD;
aForegroundMad[ 3 ] = ( pOU_D-> iBackgroundFlag - 1 ) & pOU_D-> iMAD;
iMaxNbrForegroundMad = WELS_MAX ( WELS_MAX ( aForegroundMad[ 0 ] , aForegroundMad[ 1 ] ) , WELS_MAX ( aForegroundMad[ 2 ] ,
aForegroundMad[ 3 ] ) ) ;
aBackgroundMad[ 0 ] = ( ( ! pOU_L-> iBackgroundFlag) - 1 ) & pOU_L-> iMAD;
aBackgroundMad[ 1 ] = ( ( ! pOU_R-> iBackgroundFlag) - 1 ) & pOU_R-> iMAD;
aBackgroundMad[ 2 ] = ( ( ! pOU_U-> iBackgroundFlag) - 1 ) & pOU_U-> iMAD;
aBackgroundMad[ 3 ] = ( ( ! pOU_D-> iBackgroundFlag) - 1 ) & pOU_D-> iMAD;
iMaxNbrBackgroundMad = WELS_MAX ( WELS_MAX ( aBackgroundMad[ 0 ] , aBackgroundMad[ 1 ] ) , WELS_MAX ( aBackgroundMad[ 2 ] ,
aBackgroundMad[ 3 ] ) ) ;
return ( ( iMaxNbrForegroundMad > pBackgroundOU-> iMinSubMad << 2 ) || ( pBackgroundOU-> iMAD > iMaxNbrBackgroundMad << 1
&& pBackgroundOU-> iMAD <= ( iMaxNbrForegroundMad * 3 ) >> 1 ) ) ;
}
return 0 ;
}
ForegroundDilation23Chroma
函数
inline bool CBackgroundDetection :: ForegroundDilation23Chroma ( int8_t iNeighbourForegroundFlags,
int32_t iStartSamplePos, int32_t iPicStrideUV, vBGDParam* pBgdParam) {
static const int8_t kaOUPos[ 4 ] = { OU_LEFT, OU_RIGHT, OU_TOP, OU_BOTTOM} ;
int32_t aEdgeOffset[ 4 ] = { 0 , BGD_OU_SIZE_UV - 1 , 0 , iPicStrideUV* ( BGD_OU_SIZE_UV - 1 ) } ;
int32_t iStride[ 4 ] = { iPicStrideUV, iPicStrideUV, 1 , 1 } ;
for ( int32_t i = 0 ; i < 4 ; i++ ) {
if ( iNeighbourForegroundFlags & kaOUPos[ i] ) {
uint8_t * pRefC = pBgdParam-> pRef[ 2 ] + iStartSamplePos + aEdgeOffset[ i] ;
uint8_t * pCurC = pBgdParam-> pCur[ 2 ] + iStartSamplePos + aEdgeOffset[ i] ;
if ( CalculateAsdChromaEdge ( pRefC, pCurC, iStride[ i] ) > BGD_THD_ASD_UV) {
return 1 ;
}
}
}
for ( int32_t i = 0 ; i < 4 ; i++ ) {
if ( iNeighbourForegroundFlags & kaOUPos[ i] ) {
uint8_t * pRefC = pBgdParam-> pRef[ 1 ] + iStartSamplePos + aEdgeOffset[ i] ;
uint8_t * pCurC = pBgdParam-> pCur[ 1 ] + iStartSamplePos + aEdgeOffset[ i] ;
if ( CalculateAsdChromaEdge ( pRefC, pCurC, iStride[ i] ) > BGD_THD_ASD_UV) {
return 1 ;
}
}
}
return 0 ;
}
inline int32_t CBackgroundDetection :: CalculateAsdChromaEdge ( uint8_t * pOriRef, uint8_t * pOriCur, int32_t iStride) {
int32_t ASD = 0 ;
int32_t idx;
for ( idx = 0 ; idx < BGD_OU_SIZE_UV; idx++ ) {
ASD += * pOriCur - * pOriRef;
pOriRef += iStride;
pOriCur += iStride;
}
return WELS_ABS ( ASD) ;
}