圖形圖像處理-之-一個複雜度爲常數的快速局部自適應算法 下篇
[email protected]
2008.04.12
(2009.03.10 可以到這裏下載完整的可以編譯的項目源代碼: http://cid-10fa89dec380323f.skydrive.live.com/browse.aspx/.Public?uc=4
tag: 圖像二值化,局部自適應,二維模板
摘要: 圖像處理中,某些算法在對一個像素的處理都需要根據周圍很多像素的綜合信息
來做處理,這類算法一般叫做局部自適應算法;用以得到更好的處理效果,但很多時候
這都可能成爲一個性能瓶頸,因爲對一個像素點都需要做大量的處理;本文將提供我使
用的一個複雜度爲常數的快速局部自適應算法。
(當然,某些二維模板不一定能夠拆解成常數算法,但很多還是可以拆解成線性算法的)
正文:
代碼使用C++,編譯器:VC2005
測試平臺:(CPU:AMD64x2 4200+(2.37G); 內存:DDR2 677(雙通道); 編譯器:VC2005)
(請先參看文章的上篇)
E:我們來優化它,得到一個線性複雜度的算法
考慮一下,一行上相鄰的兩個像素,如果知道了上一個像素周圍的亮度和,那麼模板
移動一個像素後的亮度和也能很容易根據上一個亮度和得到;所以有了新的實現:
long getLocalLight_linearV( const TPicRegion & src, long x, long y0, long localHalfWidth)
{
long sumYLight = 0 ;
for ( long y = y0 - localHalfWidth;y <= y0 + localHalfWidth; ++ y)
{
const TARGB32 & mapBorderColor = getMapBorderColor(src,x,y);
sumYLight += getGrayInt(mapBorderColor);
}
return sumYLight;
}
// 返回圖像src中座標爲(x0,y)的橫軸上距離localHalfWidth內的所有像素的亮度和
long getLocalLight_linearH( const TPicRegion & src, long x0, long y, long localHalfWidth)
{
long sumXLight = 0 ;
for ( long x = x0 - localHalfWidth;x <= x0 + localHalfWidth; ++ x)
{
const TARGB32 & mapBorderColor = getMapBorderColor(src,x,y);
sumXLight += getGrayInt(mapBorderColor);
}
return sumXLight;
}
void localAdaptiveThreshold_linear( const TPicRegion & dst, const TPicRegion & src, long localWidth)
{
long width = dst.width;
if (src.width < width) width = src.width;
long height = dst.height;
if (src.height < height) height = src.height;
TARGB32 * srcLine = src.pdata;
TARGB32 * dstLine = dst.pdata;
long localHalfWidth = localWidth / 2 ;
long tLocalWidth = localHalfWidth * 2 + 1 ;
long tLocalWidthSqr = tLocalWidth * tLocalWidth;
long sumLight0 = getLocalLight_quadratic(src, - 1 , - 1 ,localHalfWidth);
for ( long y = 0 ;y < height; ++ y)
{
sumLight0 = sumLight0
+ getLocalLight_linearH(src, - 1 ,y + localHalfWidth,localHalfWidth)
- getLocalLight_linearH(src, - 1 ,y - localHalfWidth - 1 ,localHalfWidth);
long sumLight = sumLight0;
for ( long x = 0 ;x < width; ++ x)
{
sumLight = sumLight
+ getLocalLight_linearV(src,x + localHalfWidth,y,localHalfWidth)
- getLocalLight_linearV(src,x - localHalfWidth - 1 ,y,localHalfWidth);
long light = getGrayInt(srcLine[x]);
TUInt32 color = ((sumLight - light * tLocalWidthSqr) >> 31 );
((TUInt32 * )dstLine)[x] = color;
}
(TUInt8 *& )srcLine += src.byte_width;
(TUInt8 *& )dstLine += dst.byte_width;
}
}
localAdaptiveThreshold_linear函數的功能和localAdaptiveThreshold_quadratic的完全一樣;
速度測試:
//////////////////////////////////////////////////////////////
// localWidth= 5 | 17 | 51 | 151
//------------------------------------------------------------
//localAdaptiveThreshold_linear 21.25 7.20 2.33 0.72 FPS
//////////////////////////////////////////////////////////////
恩,隨着localWidth的增大,函數速度成線性降低
F:繼續優化,得到一個常數複雜度的算法
我們考慮了水平方向的計算優化,再來看看垂直方向上的計算節約,保留上一行的所有亮度和,
爲下一行的計算服務;算法實現如下:
{
return getGrayInt(getMapBorderColor(src,x,y));
}
void localAdaptiveThreshold_constant( const TPicRegion & dst, const TPicRegion & src, long localWidth)
{
long width = dst.width;
if (src.width < width) width = src.width;
if (width <= 0 ) return ;
long height = dst.height;
if (src.height < height) height = src.height;
TARGB32 * srcLine = src.pdata;
TARGB32 * dstLine = dst.pdata;
long localHalfWidth = localWidth / 2 ;
long tLocalWidth = localHalfWidth * 2 + 1 ;
long tLocalWidthSqr = tLocalWidth * tLocalWidth;
long * _sumLightArray = new long [width + 1 ];
long * sumLightArray =& _sumLightArray[ 1 ];
sumLightArray[ - 1 ] = getLocalLight_quadratic(src, - 1 , - 1 ,localHalfWidth);
for ( long x = 0 ;x < width; ++ x)
{
sumLightArray[x] = sumLightArray[x - 1 ]
+ getLocalLight_linearV(src,x + localHalfWidth, - 1 ,localHalfWidth)
- getLocalLight_linearV(src,x - localHalfWidth - 1 , - 1 ,localHalfWidth);
}
for ( long y = 0 ;y < height; ++ y)
{
long sumLight0 = sumLightArray[ - 1 ]
+ getLocalLight_linearH(src, - 1 ,y + localHalfWidth,localHalfWidth)
- getLocalLight_linearH(src, - 1 ,y - localHalfWidth - 1 ,localHalfWidth);
for ( long x = 0 ;x < width; ++ x)
{
long sumLight = sumLight0 + sumLightArray[x] - sumLightArray[x - 1 ]
+ getLocalLight_constant(src,x - localHalfWidth - 1 ,y - localHalfWidth - 1 )
+ getLocalLight_constant(src,x + localHalfWidth,y + localHalfWidth)
- getLocalLight_constant(src,x + localHalfWidth,y - localHalfWidth - 1 )
- getLocalLight_constant(src,x - localHalfWidth - 1 ,y + localHalfWidth);
sumLightArray[x - 1 ] = sumLight0;
sumLight0 = sumLight;
long light = getGrayInt(srcLine[x]);
TUInt32 color = ((sumLight - light * tLocalWidthSqr) >> 31 );
((TUInt32 * )dstLine)[x] = color;
}
sumLightArray[width - 1 ] = sumLight0;
(TUInt8 *& )srcLine += src.byte_width;
(TUInt8 *& )dstLine += dst.byte_width;
}
delete []_sumLightArray;
}
localAdaptiveThreshold_constant函數的功能和localAdaptiveThreshold_quadratic的完全一樣;
速度測試:
//////////////////////////////////////////////////////////////
// localWidth= 5 | 17 | 51 | 151
//------------------------------------------------------------
//localAdaptiveThreshold_constant 57.30 56.00 51.89 43.00 FPS
//////////////////////////////////////////////////////////////
:D 隨着localWidth的增大,速度變化不大!
當然,該函數還可以繼續優化的,比如將邊界和內部區域分開處理;
比如使用MMX、SSE等的指令,等等;
該常數複雜度算法的實現也可以用兩次模板運算來實現的,申請一個和源圖片一樣大的臨時緩
衝區,先計算緩衝區的每個點(x,y)在源圖片(x,y)點垂直M範圍內的亮度和(可以做到常數複雜度),
那麼計算源圖片(x,y)點周圍的亮度和就可以通過計算緩衝區(x,y)點水平M範圍內的亮度和(也可
以做到常數複雜度)來獲得;