图像二值化算法 【迭代法和大律法算子】

二值化是一个相当复杂的理论问题,如果不给出具体的应用要求是无法做的.

最简单的:

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、  处理的效果
 

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=886749

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值