文章目录
- Otsu算法简介
- Otsu 算法的逻辑
- 源码实现
 
欢迎访问个人网络日志🌹🌹知行空间🌹🌹
Otsu算法简介
Otsu阈值法发表于1979年,论文为A threshold selection method from gray level histograms,作者是日本东京大学的Nobuyuki Otsu(大津 展之)。
自动全局阈值算法通常包括如下几步
- 1.对输入图像进行预处理,如高斯平滑
- 2.获取图像的灰度直方图
- 3.计算阈值T
- 4.对原图像二值化,小于阈值T的位置像素值设为0,大于阈值T的像素值设为255
一般,各种阈值处理算法的区别主要在第3步,即确定阈值的逻辑不同。
Otsu 算法的逻辑
其核心思想是,将图像的像素根据某个像素值分成两簇,并使得这两簇之间的像素值的类间方差最大化。
所以Otsu算法适合用于像素直方图表现为双峰图像的阈值处理。
双峰图像(bimodal images)是指具有如下形式像素直方图的图像:

如下就是一个双峰图像的示例:

 假设一副灰度图,像素值灰度级为 
     
      
       
       
         L 
        
       
      
        L 
       
      
    L,如我们常见的灰度图像,灰度级是256。
像素值为第 i i i个灰度级的像素点有 n i n_i ni个,则这幅图像总的像素点个数为 N = n 1 + n 2 + . . . n L N=n_1+n_2+...n_L N=n1+n2+...nL
基于上述假设,某个像素点为灰度级 i i i的概率可表示为:
p i = n i N p_i=\frac{n_i}{N} pi=Nni
p i p_i pi满足以下条件: p i > 0 , ∑ i = 1 L p i = 1 p_i\gt0,\sum_{i=1}^Lp_i=1 pi>0,i=1∑Lpi=1
取灰度级 t t t为阈值将这幅图像的像素点分成 C 1 C_1 C1和 C 2 C_2 C2两簇,
- C 1 C_1 C1包含像素级为 [ 1 , 2 , . . . , t ] [1,2,...,t] [1,2,...,t]的像素
- C 2 C_2 C2包含像素级为 [ t + 1 , . . . , L ] [t+1,...,L] [t+1,...,L]的像素
对于图像中某个像素属于 C 1 / C 2 C_1/C_2 C1/C2类的概率可表示为:
 
      
       
        
         
         
           ω 
          
         
           1 
          
         
        
          ( 
         
        
          t 
         
        
          ) 
         
        
          = 
         
         
         
           ∑ 
          
          
          
            i 
           
          
            = 
           
          
            1 
           
          
         
           t 
          
         
         
         
           p 
          
         
           i 
          
         
        
       
         \omega_1(t) = \sum^t_{i=1}p_i 
        
       
     ω1(t)=i=1∑tpi
  
      
       
        
         
         
           ω 
          
         
           2 
          
         
        
          ( 
         
        
          t 
         
        
          ) 
         
        
          = 
         
         
         
           ∑ 
          
          
          
            i 
           
          
            = 
           
          
            t 
           
          
            + 
           
          
            1 
           
          
         
           L 
          
         
         
         
           p 
          
         
           i 
          
         
        
       
         \omega_2(t) = \sum^L_{i=t+1}p_i 
        
       
     ω2(t)=i=t+1∑Lpi
ω 1 ( t ) , ω 2 ( t ) \omega_1(t),\omega_2(t) ω1(t),ω2(t)满足关系 ω 1 ( t ) = 1 − ω 2 ( t ) \omega_1(t) = 1 - \omega_2(t) ω1(t)=1−ω2(t)
求 C 1 / C 2 C_1/C_2 C1/C2每个簇对应的像素均值:
μ 1 ( t ) = ∑ i = 1 t i ∗ n i ∑ i = 1 t n i = ∑ i = 1 t i ∗ n i N ∑ i = 1 t n i N = ∑ i = 1 t i p i ω 1 ( t ) \mu_1(t)=\frac{\sum\limits_{i=1}^ti*n_i}{\sum\limits_{i=1}^tn_i}=\frac{\sum\limits_{i=1}^t\frac{i*n_i}{N}}{\sum\limits_{i=1}^t\frac{n_i}{N}}=\sum_{i=1}^t\frac{ip_i}{\omega_1(t)} μ1(t)=i=1∑tnii=1∑ti∗ni=i=1∑tNnii=1∑tNi∗ni=i=1∑tω1(t)ipi
同样可推导:
μ 2 ( t ) = ∑ i = t + 1 L i p i ω 2 ( t ) \mu_2(t)=\sum_{i=t+1}^L\frac{ip_i}{\omega_2(t)} μ2(t)=i=t+1∑Lω2(t)ipi
整幅图像的像素均值记为:
μ T = ∑ i L i ∗ p i = ω 1 ( t ) μ 1 ( t ) + ω 2 ( t ) μ 2 ( t ) \mu_T=\sum_i^Li*p_i=\omega_1(t)\mu_1(t)+\omega_2(t)\mu_2(t) μT=i∑Li∗pi=ω1(t)μ1(t)+ω2(t)μ2(t)
求 
     
      
       
        
        
          C 
         
        
          1 
         
        
       
         / 
        
        
        
          C 
         
        
          2 
         
        
       
      
        C_1/C_2 
       
      
    C1/C2每个簇对应的像素值方差:
  
      
       
        
         
         
           σ 
          
         
           1 
          
         
           2 
          
         
        
          ( 
         
        
          t 
         
        
          ) 
         
        
          = 
         
         
          
           
           
             ∑ 
            
            
            
              i 
             
            
              = 
             
            
              1 
             
            
           
             t 
            
           
          
            [ 
           
          
            i 
           
          
            − 
           
           
           
             μ 
            
           
             1 
            
           
          
            ( 
           
          
            t 
           
          
            ) 
           
           
           
             ] 
            
           
             2 
            
           
          
            ∗ 
           
           
           
             n 
            
           
             i 
            
           
          
          
           
           
             ∑ 
            
            
            
              i 
             
            
              = 
             
            
              1 
             
            
           
             t 
            
           
           
           
             n 
            
           
             i 
            
           
          
         
        
          = 
         
         
          
           
           
             ∑ 
            
            
            
              i 
             
            
              = 
             
            
              1 
             
            
           
             t 
            
           
           
            
            
              [ 
             
            
              i 
             
            
              − 
             
             
             
               μ 
              
             
               1 
              
             
            
              ( 
             
            
              t 
             
            
              ) 
             
             
             
               ] 
              
             
               2 
              
             
            
              ∗ 
             
             
             
               n 
              
             
               i 
              
             
            
           
             N 
            
           
          
          
           
           
             ∑ 
            
            
            
              i 
             
            
              = 
             
            
              1 
             
            
           
             t 
            
           
           
            
            
              n 
             
            
              i 
             
            
           
             N 
            
           
          
         
        
          = 
         
         
          
           
           
             ∑ 
            
            
            
              i 
             
            
              = 
             
            
              1 
             
            
           
             t 
            
           
          
            [ 
           
          
            i 
           
          
            − 
           
           
           
             μ 
            
           
             1 
            
           
          
            ( 
           
          
            t 
           
          
            ) 
           
           
           
             ] 
            
           
             2 
            
           
           
           
             p 
            
           
             i 
            
           
          
          
           
           
             ω 
            
           
             1 
            
           
          
            ( 
           
          
            t 
           
          
            ) 
           
          
         
        
       
         \sigma^2_1(t)=\frac{\sum\limits_{i=1}^t[i-\mu_1(t)]^2*n_i}{\sum\limits_{i=1}^tn_i}=\frac{\sum\limits_{i=1}^t\frac{[i-\mu_1(t)]^2*n_i}{N}}{\sum\limits_{i=1}^t\frac{n_i}{N}}=\frac{\sum\limits_{i=1}^t[i-\mu_1(t)]^2p_i}{\omega_1(t)} 
        
       
     σ12(t)=i=1∑tnii=1∑t[i−μ1(t)]2∗ni=i=1∑tNnii=1∑tN[i−μ1(t)]2∗ni=ω1(t)i=1∑t[i−μ1(t)]2pi
同样可推导:
σ 2 2 ( t ) = ∑ i = t + 1 L [ i − μ 2 ( t ) ] 2 p i ω 2 ( t ) \sigma^2_2(t)=\frac{\sum\limits_{i=t+1}^L[i-\mu_2(t)]^2p_i}{\omega_2(t)} σ22(t)=ω2(t)i=t+1∑L[i−μ2(t)]2pi
为了衡量所取阈值 t t t的二值化效果,作者定义了三种方差,分别是:
类内方差:
  
      
       
        
         
         
           σ 
          
         
           W 
          
         
           2 
          
         
        
          = 
         
         
         
           ω 
          
         
           1 
          
         
         
         
           σ 
          
         
           1 
          
         
           2 
          
         
        
          + 
         
         
         
           ω 
          
         
           2 
          
         
         
         
           σ 
          
         
           2 
          
         
           2 
          
         
        
       
         \sigma_W^2=\omega_1\sigma_1^2 + \omega_2\sigma_2^2 
        
       
     σW2=ω1σ12+ω2σ22
类间方差:
  
      
       
        
         
         
           σ 
          
         
           B 
          
         
           2 
          
         
        
          = 
         
         
         
           ω 
          
         
           1 
          
         
        
          ( 
         
         
         
           μ 
          
         
           1 
          
         
        
          − 
         
         
         
           μ 
          
         
           T 
          
         
         
         
           ) 
          
         
           2 
          
         
        
          + 
         
         
         
           ω 
          
         
           2 
          
         
        
          ( 
         
         
         
           μ 
          
         
           2 
          
         
        
          − 
         
         
         
           μ 
          
         
           T 
          
         
         
         
           ) 
          
         
           2 
          
         
        
          = 
         
         
         
           ω 
          
         
           1 
          
         
         
         
           ω 
          
         
           2 
          
         
        
          ( 
         
         
         
           μ 
          
         
           1 
          
         
        
          − 
         
         
         
           μ 
          
         
           2 
          
         
         
         
           ) 
          
         
           2 
          
         
        
       
         \sigma_B^2=\omega_1(\mu_1-\mu_T)^2 + \omega_2(\mu_2-\mu_T)^2=\omega_1\omega_2(\mu_1-\mu_2)^2 
        
       
     σB2=ω1(μ1−μT)2+ω2(μ2−μT)2=ω1ω2(μ1−μ2)2
图像总的像素值方差:
σ T 2 = ∑ i = 1 L ( i − μ T ) 2 p i \sigma_T^2=\sum_{i=1}^L(i-\mu_T)^2p_i σT2=i=1∑L(i−μT)2pi
可以推导三者之间有如下关系:
σ W 2 + σ B 2 = σ T 2 \sigma_W^2 + \sigma_B^2 = \sigma_T^2 σW2+σB2=σT2
从上面的定义可以发现, σ W 2 / σ B 2 \sigma_W^2/ \sigma_B^2 σW2/σB2于阈值 t t t有关,而 σ T 2 \sigma_T^2 σT2与阈值 t t t无关。
上面 σ W 2 \sigma_W^2 σW2是 t t t的二阶函数, σ B 2 \sigma_B^2 σB2是 t t t的一阶函数,更易优化。最后,求阈值 t t t可以变成最大化类间方差 σ B 2 \sigma_B^2 σB2
σ B 2 ( t ∗ ) = max  1 ≤ t ≤ L σ B 2 ( t ) \sigma_B^2(t^*)=\max_{1\le t\le L}\sigma_B^2(t) σB2(t∗)=1≤t≤LmaxσB2(t)
欢迎访问个人网络日志🌹🌹知行空间🌹🌹
源码实现
// Include Libraries
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
 
using namespace std;
using namespace cv;
 
int main(){
 
  // read the image in BGR format
  Mat testImage = imread("boat.jpg", 0);
int bins_num = 256;
 
// Get the histogram
long double histogram[256];
 
// initialize all intensity values to 0
for(int i = 0; i < 256; i++)
    histogram[i] = 0;
 
// calculate the no of pixels for each intensity values
for(int y = 0; y < testImage.rows; y++)
    for(int x = 0; x < testImage.cols; x++)
        histogram[(int)testImage.at<uchar>(y,x)]++;
 
// Calculate the bin_edges
long double bin_edges[256];
bin_edges[0] = 0.0;
long double increment = 0.99609375;
for(int i = 1; i < 256; i++)
    bin_edges[i] = bin_edges[i-1] + increment;
 
// Calculate bin_mids
long double bin_mids[256];
for(int i = 0; i < 256; i++)
  bin_mids[i] = (bin_edges[i] + bin_edges[i+1])/2;
 
// Iterate over all thresholds (indices) and get the probabilities weight1, weight2
long double weight1[256];
weight1[0] = histogram[0];
for(int i = 1; i < 256; i++)
  weight1[i] = histogram[i] + weight1[i-1];
 
int total_sum=0;
for(int i = 0; i < 256; i++)
    total_sum = total_sum + histogram[i];
long double weight2[256];
weight2[0] = total_sum;
for(int i = 1; i < 256; i++)
  weight2[i] = weight2[i-1] - histogram[i - 1];
 
// Calculate the class means: mean1 and mean2
long double histogram_bin_mids[256];
for(int i = 0; i < 256; i++)
  histogram_bin_mids[i] = histogram[i] * bin_mids[i];
 
long double cumsum_mean1[256];
cumsum_mean1[0] = histogram_bin_mids[0];
for(int i = 1; i < 256; i++)
  cumsum_mean1[i] = cumsum_mean1[i-1] + histogram_bin_mids[i];
 
long double cumsum_mean2[256];
cumsum_mean2[0] = histogram_bin_mids[255];
for(int i = 1, j=254; i < 256 && j>=0; i++, j--)
  cumsum_mean2[i] = cumsum_mean2[i-1] + histogram_bin_mids[j];
 
long double mean1[256];
for(int i = 0; i < 256; i++)
  mean1[i] = cumsum_mean1[i] / weight1[i];
 
long double mean2[256];
for(int i = 0, j = 255; i < 256 && j >= 0; i++, j--)
  mean2[j] = cumsum_mean2[i] / weight2[j];
 
// Calculate Inter_class_variance
long double Inter_class_variance[255];
long double dnum = 10000000000;
for(int i = 0; i < 255; i++)
  Inter_class_variance[i] = ((weight1[i] * weight2[i] * (mean1[i] - mean2[i+1])) / dnum) * (mean1[i] - mean2[i+1]); 
 
// Maximize interclass variance
long double maxi = 0;
int getmax = 0;
for(int i = 0;i < 255; i++){
  if(maxi < Inter_class_variance[i]){
    maxi = Inter_class_variance[i];
    getmax = i;
  }
}
 
cout << "Otsu's algorithm implementation thresholding result: " << bin_mids[getmax];
 
- 1.https://learnopencv.com/otsu-thresholding-with-opencv/
















