一、算法原理
OSTU算法也就是最大类间方差法,也即大津法。是一种选取最佳的阈值分割的方法,是阈值选取中最佳的方法。
按照灰度的特性将图像分成前景和背景两部分。背景和前景之间的类间方差越大,说明构成图像两部分的差别就
越大,当部分前景错分为背景活部分背景错分为前景都会导致两部分差别变小。因此,是类间方差最大的分割
意味着错分概率最小。
设图像I(x,y)的前景和背景的分割阈值为T,属于前景像素点占整幅图像的比例记为w1,其平均灰度为u1,
属于背景像素点占整幅图像的比例记为w2,其平均灰度为u2。图像的总平均灰度记为u,类间方差记为g。假设
图像的大小为M*N,灰度值是0至255。具体步骤为:
1.首先计算每个像素在整幅图像中的个数h[k],然后把每个像素值的个数除以图像的大小(M*N),得到每个像素在
在整幅图像中的比例 p[i]。
2.求得前k个像素值所占的比例w[k]]和其均值u[k],同时求的整幅图像像素的均值uT,然后根据方差公式求的最大类间方差。
在这里我只求了前景的比例和均值。因为根据方差公式可以推导出最简单的公式:
t=Max[(uT*w[k] - u[k])*(uT*w[k] - u[k]) / (w[k]*(1-w[k]))];推导过程如下:
二、ostu代码如下
#include <stdafx.h>
#include <math.h>
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
int hei;
int wid;
void otsu(IplImage* A, IplImage* B)
{
int i,j,k;
long N = hei * wid;
int h[256];
double p[256],u[256],w[256];
for(i = 0; i < 256; i++)
{
h[i] = 0;
p[i] = 0;
u[i] = 0;
w[i] = 0;
}
for(i = 0; i < hei; i++)
{
for(j = 0; j < wid; j++)
{
for(k = 0; k < 256; k++)
{
if(((uchar*)(A->imageData + A->widthStep*i))[j] == k)
{
h[k]++; //统计灰度级中每个像素在整幅图像中的个数
}
}
}
}
for(i = 0; i < 256; i++)
p[i] = h[i] / double(N); //计算每个像素在整幅图像中的比例
int T = 0; //阈值初始化为0
double uT,thegma2fang;
double thegma2fang_max = -10000;
for(int k = 0; k < 256; k++)
{
uT = 0;
for(i = 0; i <= k; i++)
{
u[k] += i*p[i];//u[k]表示前k个像素值的均值
w[k] += p[i]; //w[k]表示前k个像素值所占的比例
}
for(i = 0; i < 256; i++)
uT += i*p[i]; //uT表示整幅图像的均值
thegma2fang = (uT*w[k] - u[k])*(uT*w[k] - u[k]) / (w[k]*(1-w[k]));
if(thegma2fang > thegma2fang_max)
{
thegma2fang_max = thegma2fang;
T = k;
}
}
printf("T=%d",T);//T=117
for(i = 0; i < hei; i++)
{
for(j = 0; j < wid; j++)
{
if(((uchar*)(A->imageData + A->widthStep*i))[j] > T)
((uchar*)(B->imageData + B->widthStep*i))[j] = 255;
else
((uchar*)(B->imageData + B->widthStep*i))[j] = 0;
}
}
}
int main(int argc, char** argv)
{
IplImage *src = cvLoadImage("lena.jpg");
IplImage *InPut = cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1);
cvCvtColor(src,InPut,CV_BGR2GRAY);
IplImage *OutPut = cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1);
hei = src->height;
wid = src->width;
otsu(InPut,OutPut);
cvNamedWindow( "Resource");
cvShowImage( "Resource", InPut );
cvNamedWindow( "Result");
cvShowImage( "Result", OutPut );
cvWaitKey(0);
return 0;
}