原理介绍:
Ostu大律法方法又名最大类间差方法,通过统计整个图像的直方图特性来实现全局阈值T的自动选取,其算法步骤为:
- 先计算图像的直方图,将图像所有的像素点按照0~255共256个bin,统计落在每个bin的像素点数量;
- 计算每个像素值的比例;
- i表示分类的最佳阈值,从0开始迭代;
- 以i为阈值分类,计算第一类和第二类总的概率w0,w1,计算第一类的平均灰度和第二类的平均灰度以及整幅图像的平均灰度u0,u1,u;
- 计算前景像素和背景像素的方差 g = w0 * (u0 - u)(u0 - u) + w1 * (u1 - u)(u1 - u)
- i++;转到4),直到i为256时结束迭代;
7)将最大g相应的i值作为图像的全局阈值。
代码:
int ostu(ImageType::Pointer image)
{
int width = image->GetLargestPossibleRegion().GetSize()[0];
int heigth = image->GetLargestPossibleRegion().GetSize()[1];
int x = 0, y = 0;
int pixelCount[256] = { 0 };//每个像素的计数
float pixelPro[256] = { 0 };; //每种像素比例
int i, j, pixelSum = width * heigth, threshold = 0;
//统计灰度级中每个像素在整幅图像中的个数
for (int i = 0; i < width; i++)
for (int j = 0; j < heigth; j++)
{
ImageType::IndexType pixelIndex;
pixelIndex[0] = i;
pixelIndex[1] = j;
pixelCount[image->GetPixel(pixelIndex)]++;
}
//计算每个像素在整幅图像中的比例
for (int i = 0; i < 256; i++)
{
pixelPro[i] = (float)pixelCount[i] / (float)pixelSum;
}
//经典ostu算法,得到前景和背景的分割
//遍历灰度级[0,255],计算出方差最大的灰度值,为最佳阈值
float w0, w1, u0tmp, u1tmp, u0, u1, u, deltaTmp, deltaMax = 0;
for (i = 0; i < 256; i++)
{
w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;
for (j = 0; j < 256; j++)
{
if (j <= i) //背景部分
{
//以i为阈值分类,第一类总的概率
w0 += pixelPro[j];
u0tmp += j * pixelPro[j];
}
else //前景部分
{
//以i为阈值分类,第二类总的概率
w1 += pixelPro[j];
u1tmp += j * pixelPro[j];
}
}
u0 = u0tmp / w0; //第一类的平均灰度
u1 = u1tmp / w1; //第二类的平均灰度
u = u0tmp + u1tmp; //整幅图像的平均灰度
//计算类间方差
deltaTmp = w0 * (u0 - u)*(u0 - u) + w1 * (u1 - u)*(u1 - u);
//找出最大类间方差以及对应的阈值
if (deltaTmp > deltaMax)
{
deltaMax = deltaTmp;
threshold = i;
}
}
ItType it(image, image->GetRequestedRegion());
//将迭代器移动到首个元素
it.GoToBegin();
//遍历像素,直至结束
while (!it.IsAtEnd())
{
//获取像素值
ImageType::PixelType value = it.Get();
if ((int)value > threshold)
{
it.Set(255);
}
else
{
it.Set(0);
}
//迭代器移动至下一元素
++it;
}
//返回最佳阈值;
return threshold;
}