大津法由大津于1979年提出,对图像Image,记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。部分计算过程如下:

//遍历所有灰度值求Max g。

for intCurrentLevel:=0 to intArrLen do

begin

if intSclGrayLevel[intCurrentLevel]=0 then

continue

else

begin

//计算当阈值为intCurrentLevel时的g

intCount:=0;

intSumPels:=0;

for intLoop:=0 to intCurrentLevel do

begin

intCount:=intCount+intSclGrayLevel[intLoop];

intSumPels:=intSumPels+intSumPelsArr[intLoop];

end;

w0:=intCount/intSize;

u0:=intSumPels/intCount;

w1:=1-w0;

if intSize-intCount<>0 then

u1:=(intTotalPels-intSumPels)/(intSize-intCount)

else

u1:=0;

RlTempO:=w0*w1*(u0-u1)*(u0-u1);

if RlTempO>RlMaxO then

begin

RlMaxO:=RlTempO;

Result:=intCurrentLevel;

end;

end;

我们在测试中发现:大津法选取出来的阈值非常理想,对各种情况的表现都较为良好。虽然它在很多情况下都不是最佳的分割,但分割质量通常都有一定的保障,可以说是最稳定的分割。由上可知,大津算法是一种较为通用的分割算法。在它的思想的启迪下,人们进一步提出了多种类似的评估阈值的算法,具体可参加【5】、【6】等。

OTSU的算法,很好用,好不容易才找到的。
/*
OTSU 算法可以说是自适应计算单阈值(用来转换灰度图像为二值图像)的简单高效方法。下面的代码最早由 Ryan Dibble提供,此后经过多人Joerg.Schulenburg, R.Z.Liu 等修改,补正。

算法对输入的灰度图像的直方图进行分析,将直方图分成两个部分,使得两部分之间的距离最大。划分点就是求得的阈值。

parameter: *image --- buffer for image
rows, cols --- size of image
x0, y0, dx, dy --- region of vector used for computing threshold
vvv --- debug option, is 0, no debug information outputed
*/
/*======================================================================*/
/* OTSU global thresholding routine */
/* takes a 2D unsigned char array pointer, number of rows, and */
/* number of cols in the array. returns the value of the threshold */
/*======================================================================*/
int otsu (unsigned char *image, int rows, int cols, int x0, int y0, int dx, int dy, int vvv)
{

unsigned char *np; // 图像指针
int thresholdValue=1; // 阈值
int ihist[256]; // 图像直方图,256个点

int i, j, k; // various counters
int n, n1, n2, gmin, gmax;
double m1, m2, sum, csum, fmax, sb;

// 对直方图置零...
memset(ihist, 0, sizeof(ihist));

gmin=255; gmax=0;
// 生成直方图
for (i = y0 + 1; i < y0 + dy - 1; i++) {
np = ℑ[i*cols+x0+1];
for (j = x0 + 1; j < x0 + dx - 1; j++) {
ihist[*np]++;
if(*np > gmax) gmax=*np;
if(*np < gmin) gmin=*np;
np++; /* next pixel */
}
}

// set up everything
sum = csum = 0.0;
n = 0;

for (k = 0; k <= 255; k++) {
sum += (double) k * (double) ihist[k]; /* x*f(x) 质量矩*/
n += ihist[k]; /* f(x) 质量 */
}

if (!n) {
// if n has no value, there is problems...
fprintf (stderr, "NOT NORMAL thresholdValue = 160/n");
return (160);
}

// do the otsu global thresholding method
fmax = -1.0;
n1 = 0;
for (k = 0; k < 255; k++) {
n1 += ihist[k];
if (!n1) { continue; }
n2 = n - n1;
if (n2 == 0) { break; }
csum += (double) k *ihist[k];
m1 = csum / n1;
m2 = (sum - csum) / n2;
sb = (double) n1 *(double) n2 *(m1 - m2) * (m1 - m2);
/* bbg: note: can be optimized. */
if (sb > fmax) {
fmax = sb;
thresholdValue = k;
}
}

// at this point we have our thresholding value

// debug code to display thresholding values
if ( vvv & 1 )
fprintf(stderr,"# OTSU: thresholdValue = %d gmin=%d gmax=%d/n",
thresholdValue, gmin, gmax);

return(thresholdValue);
}

///
Otsu算法(大律法或最大类间方差法)
一、Otsu最大类间方差法原理
利用阈值将原图像分成前景,背景两个图象。
前景:用n1,csum,m1来表示在当前阈值下的前景的点数,质量矩,平均灰度
后景:用n2,sum-csum,m2来表示在当前阈值下的背景的点数,质量矩,平均灰度
当取最佳阈值时,背景应该与前景差别最大,关键在于如何选择衡量差别的标准,而在otsu算法中这个衡量差别的标准就是最大类间
方差(英文简称otsu,这也就是这个算法名字的来源),在本程序中类间方差用sb表示,最大类间方差用fmax
关于最大类间方差法(otsu)的性能:
类间方差法对噪音和目标大小十分敏感,它仅对类间方差为单峰的图像产生较好的分割效果。
当目标与背景的大小比例悬殊时,类间方差准则函数可能呈现双峰或多峰,此时效果不好,但是类间方差法是用时最少的。
最大类间方差法(otsu)的公式推导:
记t为前景与背景的分割阈值,前景点数占图像比例为w0,平均灰度为u0;背景点数占图像比例为w1,平均灰度为u1。
则图像的总平均灰度为:u=w0*u0+w1*u1。
前景和背景图象的方差:g=w0*(u0-u)*(u0-u)+w1*(u1-u)*(u1-u)=w0*w1*(u0-u1)*(u0-u1),此公式为方差公式。
可参照概率论课本上面的g的公式也就是下面程序中的sb的表达式。当方差g最大时,可以认为此时前景和背景差异最大,此时的灰
度t是最佳阈值sb= w1*w2*(u1-u0)*(u0-u1)
算法实现1:
unsafepublicintGetThreshValue(Bitmapimage)
{
BitmapDatabd=image.LockBits(new Rectangle(0,0,image.Width, image.Height), ImageLockMode.WriteOnly, image.PixelFormat);
byte*pt=(byte*)bd.Scan0;
int[] pixelNum=newint[256]; //图象直方图,共256个点
bytecolor;
byte*pline;
int n,n1,n2;
int total; //total 为总和,累计值
doublem1,m2,sum,csum,fmax, sb; //sb 为类间方差,fmax存储最大方差值
int k,t, q;
int threshValue =1; // 阈值
int step=1;
switch(image.PixelFormat)
{
casePixelFormat.Format24bppRgb:
step=3;
break;
casePixelFormat.Format32bppArgb:
step=4;
break;
casePixelFormat.Format8bppIndexed:
step=1;
break;
}
//生成直方图
for(inti =0;i
{
pline=pt+i *bd.Stride;
for(intj =0;j
{
color=*(pline+j *step); //返回各个点的颜色,以RGB表示
pixelNum[color]++; //相应的直方图加1
}
}
//直方图平滑化
for(k =0;k<=255;k++)
{
total =0;
for(t =-2;t <=2;t++) //与附近2个灰度做平滑化,t值应取较小的值
{
q=k+t;
if (q<0) //越界处理
q=0;
if (q>255)
q=255;
total =total +pixelNum[q]; //total 为总和,累计值
}
//平滑化,左边2个+中间1个+右边2个灰度,共5个,所以总和除以5,后面加0.5是用修正值
pixelNum[k]=(int)((float)total/ 5.0+0.5);
}
//求阈值
sum=csum=0.0;
n=0;
//计算总的图象的点数和质量矩,为后面的计算做准备
for(k =0;k<=255;k++)
{
//x*f(x)质量矩,也就是每个灰度的值乘以其点数(归一化后为概率),sum为其总和
sum+=(double)k *(double)pixelNum[k];
n+=pixelNum[k]; //n 为图象总的点数,归一化后就是累积概率
}
fmax=-1.0; //类间方差sb不可能为负,所以fmax初始值为-1不影响计算的进行
n1=0;
for(k =0;k<255;k++) //对每个灰度(从0到255)计算一次分割后的类间方差sb
{
n1+=pixelNum[k]; //n1 为在当前阈值遍前景图象的点数
if (n1==0){continue;} //没有分出前景后景
n2=n-n1; //n2 为背景图象的点数
//n2 为0表示全部都是后景图象,与n1=0情况类似,之后的遍历不可能使前景点数增加,所以此时可以退出循环
if (n2==0){break;}
csum+=(double)k*pixelNum[k]; //前景的“灰度的值*其点数”的总和
m1=csum/ n1; //m1 为前景的平均灰度
m2=(sum -csum)/ n2; //m2 为背景的平均灰度
sb=(double)n1*(double)n2*(m1-m2)*(m1- m2); //sb为类间方差
if (sb>fmax) //如果算出的类间方差大于前一次算出的类间方差
{
fmax=sb; //fmax 始终为最大类间方差(otsu)
threshValue =k; //取最大类间方差时对应的灰度的k就是最佳阈值
}
}
image.UnlockBits(bd);
image.Dispose();
returnthreshValue;
}
算法实现2:
Otsu算法步骤如下:
设图象包含L个灰度级(0,1…,L-1),灰度值为i的的象素点数为Ni,图象总的象素点数为
N=N0+N1+...+N(L-1)。灰度值为i的点的概率为:P(i)= N(i)/N.
门限t将整幅图象分为暗区c1和亮区c2两类,则类间方差σ是t的函数:σ=a1*a2(u1-u2)^2(2)
式中,aj为类cj的面积与图象总面积之比,a1=sum(P(i))i->t,a2= 1-a1;
uj为类cj的均值,u1= sum(i*P(i))/a10->t,u2= sum(i*P(i))/a2,t+1->L-1,该法选择最佳门限t^
使类间方差最大,即:令Δu=u1-u2,σb = max{a1(t)*a2(t)Δu^2}
代码实现:
int otsu(IplImage*image,int rows,int cols,int x0,int y0,int dx,int dy,int vvv)
{
unsignedchar*np;// 图像指针
int thresholdValue=1;// 阈值
int ihist[256]; // 图像直方图,256个点
int i, j,k;// variouscounters
int n,n1,n2,gmin,gmax;
doublem1,m2,sum,csum,fmax,sb;
// 对直方图置零
memset(ihist,0,sizeof(ihist));
gmin=255;gmax=0;
// 生成直方图

for(j=y0;j
{
for(i=0;i
{
unsignedchartemp=CV_IMAGE_ELEM(image,uchar,j,i);
ihist[temp]++;
}
}
//setupeverything
sum=csum=0.0;
n=0;
for(k=0;k<=255;k++)
{
sum+=(double)k*(double)ihist[k]; //x*f(x)质量矩
n+=ihist[k]; //f(x) 质量
}
if (!n)
{
//if nhasnovalue,thereis problems
fprintf(stderr,"NOTNORMALthresholdValue=160\n");
return(160);
}
//dotheotsuglobalthresholdingmethod
fmax=-1.0;
n1=0;
for(k=0;k<255;k++)
{
n1+=ihist[k];
if (!n1){continue;}
n2=n-n1;
if (n2==0){break;}
csum+=(double)k*ihist[k];
m1=csum/n1;
m2=(sum-csum)/n2;
sb=(double)n1*(double)n2*(m1-m2)*(m1-m2);

if (sb>fmax){
fmax=sb;
thresholdValue=k;
}
}
//atthis pointwehaveourthresholdingvalue,debugcodetodisplaythresholdingvalues
if (vvv&1)
fprintf(stderr,"#OTSU:thresholdValue=%dgmin=%dgmax=%d\n",thresholdValue,gmin,gmax);
return(thresholdValue);
}

简称OTSU。它是按图像的灰度特性,将图像分成背景和目标2部分。背景和目标之间的类间方差
越大,说明构成图像的2部分的差别越大,当部分目标错分为背景或部分背景错分为目标都会导致2部
分差别变小。因此,使类间方差最大的分割意味着错分概率最小。
对于图像I(x,y),前景(即目标)和背景的分割阈值记作T,属于前景的像素点数占整幅图像的比
例记为ω0,其平均灰度μ0;背景像素点数占整幅图像的比例为ω1,其平均灰度为μ1。图像的总平均
灰度记为μ,类间方差记为g。
假设图像的背景较暗,并且图像的大小为M×N,
图像中像素的灰度值小于阈值T的像素个数记作N0,像素灰度大于阈值T的像素个数记作N1,则有:
      ω0=N0/M×N

              (1)
      ω1=N1/M×N                (2)
      N0+N1=M×N              (3)
      ω0+ω1=1                    (4)
      μ=ω0*μ0+ω1*μ1      (5)
      g=ω0(μ0-μ)^2+ω1(μ1-μ)^2        (6)
将式(5)代入式(6),得到等价公式:
g=ω0ω1(μ0-μ1)^2        (7)
采用遍历的方法得到使类间方差最大的阈值
T,即为所求。
int    Otsu(long *pg,long*pg1)                                          //    大津法取阈值
{
      int    i,j,p;
      doubleA,B,An,Bn,u,v,qqq[256],max,min;
      An=Bn=0;
      for(i=0;i<256;i++)
      {
            An+=pg;          Bn+=pg*(i+1);
      }
      for(j=0;j<256;j++)
      {
            A=B=0;
            for(i=0;i<=j;i++)
      {
            A+=pg; 
      B+=pg*(i+1);
            }
            if(A) u=B/A;
            else      u=0;
            if(An-A) v=(Bn-B)/(An-A);
            else            v=0;
            qqq[j]=A*(An-A)*(u-v)*(u-v);                                //    计算类间方差
      }
      max=min=qqq[0];    p=0;
      for(i=1;i<256;i++)
      {                                        //    寻找判别函数最大值
            if(qqq>max)
      {
            max=qqq;
            p=i;
            }
      elseif (qqq<min) min=qqq;
      }
      if(pg1!=0)
      {
          for(i=0;i<256;i++)
    {
              pg1=(long)(120*(qqq-min)/(max-min));
    }
      }
      return(p);                                      //    取判别函数最大值的灰度为其阈值
}
其实说白了无论是摄像头还是先行CCD,图像处理应该按照如下步骤处理:
1.计算动态阈值(暂时接触到的就是上面介绍的大津法)。
2.二值化处理,区分黑点白点(这个没有什么好说的,循环遍历即可)
3.消除黑点白点噪声(暂时接触的腐蚀膨胀算法,说白了就是如何两个白点中间有个黑点,或者两个黑点中间有个白点那就认为中间的那个点是噪声,进行算法矫正)。
4.提取黑线,计算黑线的中心位置(若是双线,就取两边黑线求出中间位置)

大律法(OTSU法)相关推荐

  1. 大律法(OTSU) ——图像数据二值化

    二值化的目的,是确定一个像素值,以像素为分界,将图像划分为前景和背景,前景的像素值取相同值,背景的像素也取相同值,从而将前景和背景的差异,在图像中最大化,或者说可以突出前景或者背景信息. 二值化可以有 ...

  2. 大津阈值法(OTSU)功能实现

    具体的公式推导参见冈萨雷斯 <数字图像处理> Otsu方法又称最大类间方差法,通过把像素分配为两类或多类,计算类间方差,当方差达到最大值时,类分割线(即灰度值)就作为图像分割阈值.Otsu ...

  3. 具有掩膜功能的大津阈值法(Otsu)

    学习记录- 前文说到大津阈值法是一种自适应的基于全局的阈值分割算法,只有在图像直方图分布为双峰的情况下才会呈现出一种比较好的分割效果,但是待分割图像直方图分布并不是每次都是理想的结果.可能会是光照的影 ...

  4. 一维OTSU法、最小交叉熵法、二维OTSU法及C++源码

    1.最大类间方差法(Otsu法) 该算法是日本人Otsu提出的一种动态阈值分割算法.它的主要思想是按照灰度特性将图像划分为背景和目标2部分,划分依据为选取门限值,使得背景和目标之间的方差最大.(背景和 ...

  5. 费曼学习法与孔子温故知新学习法为两大重要学习法,前者外向表现,后者内省提升

    费曼学习法与孔子温故知新学习法为两大重要学习法,前者外向表现,后者内省提升 附前者链接 https://blog.csdn.net/wo541075754/article/details/101554 ...

  6. div搜索框与按钮不在一行_前阿里巴巴运营专家:搜索框的5大运营玩法

    *全文图片来自网络,基于 CC0 协议  作者 |磊叔,前阿里巴巴运营专家"古语有云:搜索做得好,用户跑不了.搜索框是重要的营销增长场景.在互联网产品上,方寸之间的位置之争是各个功能的生存之 ...

  7. 算法图解学习笔记01:二分查找大O表示法

    二分查找 二分查找又称折半查找,其输入的必须是有序的元素列表.二分查找的基本思想是将n个元素分成大致相等的两部分,取a[n/2]与x做比较,如果x=a[n/2],则找到x,算法中止:如果x<a[ ...

  8. a*算法的时间复杂度_算法的时间复杂度:大O表示法

    本文讨论一下算法的时间复杂度问题,用到的素材取自<算法图解>一书,强烈推荐, 如有不妥,请联系我! 二分查找 随便想一个1-100的数字. 你的目标是以最少的次数猜到这个数字.你每次猜测后 ...

  9. 算法概念:大O表示法/小o表示法/Ω/Θ

    如果算法A需要的时间与f(n)成正比,则算法A称为f(n)阶,表示为O(f(n)).函数f(n)称为算法的增率函数(growth-rate function).该表示法使用大写字母O来表示(order ...

最新文章

  1. npm导入bootstrap_vue cli3.0如何通过npm引入jquery和bootstrap?
  2. uniapp中slot插槽用法
  3. Log4Net使用详解(续)
  4. 雨棚板弹性法计算简图_造价工程师:钢结构工程量计算注意事项
  5. 第四章:通过:driver.getAttribute(value); 获取value的值
  6. 图片怎么压缩图片大小_图片的体积怎么压缩?这三种方法你会吗?
  7. beta冲刺总结那周余嘉熊掌将得队
  8. 用dw(dreamweaver)开发asp.net,连接数据库时出现“http错误500,服务器内部错误”的解决方法...
  9. 7-293 鸡兔同笼 (10 分)
  10. The 46th ICPC Asia Jinan Regional Contest,2021,46届济南站热身赛
  11. SOAPUI接口测试http协议详细测试过程
  12. JS 中样式显示(clientWidth和clientHeight、offsetLeft、scrollHeight )
  13. Java 拾遗补阙 ----- 继承父类的成员变量与方法区别
  14. h5截长图(html2canvas保存图片)
  15. C++11新特性内存模型总结详解--一篇秒懂
  16. android跑马灯效果不起作用,Android实现跑马灯效果的方法
  17. elasticsearch实现类似京东的商品搜索效果(elasticsearch动态聚合)
  18. Python基本语法,让我们轻松入门学习Python!
  19. 谷歌浏览器怎么调试js
  20. PMP超详细的报名流程,手把手教你报名(含备考资源)

热门文章

  1. 阿里云数据湖分析急招实习生
  2. EI收录的中国(中文)期刊(2022版)
  3. Linux: meld软件使用
  4. 多项式定理 matlab,泊松定理卡方分布及多项式拟合的MATLAB实现.pdf
  5. 游戏服务器开发技术小结
  6. 微服务架构通讯模式架构分析
  7. @Reference是干啥的
  8. Pr混剪视频制作教程[纯萌新]
  9. kafka-eagle-2.0.1安装及使用(超详细)
  10. 聊聊你不知道的Java变量转型