一、大津法二值化算法
大津法是一种自适应阈值法,该算法是由日本学者大津展之于1979年提出的,也被称为OTSU算法。
该算法是对灰度图像进行二值化的一种方法,它通过计算图像的阈值,将图像分成前景和背景两部分。阈值能够根据图像的直方图分布情况自适应的调整。
该算法的主要思路如下:
1、对图像的每一个灰度值进行统计,得到灰度直方图。
2、遍历灰度直方图,计算每一个灰度值的“类内方差”。类内方差度量了同一区域内像素灰度分布的聚集程度,方差越小,表示像素值分布越聚集,对应的区域越容易被划分为背景或者前景。
3、选取类内方差最小的灰度阈值作为二值化的阈值。
二、大津法二值化的代码实现
接下来是一个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 maxSigma) { maxSigma = sigma[i]; threshold = i; } } // 对图像进行二值化 for (int i = 0; i < h; i++) { for (int j = 0; j 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 threshold) { img[i*w + j] = 255; } else { img[i*w + j] = 0; } } }
在MATLAB中,可以使用以下代码进行二值化:
bwImg = imbinarize(img, threshold/255);
五、大津算法求二值化阈值选取
大津算法求二值化阈值选取是对大津法二值化的改进,该算法通过迭代的方式求出最优的阈值,从而使得阈值更加准确。
该算法主要思路如下:
1、初始化阈值T为图像的平均值。
2、将像素分为两类:小于等于阈值T和大于阈值T。
3、计算两个类的平均值:μ1和μ2。
4、计算两个类对应的类内方差:var1和var2。
5、计算全局类内方差:intraVariance。
6、将阈值T更新为使得全局类内方差最小的值。
7、重复步骤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 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 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 threshold) { img[i*w + j] = 255; } else { img[i*w + j] = 0; } } }
上述代码首先定义了一个阈值的变化阈值,当两次迭代之间的阈值变化小于该值时,算法停止。接下来进行迭代,直到达到停止条件。在每一次迭代过程中,首先将图像分为两类,统计每一类的像素值频率和像素值分布情况等参数,然后计算全局类内方差,更新阈值。最后,使用更新后的阈值对图像进行二值化处理。
原创文章,作者:EPXP,如若转载,请注明出处:https://www.506064.com/n/142125.html