一、大津法二值化算法
大津法是一种自适应阈值法,该算法是由日本学者大津展之于1979年提出的,也被称为OTSU算法。 该算法是对灰度图像进行二值化的一种方法,它通过计算图像的阈值,将图像分成前景和背景两部分。阈值能够根据图像的直方图分布情况自适应的调整。 该算法的主要思路如下:
- 对图像的每一个灰度值进行统计,得到灰度直方图。
- 遍历灰度直方图,计算每一个灰度值的“类内方差”。类内方差度量了同一区域内像素灰度分布的聚集程度,方差越小,表示像素值分布越聚集,对应的区域越容易被划分为背景或者前景。
- 选取类内方差最小的灰度阈值作为二值化的阈值。
二、大津法二值化的代码实现
接下来是一个C语言中实现大津法二值化的示例代码:
// img -- 图像数据
// w -- 图像宽度
// h -- 图像高度
int threshold = 0;
int pixelCount[256] = {0};
float pixelProb[256] = {0.0f};
float cumProb[256] = {0.0f};
float cumMean[256] = {0.0f};
float sigma[256] = {0.0f};
// 计算像素值出现的频率
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
int pixel = img[i*w + j];
pixelCount[pixel]++;
}
}
// 计算像素值出现的概率
for (int i = 0; i < 256; i++) {
pixelProb[i] = (float)pixelCount[i] / (float)(w * h);
}
// 计算累积概率和累积分布均值
for (int i = 0; i < 256; i++) {
if (i == 0) {
cumProb[i] = pixelProb[i];
cumMean[i] = i * pixelProb[i];
} else {
cumProb[i] = cumProb[i-1] + pixelProb[i];
cumMean[i] = cumMean[i-1] + i * pixelProb[i];
}
}
// 计算全局平均值
float globalMean = cumMean[255];
// 计算类内方差
for (int i = 0; i < 256; i++) {
if (i == 0 || cumProb[i] == 1.0f) {
sigma[i] = 0.0f;
} else {
float weight = cumProb[i];
float mean = cumMean[i] / cumProb[i];
sigma[i] = (globalMean * weight - mean) * (globalMean * weight - mean) / (weight * (1.0f - weight));
}
}
// 选取类内方差最小的像素值作为阈值
float maxSigma = 0.0f;
for (int i = 0; i < 256; i++) {
if (sigma[i] > maxSigma) {
maxSigma = sigma[i];
threshold = i;
}
}
// 对图像进行二值化
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
int pixel = img[i*w + j];
if (pixel > threshold) {
img[i*w + j] = 255;
} else {
img[i*w + j] = 0;
}
}
}
三、大津法二值化的程序实现
除了使用C语言实现大津法二值化之外,我们还可以使用其他的编程语言实现。下面是使用MATLAB实现大津法二值化的示例代码:
% img -- 图像数据
histogram = imhist(img);
pixelProb = histogram / sum(histogram);
cumProb = cumsum(pixelProb);
cumMean = cumsum((0:255)'.*pixelProb);
globalMean = cumMean(end);
sigma = (globalMean*cumProb - cumMean).^2 ./ (cumProb.*(1-cumProb));
[~, threshold] = max(sigma);
bwImg = imbinarize(img, threshold/255);
使用MATLAB时,可以使用imhist
函数计算图像的直方图,使用imbinarize
函数进行二值化。
四、大津法二值化后如何知道具体阈值
大津法二值化得到的阈值可以用于对图像进行二值化处理。 我们可以在处理图像的时候,将得到的阈值作为参数传入二值化函数。在C语言中,可以使用以下代码进行二值化:
int threshold = 128;
// img -- 图像数据
// w -- 图像宽度
// h -- 图像高度
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
int pixel = img[i*w + j];
if (pixel > threshold) {
img[i*w + j] = 255;
} else {
img[i*w + j] = 0;
}
}
}
在MATLAB中,可以使用以下代码进行二值化:
bwImg = imbinarize(img, threshold/255);
五、大津算法求二值化阈值选取
大津算法求二值化阈值选取是对大津法二值化的改进,该算法通过迭代的方式求出最优的阈值,从而使得阈值更加准确。 该算法主要思路如下:
- 初始化阈值T为图像的平均值。
- 将像素分为两类:小于等于阈值T和大于阈值T。
- 计算两个类的平均值:μ1和μ2。
- 计算两个类对应的类内方差:var1和var2。
- 计算全局类内方差:intraVariance。
- 将阈值T更新为使得全局类内方差最小的值。
- 重复步骤2~6,直到阈值T的变化小于给定的阈值。 下面是使用C语言实现大津算法求二值化阈值选取的示例代码:
// img -- 图像数据
// w -- 图像宽度
// h -- 图像高度
#define THRESHOLD_DELTA 0.5f
float threshold = 0.0f;
while (true) {
int pixelCount1 = 0;
int pixelCount2 = 0;
float pixelProb1 = 0.0f;
float pixelProb2 = 0.0f;
float cumProb1 = 0.0f;
float cumProb2 = 0.0f;
float cumMean1 = 0.0f;
float cumMean2 = 0.0f;
float intraVariance = 0.0f;
// 遍历图像,计算各种参数
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
int pixel = img[i*w + j];
if (pixel > threshold) {
pixelCount1++;
cumMean1 += pixel;
} else {
pixelCount2++;
cumMean2 += pixel;
}
}
}
pixelProb1 = (float)pixelCount1 / (float)(w * h);
pixelProb2 = (float)pixelCount2 / (float)(w * h);
cumProb1 = pixelProb1;
cumProb2 = pixelProb2;
cumMean1 /= pixelCount1;
cumMean2 /= pixelCount2;
// 计算类内方差和全局方差
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
int pixel = img[i*w + j];
if (pixel > threshold) {
intraVariance += (pixel-cumMean1)*(pixel-cumMean1);
} else {
intraVariance += (pixel-cumMean2)*(pixel-cumMean2);
}
}
}
intraVariance /= (float)(w*h);
// 更新阈值
float newThreshold = (cumMean1+cumMean2) / 2.0f;
if (fabs(newThreshold-threshold) < THRESHOLD_DELTA) {
threshold = newThreshold;
break;
}
threshold = newThreshold;
}
// 对图像进行二值化
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
int pixel = img[i*w + j];
if (pixel > threshold) {
img[i*w + j] = 255;
} else {
img[i*w + j] = 0;
}
}
}
上述代码首先定义了一个阈值的变化阈值,当两次迭代之间的阈值变化小于该值时,算法停止。接下来进行迭代,直到达到停止条件。在每一次迭代过程中,首先将图像分为两类,统计每一类的像素值频率和像素值分布情况等参数,然后计算全局类内方差,更新阈值。最后,使用更新后的阈值对图像进行二值化处理。