阈值化在图像分割和形态学操作,图像增强方面都有很多的用处,操作简单,速度快。
最一般的就是设个值大于某个值的时候把这个像素变为255,小于这个值就是0,但是在实际操作的时候这种方法有个问题就是:太主观了,你怎么知道那个阈值好,那个阈值坏,图片的信息丢掉丢失了多少。所以后来在使用阈值进行图像的分割的时候就提出
大律法阈值化,
大津法又称最大类间方差法。对图像,记t为前景与背景的分割阈值,前景点数占图像比例为w0,
平均灰度为u0;背景点数占图像比例为w1,平均灰度为u1。图像的总平均灰度为:u=w0*u0+w1*u1。从最小灰度值到最大灰度值遍历t,当t使
得值g=w0*(u0-u)2+w1*(u1-u)2
最大时t即为分割的最佳阈值。阈值t分割出的前景和背景两部分构成了整幅图像,而前景取值u0,概率为w0,背景取值u1,概率为w1,总均值为u,根据
方差的定义即得该式。因方差是灰度分布均匀性的一种度量,方差值越大,说明构成图像的两部分差别越大,当部分目标错分为背景或部分背景错分为目标都会导致
两部分差别变小,因此使类间方差最大的分割意味着错分概率最小。直接应用大津法计算量较大,因此我们在实现时采用了等价的公式g=w0*w1*(u0-
u1)2。不管怎么说,图片的信息变幻多端,到底该怎么处理,具体的时候有具体的方法。现在越来越觉得对于图片信息的分析能力,是很重要的,知道如何去分析,才知道如何让去使用程序来达到最好的效果。阈值化的代码:
/*************************************************************
阈值化处理函数
图片信息
图片数据
最大值
阈值处理的类型
IMG_THRESHOLD_BINARY 0 二值化,大于阈值设定为max_value,否则为0
IMG_THRESHOLD_BINARY_INV 1 二值化,小于阈值设定为max_value,否则为0
IMG_THRESHOLD_TOZERO 2 二值化,大于阈值设定为0,否则为原来的数据
IMG_THRESHOLD_TOZERO_INV 3 二值化,小于阈值设定为max_value,否则为原数据
IMG_THRESHOLD_TRUNCATE 4 二值化,大于阈值设定为threhold,否则为0
****************************************************************/
BOOL ImgThreshold(BITMAPINFO* pbmpinfo,BYTE* pbmpdata,UINT threhold,UINT max_value , int threshold_type)
{
LONG imagewidth=pbmpinfo->bmiHeader.biWidth;
LONG imageheigth=pbmpinfo->bmiHeader.biHeight;
LONG Linebyte =( pbmpinfo->bmiHeader.biBitCount * imagewidth + 31)/32*4;
LONG ImageSize=Linebyte * imageheigth;
LONG i=0,j=0,k=0,heigth=0,width=0;
//data is not null
if (pbmpdata == NULL)
{
return FALSE;
}
//color must be gray
if (pbmpinfo->bmiHeader.biBitCount != 8)
{
AfxMessageBox("只对灰度图像进行操作!");
return FALSE;
}
//分配空间
BYTE *pNewbmpdata=(BYTE*)malloc(ImageSize);
//copy data
if (pNewbmpdata == NULL)
{
return FALSE;
}
memcpy(pNewbmpdata,pbmpdata,ImageSize);
BYTE *psrc=NULL;
BYTE *pdest=NULL;
BYTE result=0;
//计算区域是:begin~image-begin-1 1~image-2
for (heigth = 0 ; heigth < imageheigth ;heigth++ )
{
for ( width = 0 ; width < imagewidth ; width++)
{
psrc = pbmpdata+(ImageSize-Linebyte-heigth*Linebyte)+width;
pdest = pNewbmpdata+(ImageSize-Linebyte-
heigth*Linebyte)+width;
switch (threshold_type)
{
//小于阈值设定为max_value,否则为0
case IMG_THRESHOLD_BINARY_INV:
if (*psrc >= threhold)
{
result = 0;
}
else
{
result = max_value;
}
break;
//大于阈值设定为原数据,否则为0
case IMG_THRESHOLD_TRUNCATE :
if (*psrc >= threhold)
{
result = threhold;
}
else
{
result = 0;
}
break;
//大于阈值设定为0,否则为原来的数据
case IMG_THRESHOLD_TOZERO :
if (*psrc >= threhold)
{
result =0;
}
else
{
result =*psrc;
}
break;
//小于阈值设定为0,否则为原来的数据
case IMG_THRESHOLD_TOZERO_INV :
if (*psrc >= threhold)
{
result =*psrc;
}
else
{
result = 0;
}
break;
//大于阈值设定为max_value,否则为0
default :
if (*psrc >= threhold)
{
result = max_value;
}
else
{
result =0 ;
}
break;
}
*pdest=(unsigned char)result;
}
}
memcpy(pbmpdata,pNewbmpdata,ImageSize);
free(pNewbmpdata);
return TRUE;
}
打律法阈值化的代码:
/*************************************************************
大律法发取阈值
图片信息
图片数据
直方图统计数据
是否是直方图统计数据
返回得到的阈值,如果失败返回-1
/////
原理:设定一个阈值,将图像分为2个部分,分别求出2个部分的灰度均值,
利用函数 W(I)= N(<)*N(>)*(V(<) - V(>))^2 中的最大值来决定阈值
************************l****************************************/
int ImgOtsu(BITMAPINFO* pbmpinfo,BYTE* pbmpdata)
{
long total_pixel =0;
long total_num =0;
long num_below = 0;
long pixel_below =0;
float percentage_below = 0;
float percentage_up = 0;
float avarage_below =0;
float avarage_up =0;
int i,j;
int threhold=0,threhold1=0,threhold2=0;
//直方图统计
long hist[256]={0};
//color must be gray
if (pbmpinfo->bmiHeader.biBitCount != 8)
{
AfxMessageBox("只对灰度图像进行操作!");
return -1;
}
ImgHist(pbmpinfo,pbmpdata,hist,NULL);
//统计总数
for (j=0;j < 256;j++)
{
total_num += hist[j];
total_pixel += hist[j]*j;
}
///////////////////
for (i=0 ; i<256; i++ )
{
num_below =0;
pixel_below =0;
percentage_below=0;
percentage_up =0;
avarage_up =0;
avarage_below =0;
/////////////////////
for (j=0;j < i+1; j++)
{
num_below += hist[j];
pixel_below += hist[j]*j;
}
///////////////
if (pixel_below)
{
percentage_below=(float)num_below /(float)total_num ;
avarage_below =(float)pixel_below /(float)num_below;
}
else
{
pixel_below =0;
}
if (total_pixel - pixel_below)
{
percentage_up=(float)( 1 - (float)num_below /(float)total_num ); //小于阈值的像素占总数的概率
avarage_up =(float)(total_pixel - pixel_below )/(float)(total_num - num_below); //小于阈值的部分的均值
}
else
{
avarage_up = 0;
}
/////////////
threhold1 =(int)( percentage_up * percentage_below * (avarage_up - avarage_below) *(avarage_up - avarage_below) );
if (threhold1 > threhold2)
{
threhold2 = threhold1;
threhold = i;
}
}
return threhold;
}
文章评论(0条评论)
登录后参与讨论