圖像二值化算法 【轉】

二值化是一個相當複雜的理論問題,如果不給出具體的應用要求是無法做的.

最簡單的:

for(......)

if(PixelY[i,j]>T)

PixelY[i,j] = 255;

else

PixelY[i,j] = 0;

如果考慮具體問題,二值化算法不下100種.

/***************************************************************************   
      *     函數名稱   
      *     OSTUThreshold()   
      *     參數   
      *           LPSTR     lpDIBBits             -     指向源DIB圖像指針   
      *           LONG       lWidth                   -     源圖像寬度(像素數)   
      *           LONG       lHeight                 -     源圖像高度(像素數)   
      *     返回值   
      *           BOOL                                   -     運算成功     返回TRUE     ,     否則     返回FALSE。   
      *     說明   
      *           該函數採用大津法進行閾值分割     二值化   
      ***************************************************************************/   
    BOOL     WINAPI     OSTUThreshold(LPSTR     lpDIBBits,     LONG     lWidth,     LONG     lHeight)   
    {   
    //     指向源圖像像素指針   
    LPSTR     lpSrc;   
    
    //     指向緩存圖像指針   
    LPSTR     lpDst;   
    
    //     指向緩存圖像像素指針   
    LPSTR     lpNewDIBBits;   
    HLOCAL     hNewDIBBits;   
    
    //     循環變量   
    int     i,     j,     t;   
    
    //     用於計算兩個區域的中間變量   
    long     lP1,     lS1,     lP2,     lS2;   
    
    //     像素值   
    unsigned     char     pixel;   
    
    //     灰度直方圖數組   
    long     lHistogram[256];   
    
    //     閾值,     最大灰度值和最小灰度值,     兩個區域的平均灰度值   
    unsigned     char     iThreshold,     iNewThreshold,     iMaxGrayValue,     iMinGrayValue,     iMean1GrayValue,     iMean2GrayValue;   
    
    //       前景點數佔圖像比例,     背景點數佔圖像比例   
    double     w0,w1;   
    
    //     方差   
    double     G,     tempG;   
    
    //     圖像每行佔字節數   
    LONG     lLineBytes;   
    
    //     暫時分配內存,     以保存新圖像   
    hNewDIBBits     =     LocalAlloc(LHND,     lWidth     *     lHeight);   
    
    if     (hNewDIBBits     ==     NULL)     
    {   
    //分配內存失敗   
    return     FALSE;   
    }   
    
    //     鎖定內存   
    lpNewDIBBits     =     (char     *)     LocalLock(hNewDIBBits);   
    
    //     初始化新分配的內存,     設定初始值爲255   
    lpDst     =     (char     *)     lpNewDIBBits;   
    memset(lpDst,     (BYTE)255,     lWidth     *     lHeight);   
    
    lLineBytes     =     WIDTHBYTES(lWidth     *     8);   
    
    for(i=     0;     i     <     256;     i++)   
    {   
    lHistogram[i]     =     0;   
    }   
    
    //     獲得灰度直方圖,灰度最大值和灰度最小值   
    iMaxGrayValue     =     0;   
    iMinGrayValue     =     255;   
    for(i     =     0;     i     <     lWidth;     i++)   
    {   
    for(j     =     0;     j     <     lHeight;     j++)   
    {   
    lpSrc     =     (char     *)     lpDIBBits     +     lLineBytes     *     j     +     i;   
    pixel     =     (unsigned     char)     *lpSrc;   
    lHistogram[pixel]++;   
    
    //     修改最大灰度值和最小灰度值   
    if     (iMinGrayValue     >     pixel)   
    {   
    iMinGrayValue     =     pixel;   
    }   
    if     (iMaxGrayValue     <     pixel)   
    {   
    iMaxGrayValue     =     pixel;   
    }   
    }   
    }   
    
    //     遍歷t,     選取最佳閾值   
    for(t     =     iMinGrayValue;     t     <     iMaxGrayValue     ;     t++)   
    {   
    iNewThreshold     =     t;   
    lP1     =     0;   
    lS1     =     0;   
    lP2     =     0;   
    lS2     =     0;   
    
    //       求前景,背景兩個區域的平均灰度值,     點數所佔比例   
    for(i     =     iMinGrayValue;     i     <=     iNewThreshold;     i++)   
    {   
    lP1     +=     lHistogram[i]     *     i;   
    lS1     +=     lHistogram[i];   
    }   
    iMean1GrayValue     =     (unsigned     char)     (lP1/lS1);   
    w0     =     (double)     (lS1)     /     (lWidth     *     lHeight);   
    for(i     =     iNewThreshold     +     1;     i     <=     iMaxGrayValue;     i++)   
    {   
    lP2     +=     lHistogram[i]     *     i;   
    lS2     +=     lHistogram[i];   
    }   
    iMean2GrayValue     =     (unsigned     char)     (lP2/lS2);   
                    w1     =     1     -     w0;   
    
    //     計算類間方差   
    G     =     (double)     w0     *     w1     
        *     (iMean1GrayValue     -     iMean2GrayValue)     *     (iMean1GrayValue     -     iMean2GrayValue);   
    if     (G     >     tempG)     
    {   
    tempG     =     G;   
    iThreshold     =     iNewThreshold;   
    }   
    }   
    
    //     根據閾值將圖像二值化   
            for(i     =     0;     i     <     lWidth;     i++)   
    {   
    for(j     =     0;     j     <     lHeight;     j++)   
    {   
    lpSrc     =     (char     *)     lpDIBBits     +     lLineBytes     *     j     +     i;   
    lpDst     =     (char     *)     lpNewDIBBits     +     lLineBytes     *     j     +     i;   
    pixel     =     (unsigned     char)     *lpSrc;   
    if     (pixel     <=     iThreshold)     
    {   
    *lpDst     =     (unsigned     char)0;   
    }   
    else   
    {   
    *lpDst     =     (unsigned     char)     255;   
    }   
    }   
    }   
    
            //     複製圖像   
    memcpy(lpDIBBits,     lpNewDIBBits,     lWidth     *     lHeight);   
    
    //     釋放內存   
    LocalUnlock(hNewDIBBits);   
    LocalFree(hNewDIBBits);   
    
    //     返回   
    return     TRUE;   
    }

/*************************************************************************
*
* 函數名稱:
*     ThresholdDIB()
*
* 參數:
*     LPSTR lpDIBBits      - 指向源DIB圖像指針
*     LONG    lWidth         - 源圖像寬度(象素數)
*     LONG    lHeight        - 源圖像高度(象素數)
*
* 返回值:
*     BOOL                 - 運算成功返回TRUE,否則返回FALSE。
*
* 說明:
* 該函數用 迭代法 對圖像進行閾值分割運算。
*
************************************************************************/

BOOL WINAPI ThresholdDIB(LPSTR lpDIBBits,LONG lWidth, LONG lHeight)
{

// 指向源圖像的指針
LPSTR lpSrc;

// 指向緩存圖像的指針
LPSTR lpDst;

// 指向緩存DIB圖像的指針
LPSTR lpNewDIBBits;
HLOCAL hNewDIBBits;

//循環變量
long i;
long j;

//像素值
unsigned char pixel;

//直方圖數組
long lHistogram[256];

//閾值,最大灰度值與最小灰度值,兩個區域的平均灰度值
unsigned char iThreshold,iNewThreshold,iMaxGrayValue,iMinGrayValue,iMean1GrayValue,iMean2GrayValue;

//用於計算區域灰度平均值的中間變量
long lP1,lP2,lS1,lS2;

//迭代次數
int iIterationTimes;

// 圖像每行的字節數
LONG lLineBytes;

// 暫時分配內存,以保存新圖像
hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

if (hNewDIBBits == NULL)
{
    // 分配內存失敗
    return FALSE;
}

// 鎖定內存
lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

// 初始化新分配的內存,設定初始值爲255
lpDst = (char *)lpNewDIBBits;
memset(lpDst, (BYTE)255, lWidth * lHeight);

// 計算圖像每行的字節數
lLineBytes = WIDTHBYTES(lWidth * 8);

for (i = 0; i < 256;i++)
{
    lHistogram[i]=0;
}

//獲得直方圖
iMaxGrayValue = 0;
iMinGrayValue = 255;
for (i = 0;i < lWidth ;i++)
{
    for(j = 0;j < lHeight ;j++)
    {
     // 指向源圖像倒數第j行,第i個象素的指針   
     lpSrc = (char *)lpDIBBits + lLineBytes * j + i;

     pixel = (unsigned char)*lpSrc;
   
     lHistogram[pixel]++;
     //修改最大,最小灰度值
     if(iMinGrayValue > pixel)
     {
      iMinGrayValue = pixel;
     }
     if(iMaxGrayValue < pixel)
     {
      iMaxGrayValue = pixel;
     }
    }
}

//迭代求最佳閾值
iNewThreshold = (iMinGrayValue + iMaxGrayValue)/2;
iThreshold = 0;

for(iIterationTimes = 0; iThreshold != iNewThreshold && iIterationTimes < 100;iIterationTimes ++)
{
    iThreshold = iNewThreshold;
    lP1 =0;
    lP2 =0;
    lS1 = 0;
    lS2 = 0;
    //求兩個區域的灰度平均值
    for (i = iMinGrayValue;i < iThreshold;i++)
    {
     lP1 += lHistogram[i]*i;
     lS1 += lHistogram[i];
    }
    iMean1GrayValue = (unsigned char)(lP1 / lS1);
    for (i = iThreshold+1;i < iMaxGrayValue;i++)
    {
     lP2 += lHistogram[i]*i;
     lS2 += lHistogram[i];
    }
    iMean2GrayValue = (unsigned char)(lP2 / lS2);
    iNewThreshold =    (iMean1GrayValue + iMean2GrayValue)/2;
}

//根據閾值將圖像二值化
for (i = 0;i < lWidth ;i++)
{
    for(j = 0;j < lHeight ;j++)
    {
     // 指向源圖像倒數第j行,第i個象素的指針   
     lpSrc = (char *)lpDIBBits + lLineBytes * j + i;

     // 指向目標圖像倒數第j行,第i個象素的指針   
     lpDst = (char *)lpNewDIBBits + lLineBytes * j + i;

     pixel = (unsigned char)*lpSrc;
   
     if(pixel <= iThreshold)
     {
      *lpDst = (unsigned char)0;
     }
     else
     {
      *lpDst = (unsigned char)255;
     }
    }
}

// 複製圖像
memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

// 釋放內存
LocalUnlock(hNewDIBBits);
LocalFree(hNewDIBBits);

// 返回
return TRUE;
}

///////////////////////////////////////////////////////////////

 

1、 圖像的二值化的基本原理
圖像的二值化處理就是講圖像上的點的灰度置爲0或255,也就是講整個圖像呈現出明顯的黑白效果。即將256個亮度等級的灰度圖像通過適當的閥值選取而獲得仍然可以反映圖像整體和局部特徵的二值化圖像。在數字圖像處理中,二值圖像佔有非常重要的地位,特別是在實用的圖像處理中,以二值圖像處理實現而構成的系統是很多的,要進行二值圖像的處理與分析,首先要把灰度圖像二值化,得到二值化圖像,這樣子有利於再對圖像做進一步處理時,圖像的集合性質只與像素值爲0或255的點的位置有關,不再涉及像素的多級值,使處理變得簡單,而且數據的處理和壓縮量小。爲了得到理想的二值圖像,一般採用封閉、連通的邊界定義不交疊的區域。所有灰度大於或等於閥值的像素被判定爲屬於特定物體,其灰度值爲255表示,否則這些像素點被排除在物體區域以外,灰度值爲0,表示背景或者例外的物體區域。如果某特定物體在內部有均勻一致的灰度值,並且其處在一個具有其他等級灰度值的均勻背景下,使用閥值法就可以得到比較的分割效果。如果物體同背景的差別表現不在灰度值上(比如紋理不同),可以將這個差別特徵轉換爲灰度的差別,然後利用閥值選取技術來分割該圖像。動態調節閥值實現圖像的二值化可動態觀察其分割圖像的具體結果。
2、 圖像的二值化的程序實現
通過Delphi刻度控件調整閥值,實現動態控制,程序如下:
procedure TForm1.Button1Click(Sender: TObject);
var
          p:PByteArray;
          Gray,x,y:integer;
begin
          TestBMP:=TBitmap.Create; changedbmp:=tbitmap.Create;
          testbmp.Assign(image1.Picture);
          for y:=0 to testbmp.Height-1 do
          begin
                  p:=testbmp.ScanLine[y];
                  for x:=0 to testbmp.Width-1 do
                  begin
                                           //首先將圖像灰度化
                          gray:=round(p[x*3+2]*0.3+p[x*3+1]*0.59+p[x*3]*0.11);
                          if gray> TrackBar1.Position then //按閥值進行二值化
                          begin
                                  p[x*3]:=255; p[x*3+1]:=255; p[x*3+2]:=255;
                          end
                          else
                          begin
                                  p[x*3]:=0;p[x*3+1]:=0;p[x*3+2]:=0;
                          end;
                  end;
          end;
          ChangedBmp.Assign(TestBMP);
          PaintBox1.Canvas.CopyMode:=srccopy;
          PaintBox1.Canvas.Draw(0,0,ChangedBmp);
end;
3、 處理的效果
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章