图形图像处理-之-一个复杂度为常数的快速局部自适应算法 下篇

  [email protected]    2008.04.12

tag: 图像二值化,局部自适应,二维模板
  
摘要: 图像处理中,某些算法在对一个像素的处理都需要根据周围很多像素的综合信息
来做处理,这类算法一般叫做局部自适应算法;用以得到更好的处理效果,但很多时候
这都可能成为一个性能瓶颈,因为对一个像素点都需要做大量的处理;本文将提供我使
用的一个复杂度为常数的快速局部自适应算法。
(当然,某些二维模板不一定能够拆解成常数算法,但很多还是可以拆解成线性算法的)
       
正文:
  代码使用C++,编译器:VC2005
  测试平台:(CPU:AMD64x2 4200+(2.37G); 内存:DDR2 677(双通道); 编译器:VC2005)
 
(请先参看文章的上篇)


E:我们来优化它,得到一个线性复杂度的算法
  考虑一下,一行上相邻的两个像素,如果知道了上一个像素周围的亮度和,那么模板
移动一个像素后的亮度和也能很容易根据上一个亮度和得到;所以有了新的实现:

     // 返回图像src中坐标为(x,y0)的纵轴上距离localHalfWidth内的所有像素的亮度和
     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:继续优化,得到一个常数复杂度的算法
  我们考虑了水平方向的计算优化,再来看看垂直方向上的计算节约,保留上一行的所有亮度和,
为下一行的计算服务;算法实现如下:

    inline  long  getLocalLight_constant( const  TPicRegion &  src, long  x, long  y)
    {
        
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范围内的亮度和(也可
以做到常数复杂度)来获得;

你可能感兴趣的:(图形图像处理-之-一个复杂度为常数的快速局部自适应算法 下篇)