影象處理演算法2——Otsu最佳閾值分割法
阿新 • • 發佈:2019-01-02
Otsu法是1979年由日本大津提出的。該方法在類間方差最大的情況下是最佳的,即統計鑑別分析中所用的度量。Otsu方法有一個重要的特性,就是它完全以在一幅影象的直方圖上執行計算為基礎,而直方圖是很容易得到的一維陣列。
具體的公式推理及公式細節就不說了,詳見 Conzalez 那本書,我是第三版的,在P.479——P.482 上面。
給出具體步驟如下:
1、計算輸入影象的直方圖,並歸一化。
2、計算累積均值mu,以及全域性灰度均值。
3、計算被分到類1的概率q1,和被分到類2的概率q2。
4、用公式計算類間方差,sigma = q1*q2*(mu1 - mu2)*(mu1 - mu2)
5、迴圈尋找類間方差最大值,並記下此時的閾值,即為最佳閾值。
6、利用最佳閾值進行影象閾值化。
關於otsu部分的程式程式碼如下:
[cpp] view plain copy print?- double getThreshVal_Otsu_8u( const Mat& _src )
- {
- Size size = _src.size();
- constint N = 256;
- int i, j, h[N] = {0};
- unsigned char* src;
- //直方圖統計
- for( i = 0; i < size.height; i++ )
- {
- src = _src.data + _src.step*i;
- j = 0;
- for(j = 0; j < size.width; j++ )
- h[src[j]]++;
- }
- //畫素平均值
- double mu = 0, scale = 1./(size.width*size.height);
- for( i = 0; i < N; i++ )
- {
- mu += i*(double)h[i];//累加均值
- }
- mu *= scale;//平均
- double mu1 = 0, q1 = 0;//q1 ,q2 為類1和類2的概率累積和,mu1=mg*q1
- double p_i, q2, mu2, sigma;
- double max_sigma = 0, max_val = 0;
- //迴圈求取最大閾值
- for( i = 0; i < N; i++ )
- {
- p_i = h[i]*scale;//直方圖歸一化
- mu1 *= q1;
- q1 += p_i;
- q2 = 1. - q1;
- mu1 = (mu1 + i*p_i)/q1;
- mu2 = (mu - q1*mu1)/q2;
- sigma = q1*q2*(mu1 - mu2)*(mu1 - mu2);//類間方差
- if( sigma > max_sigma )
- {
- max_sigma = sigma;
- max_val = i;//記下使類間方差最大的閾值
- }
- }
- return max_val;//返回閾值
- }
double getThreshVal_Otsu_8u( const Mat& _src )
{
Size size = _src.size();
const int N = 256;
int i, j, h[N] = {0};
unsigned char* src;
//直方圖統計
for( i = 0; i < size.height; i++ )
{
src = _src.data + _src.step*i;
j = 0;
for(j = 0; j < size.width; j++ )
h[src[j]]++;
}
//畫素平均值
double mu = 0, scale = 1./(size.width*size.height);
for( i = 0; i < N; i++ )
{
mu += i*(double)h[i];//累加均值
}
mu *= scale;//平均
double mu1 = 0, q1 = 0;//q1 ,q2 為類1和類2的概率累積和,mu1=mg*q1
double p_i, q2, mu2, sigma;
double max_sigma = 0, max_val = 0;
//迴圈求取最大閾值
for( i = 0; i < N; i++ )
{
p_i = h[i]*scale;//直方圖歸一化
mu1 *= q1;
q1 += p_i;
q2 = 1. - q1;
mu1 = (mu1 + i*p_i)/q1;
mu2 = (mu - q1*mu1)/q2;
sigma = q1*q2*(mu1 - mu2)*(mu1 - mu2);//類間方差
if( sigma > max_sigma )
{
max_sigma = sigma;
max_val = i;//記下使類間方差最大的閾值
}
}
return max_val;//返回閾值
}
注意,上面這部分傳遞的影象是 Mat 型別的,和 Iplimage 型別在影象引數部分寫法上有一點區別,注意區分開來
顯示結果如下: