现有的阈值分割方法例如最大类间方差阈值分割、迭代法阈值分割对于光斑图像分割的效果都不理想。通过研究得出,光斑图像具有背景暗而目标亮,背景面积大而目标面积小特点, 并结合大津阈值分割的思想, 本文提出了一种针对光斑图像的阈值分割方法。以背景和目标的类间方差最大,类内方差最小,背景与目标的面积比最大作为判定准则。设一幅图像的灰度值为0~m-1 级,图像中灰度值为i 的像素的个数为ni,用阈值T 将其分成两组C0={0~T-1}为背景(暗),C1={T~m-1}为目标(亮)。
像素总数:各值的概率:背景概率:
目标概率:背景平均值:目标平均值:
全部采样的灰度平均值:两组间的方差:
背景区类内方差:目标区类内方差:
背景与目标出现的概率比:
准则函数为:
代码实现:(准则函数的求解公式推导过程比较麻烦,并且代码里没有展示中间变量是因为w和1-w可能极小造成的输出无效,所以写成综合式。
int otsu(IplImage* src)
{
int histSize = 256; //直方图尺寸
int histHeight = 256;
float range[] = {0,255}; //灰度级的范围
float* ranges[]={range};
//创建一维直方图,统计图像在[0 255]像素的均匀分布
CvHistogram* grayHist = cvCreateHist(1,&histSize,CV_HIST_ARRAY,ranges,1);
//计算灰度图像的一维直方图
cvCalcHist(&src,grayHist,0,0);
//归一化直方图
cvNormalizeHist(grayHist,1.0);
int threshold = 0;
double delta1 = 0, delta2 = 0;
double firstMoment = 0, secondMoment = 0;
double variance = 0;
for(int m=0; m<256; m++)
{
firstMoment += cvQueryHistValue_1D(grayHist,m)*m; //图像一阶距
secondMoment += pow(m,2)*cvQueryHistValue_1D(grayHist,m); //图像二阶距
}
double u = 0, w = 0;
for(int k=0; k<256; k++)
{
u += cvQueryHistValue_1D(grayHist,k)*k; //
w += cvQueryHistValue_1D(grayHist,k); //灰度大于阈值k的像素的概率
double t = firstMoment * w - u;
double delta1 = t * t / (w * (1 - w) ); //类间方差
delta2 = ((pow(u,2)/w + pow(firstMoment-u,2)/(1-w)) - pow(k-u/w,2)*cvQueryHistValue_1D(grayHist,k))/(1-w); //目标区内方差
double varianceTmp = (w/(1-w)*delta1)/(pow(k-u/w,2)*cvQueryHistValue_1D(grayHist,k)+(1-w)*delta2); //准则函数
if(varianceTmp > variance)
{
variance = varianceTmp;
threshold = k;
}
}
cvReleaseHist(&grayHist);
return threshold;
}