最大类间方差法(otsu)的原理
OpenCV-Python系列之OTSU算法

OpenCV-Python系列之OTSU算法上⼀个教程中,我们谈到了关于图像⼆值化的两种⽅法,⼀种是固定阈值法,另⼀种是⾃适应阈值法,总的来说,⾃适应阈值法在某些⽅⾯要由于固定阈值法,但还没完,这次我们将隆重介绍我们的重量级选⼿,也就是OTSU算法(⼜称为⼤津算法和最⼤类间⽅差法)。
最⼤类间⽅差法是1979年由⽇本学者⼤津提出的,是⼀种⾃适应阈值确定的⽅法,⼜叫⼤津法,简称OTSU,是⼀种基于全局的⼆值化算法,它是根据图像的灰度特性,将图像分为前景和背景两个部分。
当取最佳阈值时,两部分之间的差别应该是最⼤的,在OTSU算法中所采⽤的衡量差别的标准就是较为常见的最⼤类间⽅差。
前景和背景之间的类间⽅差如果越⼤,就说明构成图像的两个部分之间的差别越⼤,当部分⽬标被错分为背景或部分背景被错分为⽬标,都会导致两部分差别变⼩,当所取阈值的分割使类间⽅差最⼤时就意味着错分概率最⼩。
OSTU原理在⼤津算法中,我们穷举搜索能使类内⽅差最⼩的阈值,定义为两个类的⽅差的加权和:权重是被阈值 t分开的两个类的概率,⽽是这两个类的⽅差⼤津证明了最⼩化类内⽅差和最⼤化类间⽅差是相同的:⽤类概率和类均值来表⽰。
类概率⽤阈值为t 的直⽅图计算:⽽类均值为:类概率和类均值可以迭代计算,⼤津算法得出了0:1范围上的⼀个阈值。
这个阈值⽤于图像中出现的像素强度的动态范围。
例如,若图像只包含155到255之间的像素强度,⼤津阈值0.75会映射到灰度阈值230(⽽不是192,因为图像包含的像素不是0–255全范围的)。
对于图像I(x,y),前景(即⽬标)和背景的分割阈值记作T,属于前景的像素点数占整幅图像的⽐例记为ω0,其平均灰度µ0;背景像素点数占整幅图像的⽐例为ω1,其平均灰度为µ1。
图像的总平均灰度记为µ,类间⽅差记为g。
假设图像的背景较暗,并且图像的⼤⼩为M×N,图像中像素的灰度值⼩于阈值T的像素个数记作N0,像素灰度⼤于阈值T的像素个数记作N1,则有: (1) ω0=N0/ (M×N) (2) ω1=N1/ (M×N) (3) N0 + N1 = M×N (4) ω0 + ω1 = 1 (5) µ = ω0 * µ0 + ω1 * µ1 (6) g = ω0 * (µ0 - µ)2 + ω1 * (µ1 - µ)2将式(5)代⼊式(6),得到等价公式: (7) g = ω0 *ω1 * (µ0 - µ1)2采⽤遍历的⽅法得到使类间⽅差g最⼤的阈值T。
Otsu算法(大律法或最大类间方差法)

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:unsafe public int GetThreshValue(Bitmap image){BitmapData bd = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.WriteOnly, image.PixelFormat);byte* pt = (byte*)bd.Scan0;int[] pixelNum = new int[256]; //图象直方图,共256个点byte color;byte* pline;int n, n1, n2;int total; //total为总和,累计值double m1, m2, sum, csum, fmax, sb; //sb为类间方差,fmax存储最大方差值int k, t, q;int threshValue = 1; // 阈值int step = 1;switch (image.PixelFormat){case PixelFormat.Format24bppRgb:step = 3;break;case PixelFormat.Format32bppArgb:step = 4;break;case PixelFormat.Format8bppIndexed:step = 1;break;}//生成直方图for (int i = 0; i < image.Height; i++){pline = pt + i * bd.Stride;for (int j = 0; j < image.Width; 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();return threshValue;}算法实现2:Otsu算法步骤如下:设图象包含L个灰度级(0,1…,L-1),灰度值为i的的象素点数为Ni ,图象总的象素点数为N=N0+N1+...+N(L-1)。
大津法原理(otsu)

最大类间方差法(大津法,OTSU)最大类间方差法是由日本学者大津(Nobuyuki Otsu)于1979年提出的,是一种自适应的阈值确定的方法,又叫大津法,简称OTSU 。
它是按图像的灰度特性,将图像分成背景和目标2部分。
背景和目标之间的类间方差越大,说明构成图像的2部分的差别越大,当部分目标错分为背景或部分背景错分为目标都会导致2部分差别变小。
因此,使类间方差最大的分割意味着错分概率最小。
对于图像I(x,y),前景(即目标)和背景的分割阈值记作T ,属于前景的像素点数占整幅图像的比例记为1ω,其平均灰度1μ;背景像素点数占整幅图像的比例为2ω,其平均灰度为2μ。
图像的总平均灰度记为μ,类间方差记为g 。
假设图像的背景较暗,并且图像的大小为M N ⨯,图像中像素的灰度值小于阈值T 的像素个数记作1N ,像素灰度大于阈值T 的像素个数记作2N ,则有:11N M N ω=⨯ (1.1)22N M N ω=⨯ (1.2)12N N M N +=⨯ (1.3)121ωω+= (1.4)1122μμωμω=⨯+⨯ (1.5) 221122()()g ωμμωμμ=⨯-+⨯-(1.6) 将式(1.5)代入式(1.6),得到等价公式:21212()g ωωμμ=⨯⨯- (1.7) 采用遍历的方法得到使类间方差最大的阈值T ,即为所求。
OpenCV 代码:int myOtsu(const IplImage *frame) //大津法求阈值{#define GrayScale 256 //frame 灰度级int width = frame->width;int height = frame->height;int pixelCount[GrayScale]={0};float pixelPro[GrayScale]={0};int i, j, pixelSum = width * height, threshold = 0;uchar* data = (uchar*)frame->imageData;//统计每个灰度级中像素的个数for(i = 0; i < height; i++){for(j = 0;j < width;j++){pixelCount[(int)data[i * width + j]]++;}}//计算每个灰度级的像素数目占整幅图像的比例for(i = 0; i < GrayScale; i++){pixelPro[i] = (float)pixelCount[i] / pixelSum;}//遍历灰度级[0,255],寻找合适的thresholdfloat w0, w1, u0tmp, u1tmp, u0, u1, deltaTmp, deltaMax = 0;for(i = 0; i < GrayScale; i++){w0 = w1 = u0tmp = u1tmp = u0 = u1 = deltaTmp = 0;for(j = 0; j < GrayScale; j++){if(j <= i) //背景部分{w0 += pixelPro[j];u0tmp += j * pixelPro[j];}else //前景部分{w1 += pixelPro[j];u1tmp += j * pixelPro[j];}}u0 = u0tmp / w0;u1 = u1tmp / w1;deltaTmp = (float)(w0 *w1* pow((u0 - u1), 2)) ;if(deltaTmp > deltaMax){deltaMax = deltaTmp;threshold = i;}}return threshold;}参考文献:Nobuyuki Otsu发表的原文"A Threshold Selection Method from Gray-Level Histograms," Systems, Man and Cybernetics, IEEE Transactions on , vol.9, no.1, pp.62-66, Jan. 1979。
OTSU算法

图像二值化----otsu(最大类间方差法、大津算法)
最大类间方差法是由日本学者大津于1979年提出的,是一种自适应的阈值确定的方法,又叫大津法,简称OTSU。
它是按图像的灰度特性,将图像分成背景和目标两部分。
背景和目标之间的类间方差越大,说明构成图像的两部分的差别越大,当部分目标错分为背景或部分背景错分为目标都会导致两部分差别变小。
因此,类间方差最大的分割意味着错分概率最小。
OTSU被认为是图像分割中阈值选取的最佳算法,计算简单,不受图像亮度和对比度的影响,因此在数字图像处理上得到了广泛的应用。
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))/a1 0->t,
u2 = sum(i*P(i))/a2, t+1->L-1
该法选择最佳门限t^ 使类间方差最大,即:令Δu=u1-u2,σb = max{a1(t)*a2(t)Δu^2}。
Ots算法(大律法或最大类间方差法)

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:unsafe public int GetThreshValue(Bitmap image){BitmapData bd = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.WriteOnly, image.PixelFormat);byte* pt = (byte*)bd.Scan0;int[] pixelNum = new int[256]; //图象直方图,共256个点byte color;byte* pline;int n, n1, n2;int total; //total为总和,累计值double m1, m2, sum, csum, fmax, sb; //sb为类间方差,fmax存储最大方差值int k, t, q;int threshValue = 1; // 阈值int step = 1;switch (image.PixelFormat){case PixelFormat.Format24bppRgb:step = 3;break;case PixelFormat.Format32bppArgb:step = 4;break;case PixelFormat.Format8bppIndexed:step = 1;break;}//生成直方图for (int i = 0; i < image.Height; i++){pline = pt + i * bd.Stride;for (int j = 0; j < image.Width; 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();return threshValue;}算法实现2:Otsu算法步骤如下:设图象包含L个灰度级(0,1…,L-1),灰度值为i的的象素点数为Ni ,图象总的象素点数为N=N0+N1+...+N(L-1)。
阈值分割-最大类间方差法(OTSU)

最大类间方差法是由日本学者大津于1979年提出的,是一种自适应的阈值确定的方法,又叫大津法,简称OTSU。
它是按图像的灰度特性,将图像分成背景和目标两部分。
背景和目标之间的类间方差越大,说明构成图像的两部分的差别越大, 当部分目标错分为背景或部分背景错分为目标都会导致两部分差别变小。
因此,使类间方差最大的分割意味着错分概率最小。
function ostu,filequeryStatus = QUERY_IMAGE(file, fileInfo)if queryStatus eq 0 then beginResult = DIALOG_MESSAGE('图像格式不可识别!',/error,title='警告') return,0endifif (fileInfo.CHANNELS ne 1) then beginResult = DIALOG_MESSAGE('图像格式必须为8bit',/error,title='警告') return,0endifimgSize = fileInfo.dimensionsimg=READ_IMAGE(file)p=HISTOGRAM(img)p=p/(imgSize[0]*imgSize[1]*1.0)D=0.0T0=0 ;阈值for T=0,255 do beginp0=0.0 & m0=0for i=0,T do beginp0=p0+p[i]m0=m0+i*p[i]endform0=m0/p0p1=0.0 & m1=0for i=T+1,255 do beginp1=p1+p[i]m1=m1+i*p[i]endform1=m1/p1m=p0*m0+p1*m1D01=p0*(m0-m)^2+p1*(m1-m)^2if (D lt D01) then beginD=D01T0=Tendifendforprint,'ostu法阈值:'+strtrim(T0,2)img [WHERE (img le T0)] = 0img [WHERE (img gt T0)] = 255return, imgend;--------------------pro ostu_test,imagefileDEVICE, DECOMPOSED=1; 获取本程序所在文件路径RootDir = Sourceroot()if n_elements(imagefile) eq 0 then imagefile='man' file=RootDir+imagefile+'.bmp'imgSize = fileInfo.dimensionsimg=READ_IMAGE(file)ostuimg=ostu(file)WINDOW, /free, XSIZE = imgSize[0], YSIZE = imgSize[1] TV, imgend。
OTSU算法学习OTSU公式证明

OTSU算法学习OTSU公式证明OTSU算法学习 OTSU公式证明1 otsu的公式如下,如果当前阈值为t,w0 前景点所占⽐例w1 = 1- w0 背景点所占⽐例u0 = 前景灰度均值u1 = 背景灰度均值u = w0*u0 + w1*u1 全局灰度均值g = w0(u0-u)*(u0-u) + w1(u1-u)*(u1-u) = w0*(1 – w0)*(u0 - u1)* (u0 - u1)⽬标函数为g, g越⼤,t就是越好的阈值.为什么采⽤这个函数作为判别依据,直观是这个函数反映了前景和背景的差值.差值越⼤,阈值越好.下⾯是⼀段证明g的推导的matlab代码syms w0 u0 u1 %w0 前景均值 u0 前景灰度均值 u1 背景灰度均值%背景均值w1 =1- w0;%全局灰度均值u=w0*u0+w1*u1;%⽬标函数g=w0*(u0-u)*(u0-u)+w1*(u1-u)*(u1-u);%化简的形式g1 =w0*w1*(u0-u1)*(u0-u1);%因式展开a1 = expand(g)%结果是 - u0^2*w0^2 + u0^2*w0 + 2*u0*u1*w0^2 - 2*u0*u1*w0 - u1^2*w0^2 + u1^2*w0a2 = expand(g)%结果是 - u0^2*w0^2 + u0^2*w0 + 2*u0*u1*w0^2 - 2*u0*u1*w0 - u1^2*w0^2 + u1^2*w0%对g进⾏因式分解a2 = factor(g)%结果 -w0*(u0 - u1)^2*(w0 - 1)这⾥是matlab初等代数运算的讲解2 关于最⼤类间⽅差法(otsu)的性能:类间⽅差法对噪⾳和⽬标⼤⼩⼗分敏感,它仅对类间⽅差为单峰的图像产⽣较好的分割效果。
当⽬标与背景的⼤⼩⽐例悬殊时,类间⽅差准则函数可能呈现双峰或多峰,此时效果不好,但是类间⽅差法是⽤时最少的。
3 代码实现public int GetThreshValue(Bitmap image){BitmapData bd = image.LockBits(new Rectangle(0,0, image.Width, image.Height), ImageLockMode.WriteOnly,image.PixelFormat);byte* pt =(byte*)bd.Scan0;int[] pixelNum = new int[256];//图象直⽅图,共256个点byte color;byte* pline;int n, n1, n2;int total;//total为总和,累计值double m1, m2, sum, csum, fmax, sb;//sb为类间⽅差,fmax存储最⼤⽅差值int k, t, q;int threshValue =1;// 阈值int step =1;switch(image.PixelFormat){case PixelFormat.Format24bppRgb:step =3;break;case PixelFormat.Format32bppArgb:step =4;break;case PixelFormat.Format8bppIndexed:step =1;break;}//⽣成直⽅图pline = pt + i * bd.Stride;for(int j =0; j < image.Width; 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();return threshValue;}参考了这篇⽂章4 ⼆维otsu算法下图是⼆维otsu的⽴体图,是对右边的A进⾏⼆维直⽅图统计得到的图像, 遍历区域为5*5.这是对应的matlab代码%统计⼆维直⽅图 i 当前点的亮度 j n*n邻域均值亮度function hist2 = hist2Function(image, n)%初始化255*2565矩阵hist2 = zeros(255,255);[height, width]= size(image);for i =1:heightfor j =1:widthdata = image(i,j);tempSum =0.0;for l =-n:1:nfor m =-n:1:nx = i + l;y = j+m;if x <1x =1;elseif x > widthx = width;endif y <1y =1;elseif y > heighty = height;endtempSum = tempSum + double(image(y,x));endendtempSum = tempSum /((2*n+1)*(2*n+1));hist2(data,floor(tempSum))= hist2(data,floor(tempSum))+1;endend%加载图像imagea = imread('a.bmp');%显⽰图像%imshow(imagea);%显⽰直⽅图%figure;imhist(imagea);%计算⼆维直⽅图hist2 = hist2Function(imagea,2);%显⽰⼆维直⽅图[x,y]=meshgrid(1:1:255);mesh(x,y,hist2)<灰度图象的⼆维Otsu⾃动阈值分割法.pdf> 这篇⽂章讲解的不错.⽂章这⾥有下载下⾯⽤数学语⾔表达⼀下i :表⽰亮度的维度j : 表⽰点区域均值的维度w0: 表⽰在阈值(s,t)时所占的⽐例w1: 表⽰在阈值(s,t)时, 所占的⽐例u0(u0i, u0j): 表⽰在阈值(s,t)时时的均值.u0时2维的u1(u1i, u1j): 表⽰在阈值(s,t)时的均值.u1时2维的uT: 全局均值和⼀维otsut函数类似的⽬标函数sb = w0(u0-uT)*(u0-uT)’ + w1(u1-uT)*(u1-uT)’= w0[(u0i-uTi)* (u0i-uTi) + (u0j-uTj)* (u0j-uTj)] + w1[(u1i-uTi)* (u1i-uTi) + (u1j-uTj)* (u1j-uTj)]这⾥是代码实现.出⾃这篇⽂章:int histogram[256][256];double p_histogram[256][256];double Pst_0[256][256];//Pst_0⽤来存储概率分布情况double Xst_0[256][256];//存储x⽅向上的均值⽮量int OTSU2d(IplImage * src){int height = src->height;int width = src->width;long pixel = height * width;int i,j;for(i =0;i <256;i++)//初始化直⽅图for(j =0; j <256;j++)histogram[i][j]=0;}IplImage * temp = cvCreateImage(cvGetSize(src),8,1);cvSmooth(src,temp,CV_BLUR,3,0);for(i =0;i < height;i++)//计算直⽅图{for(j =0; j < width;j++){int data1 = cvGetReal2D(src,i,j);int data2 = cvGetReal2D(temp,i,j);histogram[data1][data2]++;}}for(i =0; i <256;i++)//直⽅图归⼀化for(j =0; j <256;j++)p_histogram[i][j]=(histogram[i][j]*1.0)/(pixel*1.0);Pst_0[0][0]= p_histogram[0][0];for(i =0;i <256;i++)//计算概率分布情况for(j =0;j <256;j++){double temp =0.0;if(i-1>=0)temp = temp + Pst_0[i-1][j];if(j-1>=0)temp = temp + Pst_0[i][j-1];if(i-1>=0&& j-1>=0)temp = temp - Pst_0[i-1][j-1];temp = temp + p_histogram[i][j];Pst_0[i][j]= temp;}Xst_0[0][0]=0* Pst_0[0][0];for(i =0; i <256;i++)//计算x⽅向上的均值⽮量for(j =0; j <256;j++){double temp =0.0;if(i-1>=0)temp = temp + Xst_0[i-1][j];if(j-1>=0)temp = temp + Xst_0[i][j-1];if(i-1>=0&& j-1>=0)temp = temp - Xst_0[i-1][j-1];temp = temp + i * p_histogram[i][j];Xst_0[i][j]= temp;}double Yst_0[256][256];//存储y⽅向上的均值⽮量Yst_0[0][0]=0* Pst_0[0][0];for(i =0; i <256;i++)//计算y⽅向上的均值⽮量for(j =0; j <256;j++){double temp =0.0;if(i-1>=0)temp = temp + Yst_0[i-1][j];if(j-1>=0)temp = temp + Yst_0[i][j-1];if(i-1>=0&& j-1>=0)temp = temp - Yst_0[i-1][j-1];temp = temp + j * p_histogram[i][j];Yst_0[i][j]= temp;}int threshold1;int threshold2;double variance =0.0;double maxvariance =0.0;for(i =0;i <256;i++)//计算类间离散测度for(j =0;j <256;j++){longdouble p0 = Pst_0[i][j];longdouble v0 = pow(((Xst_0[i][j]/p0)-Xst_0[255][255]),2)+ pow(((Yst_0[i][j]/p0)-Yst_0[255][255]),2);longdouble p1 = Pst_0[255][255]-Pst_0[255][j]-Pst_0[i][255]+Pst_0[i][j];longdouble vi = Xst_0[255][255]-Xst_0[255][j]-Xst_0[i][255]+Xst_0[i][j];longdouble vj = Yst_0[255][255]-Yst_0[255][j]-Yst_0[i][255]+Yst_0[i][j];longdouble v1 = pow(((vi/p1)-Xst_0[255][255]),2)+pow(((vj/p1)-Yst_0[255][255]),2);variance = p0*v0+p1*v1;if(variance > maxvariance){maxvariance = variance;threshold1 = i;threshold2 = j;}}//printf("%d %d",threshold1,threshold2);return(threshold1+threshold2)/2;}总结: ⼆维otsu算法得到⼀个阈值,然后对图像做⼆值化.仍然不能解决光照不均匀⼆值化的问题.⽐⼀维otsu效果好⼀些,但不是很明显.这个算法的亮点在于考虑的点的附近区域的均值.。
一种改进的火焰图像分割方法

一种改进的火焰图像分割方法摘要:在火灾图像识别算法中,将火焰图像从背景中分离出来是识别过程的前提条件和必要环节。
从目前应用情况来看,最大类间方差法(也称Otsu法)是比较简洁有效的方法。
该方法属于阈值选取方法,其特点是算法比较简单,适于实时处理,其局限性在于对图像的“双峰直方图”过于依赖。
针对该方法上述的缺点和不足,提出了一种新型的基于灰度积分投影法的火焰图像分割及定位方法。
实验证明,该算法不但能正确地将火焰图像从背景中快速分离出来,而且可迅速定位火焰的中心位置,可以为动态识别火焰图像提供重要的判别依据。
关键词:图像分割灰度积分投影最大类间方差法火焰检测在现有的火灾识别算法中,将火焰图像与背景图像进行准确有效地分离一直是火灾监控中的关键技术。
只有将火焰与背景图像相分离,并对其特性做进一步的分析,才能对火灾是否发生做出正确的判断。
还可以根据火焰图像像素的增加对火势蔓延做出正确的分析和评估。
因此,基于火焰特点的图像分割算法就显得格外重要。
目前,基于图像灰度或饱和度的直方图分析法是最为常用的方法。
但这种方法受双峰直方图这一条件的限制,对有的图像效果不理想。
此外,直方图法只能显示图像的颜色信息,无法体现图像的空间信息。
在如果能找到一种方法,既能判断火焰图像的尖角位置,又能有效地实现火焰图像与背景的分离,且计算量不大,那么这种方法无疑是比较理想的。
本文利用灰度积分投影法,先确定出火焰图像火苗最高处的水平坐标位置,再从这一列上按搜索法取一片区域像素的平均值作为二值化的阈值,可实现火焰图像的分割,同时这也符合人们的分类习惯。
这样做的的好处是,整个运算过程只有一次对整个图像的遍历操作,大大减少了运算时间。
其次,在抽取火焰图像同时可确定火焰的尖角位置,为后面的识别提供必要的信息。
实验证明,该方法具有运算速度快、定位准确、适用范围广等特点。
1 最大类间方差法简介最大类间方差法是一种常用的图像分割方法,该方法是Otsu在1979年提出的基于自适应阈值分割方法。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
在网上很多地方都可以找到,但是我发觉似乎都是一样,而且一点注释 都没有,如果光拿来用当然可以了,可是用一个算法不搞清楚里面的数 学是件很遗憾的事情,我把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)*(u1u)=w0*w1*(u0-u1)*(u0-u1),此公式为方差公式,可参照概率论课本 上面的g的公式也就是下面程序中的sb的表达式 当方差g最大时,可以认为此时前景和背景差异最大,也就是此时的灰 度是最佳阈值 unsafe public int GetThreshValue(Bitmap image) { BitmapData bd = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.WriteOnly, image.PixelFormat); byte* pt = (byte*)bd.Scan0; int[] pixelNum = new int[256]; //图象直方图,共256个点pline; int n, n1, n2; int total; //total为总和,累计值 double m1, m2, sum, csum, fmax, sb; //sb为类间方差,fmax存储最 大方差值 int k, t, q; int threshValue = 1; // 阈值 int step = 1; switch (image.PixelFormat) { case PixelFormat.Format24bppRgb: step = 3; break; case PixelFormat.Format32bppArgb: step = 4; break; case PixelFormat.Format8bppIndexed: step = 1; break; } //生成直方图 for (int i = 0; i < image.Height; i++) { pline = pt + i * bd.Stride; for (int j = 0; j < image.Width; 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值应取较小 的值 {
间方差 if (sb > fmax) //如果算出的类间方差大于前一次算出的类间方差 { fmax = sb; //fmax始终为最大类间方差(otsu) threshValue = k; //取最大类间方差时对应的灰度的k就是最佳阈值 } } image.UnlockBits(bd); image.Dispose();
q = k + t; if (q < 0) //越界处理 q = 0; if (q > 255) q = 255; total = total + pixelNum[q]; //total为总和,累计值 } pixelNum[k] = (int)((float)total / 5.0 + 0.5); //平滑化,左边2 个+中间1个+右边2个灰度,共5个,所以总和除以5,后面加0.5是用修 正值 } //求阈值 sum = csum = 0.0; n = 0; //计算总的图象的点数和质量矩,为后面的计算做准备 for (k = 0; k <= 255; k++) { sum += (double)k * (double)pixelNum[k]; //x*f(x)质量矩,也就是 每个灰度的值乘以其点数(归一化后为概率),sum为其总和 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为背景图象的点数 if (n2 == 0) { break; } //n2为0表示全部都是背景图象,与n1=0情 况类似,之后的遍历不可能使前景点数增加,所以此时可以退出循环 csum += (double)k * pixelNum[k]; //前景的“灰度的值*其点数”的 总和 m1 = csum / n1; //m1为前景的平均灰度 m2 = (sum - csum) / n2; //m2为背景的平均灰度 sb = (double)n1 * (double)n2 * (m1 - m2) * (m1 - m2); //sb为类