圖形圖像處理-之-誤差擴散 中篇

                        圖形圖像處理-之-誤差擴散 中篇
                     
[email protected]    2008.04.22


(2010.01.05 文章由2篇變成3篇,對誤差擴散的速度和質量作進一步探討!
  代碼也有一些更新,容納到我的圖像處理建議框架內,並提供源代碼下載!
  測試環境也有了變動;由AMD64x2 4200+(2.37G)DDR2 677(雙通道) 升級爲i7-920 DDR3 1333(三通道) )

(2008.12.01 修正一處bug,顏色誤差多累加了一次; 該錯誤由QueQuan發現,表示感謝! )

 
tag: 誤差擴散,真彩色到高彩色轉換,色階,減色,半色調
  
摘要: 在圖像的顏色轉換過程中,由於顏色值域的不同,轉換過程中可能會產生誤差;
誤差擴散算法通過將誤差傳遞到周圍像素而減輕其造成的視覺誤差。
上篇:簡單實現; 中篇:簡單的速度優化; 下篇: 更快的速度或更好的效果.

 

(測試源代碼下載: https://github.com/sisong/demoForHssBlog )

 

正文:
  代碼使用C++,編譯器:VC2005
  測試平臺:(CPU:i7-920(3.44G); 內存:DDR3 1333(三通道); 編譯器:VC2005)
  
(請先參看文章的上篇)
 
 
E: 將誤差擴散的浮點實現改寫爲一個整數的定點數實現:


 struct  TErrorColor{
         long  dR;
         long  dG;
         long  dB;
    };
    inline  long  getBestRGB16_555Color( const   long  wantColor){
         const   long  rMax = ( 1 << 5 ) - 1 ;
         if  (wantColor <= 0 )
             return   0 ;
         else   if  (wantColor >= (rMax << 3 ))
             return  rMax;
         else
             return  wantColor >> 3 ;
    }
    inline  long  getC8Color( const   long  rColor){
         return  rColor*(255*(1<<16)/((1<<5)-1)) >>16; // rColor*255/((1<<5)-1);
    }
     void  CvsPic32To16_ErrorDiffuse_Line_1(UInt16 *  pDst, const  Color32 *  pSrc, long  width,TErrorColor *  PHLineErr){
        TErrorColor HErr;
        HErr.dR = 0 ; HErr.dG = 0 ; HErr.dB = 0 ;
        PHLineErr[ - 1 ].dB = 0 ; PHLineErr[ - 1 ].dG = 0 ; PHLineErr[ - 1 ].dR = 0 ;
         for  ( long  x = 0 ;x < width; ++ x)
        {
             long  cB = (pSrc[x].b + HErr.dB*2  + PHLineErr[x].dB );
             long  cG = (pSrc[x].g + HErr.dG*2  + PHLineErr[x].dG );
             long  cR = (pSrc[x].r + HErr.dR*2  + PHLineErr[x].dR );
             long  rB = getBestRGB16_555Color(cB);
             long  rG = getBestRGB16_555Color(cG);
             long  rR = getBestRGB16_555Color(cR);
            pDst[x] =  rB | (rG << 5 ) | (rR << 10 );
            HErr.dB = (cB - getC8Color(rB)) >> 2 ;
            HErr.dG = (cG - getC8Color(rG)) >> 2 ;
            HErr.dR = (cR - getC8Color(rR)) >> 2 ;
            PHLineErr[x - 1 ].dB += HErr.dB;
            PHLineErr[x - 1 ].dG += HErr.dG;
            PHLineErr[x - 1 ].dR += HErr.dR;
            PHLineErr[x] = HErr;
        }
    }
void  CvsPic32To16_ErrorDiffuse_1( const  TPicRegion_RGB16_555 &  dst, const  TPixels32Ref &  src){
    UInt16 *  pDst = (UInt16 * )dst.pdata;
     const  Color32 *  pSrc = src.pdata;
     const   long  width = src.width;
    TErrorColor *  _HLineErr = new  TErrorColor[width + 2 ];
     for  ( long  x = 0 ;x < width + 2 ; ++ x){
        _HLineErr[x].dR = 0 ;
        _HLineErr[x].dG = 0 ;
        _HLineErr[x].dB = 0 ;
    }
    TErrorColor *  HLineErr =& _HLineErr[ 1 ];
     for  ( long  y = 0 ;y < src.height; ++ y){
        CvsPic32To16_ErrorDiffuse_Line_1(pDst,pSrc,width,HLineErr);
        (UInt8 *& )pDst += dst.byte_width;
        (UInt8 *& )pSrc += src.byte_width;
    }
    delete[]_HLineErr;
}


速度測試:
//////////////////////////////////////////////////////////////
//CvsPic32To16_ErrorDiffuse_1     283.77  FPS
//////////////////////////////////////////////////////////////
 
F:繼續優化
 getBestRGB16_555Color函數有條件分支,建立一個查找表來代替,完整的實現如下:


     static  UInt8 _BestRGB16_555Color_Table[ 256 * 5 ];
     const  UInt8 *  BestRGB16_555Color_Table =& _BestRGB16_555Color_Table[ 256 * 2 ];
     struct  _TAutoInit_BestRGB16_555Color_Table{
        _TAutoInit_BestRGB16_555Color_Table(){
             for  ( long  i = 0 ;i < 256 * 5 ; ++ i){
                _BestRGB16_555Color_Table[i] = getBestRGB16_555Color(i - 256 * 2 );
            }
        }
    };
     static  _TAutoInit_BestRGB16_555Color_Table _AutoInit_BestRGB16_555Color_Table;
  //實際代碼中建議預先生成_BestRGB16_555Color_Table的數據,從而避免初始化順序依賴的問題
     void  CvsPic32To16_ErrorDiffuse_Line_2(UInt16 *  pDst, const  Color32 *  pSrc, long  width,TErrorColor *  PHLineErr){
        TErrorColor HErr;
        HErr.dR = 0 ; HErr.dG = 0 ; HErr.dB = 0 ;
        PHLineErr[ - 1 ].dB = 0 ; PHLineErr[ - 1 ].dG = 0 ; PHLineErr[ - 1 ].dR = 0 ;
         for  ( long  x = 0 ;x < width; ++ x)
        {
             long  cB = (pSrc[x].b + HErr.dB*2  + PHLineErr[x].dB );
             long  cG = (pSrc[x].g + HErr.dG*2  + PHLineErr[x].dG );
             long  cR = (pSrc[x].r + HErr.dR*2  + PHLineErr[x].dR );
             long  rB = BestRGB16_555Color_Table[cB];
             long  rG = BestRGB16_555Color_Table[cG];
             long  rR = BestRGB16_555Color_Table[cR];
            pDst[x] =  rB | (rG << 5 ) | (rR << 10 );
   //做乘法比較慢的cpu體系下可以嘗試把getC8Color也做成一個數組表 
            HErr.dB = (cB - getC8Color(rB)) >> 2 ;
            HErr.dG = (cG - getC8Color(rG)) >> 2 ;
            HErr.dR = (cR - getC8Color(rR)) >> 2 ;
            PHLineErr[x - 1 ].dB += HErr.dB;
            PHLineErr[x - 1 ].dG += HErr.dG;
            PHLineErr[x - 1 ].dR += HErr.dR;
            PHLineErr[x] = HErr;
        }
    }
 
void  CvsPic32To16_ErrorDiffuse_2( const  TPicRegion_RGB16_555 &  dst, const  TPixels32Ref &  src){
    UInt16 *  pDst = (UInt16 * )dst.pdata;
     const  Color32 *  pSrc = src.pdata;
     const   long  width = src.width;
    TErrorColor *  _HLineErr = new  TErrorColor[width + 2 ];
     for  ( long  x = 0 ;x < width + 2 ; ++ x){
        _HLineErr[x].dR = 0 ;
        _HLineErr[x].dG = 0 ;
        _HLineErr[x].dB = 0 ;
    }
    TErrorColor *  HLineErr =& _HLineErr[ 1 ];
     for  ( long  y = 0 ;y < src.height; ++ y){
        CvsPic32To16_ErrorDiffuse_Line_2(pDst,pSrc,width,HLineErr);
        (UInt8 *& )pDst += dst.byte_width;
        (UInt8 *& )pSrc += src.byte_width;
    }
    delete[]_HLineErr;
}


速度測試:
//////////////////////////////////////////////////////////////
//CvsPic32To16_ErrorDiffuse_2     316.62  FPS
//////////////////////////////////////////////////////////////

函數效果:

 
 

(文章的 下篇 將討論更快的速度或者更好的效果)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章