登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

易拉罐的博客

心静自然凉

 
 
 

日志

 
 

转 图像二值化算法  

2010-07-30 11:59:21|  分类: 机器视觉 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

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

最简单的:

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、 处理的效果
转 图像二值化算法 - 易拉罐bb - 易拉罐的博客
 
  评论这张
 
阅读(1355)| 评论(0)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018