1.最大类间方差法(Otsu法)
该算法是日本人Otsu提出的一种动态阈值分割算法。它的主要思想是按照灰度特性将图像划分为背景和目标2部分,划分依据为选取门限值,使得背景和目标之间的方差最大。(背景和目标之间的类间方差越大,说明这两部分的差别越大,当部分目标被错划分为背景或部分背景错划分为目标都会导致这两部分差别变小。因此,使用类间方差最大的分割意味着错分概率最小。)这是该方法的主要思路。其主要的实现原理为如下:
1)建立图像灰度直方图(共有L个灰度级,每个出现概率为p)
2)计算背景和目标的出现概率,计算方法如下:
上式中假设t为所选定的阈值,A代表背景(灰度级为0~N),根据直方图中的元素可知,Pa为背景出现的概率,同理B为目标,Pb为目标出现的概率。
3)计算A和B两个区域的类间方差如下:
第一个表达式分别计算A和B区域的平均灰度值;
第二个表达式计算灰度图像全局的灰度平均值;
第三个表达式计算A、B两个区域的类间方差。4)以上几个步骤计算出了单个灰度值上的类间方差,因此最佳分割门限值应该是图像中能够使得A与B的类间灰度方差最大的灰度值。在程序中需要对每个出现的灰度值据此进行寻优。
以下对两个不同类型的图像采用最大类间方差法寻找最优阈值进行分割:
C++源码:
#include "stdio.h"
#include "cv.h"
#include "highgui.h"
#include "Math.h"
#include <tchar.h>
int Otsu(IplImage* src);
int _tmain(int argc, _TCHAR* argv[])
{
IplImage* img = cvLoadImage("E:\\11.jpg", 0);
IplImage* dst = cvCreateImage(cvGetSize(img), 8, 1);
int threshold = Otsu(img);
cvThreshold(img, dst, threshold, 255, CV_THRESH_BINARY);
cvNamedWindow("img", 1);
cvShowImage("img", dst);
cvWaitKey(-1);
cvReleaseImage(&img);
cvReleaseImage(&dst);
cvDestroyWindow("dst");
return 0;
}
int Otsu(IplImage* src)
{
int height = src->height;
int width = src->width;
double nHistogram[256]; //灰度直方图
double dVariance[256]; //类间方差
int N = height*width; //总像素数
for (int i = 0; i<256; i++)
{
nHistogram[i] = 0.0;
dVariance[i] = 0.0;
}
for (int i = 0; i<height; i++)
{
unsigned char* nData = (unsigned char*)src->imageData + src->widthStep * i;
for (int j = 0; j < width; j++)
{
nHistogram[*nData++]++; //建立直方图
}
}
double Pa = 0.0; //背景出现概率
double Pb = 0.0; //目标出现概率
double Wa = 0.0; //背景平均灰度值
double Wb = 0.0; //目标平均灰度值
double W0 = 0.0; //全局平均灰度值
double dData1 = 0.0,