Otsu 阈值算法


Otsu 阈值算法的简单实现

1. 什么是 Otsu 阈值算法

Otsu 阈值算法是一种自适应阈值分割算法,用于将图像分割为前景和背景。核心思想是通过最大化类间方差来确定最佳阈值。

Otsu 阈值算法的基本思想是:通过计算图像的灰度直方图,找到一个阈值,使得前景和背景的类间方差最大。

2. 算法步骤

  1. 计算图像的灰度直方图:
    • 图像的像素值被划分为若干个灰度级,计算每个灰度级的像素数。
    • 计算每个灰度级的像素数占总像素数的比例。
  2. 计算前景和背景的类间方差
    • 对每个可能的阈值,将图像的像素值划分为前景和背景。
    • 计算这两部分的灰度均值、像素比例和类间方差。
    • 寻找使类间方差最大的阈值。

3. 数学表达

  • 假设总像素数为 \(N\),灰度值的范围为 \([0, L-1]\),灰度级 \(k\) 的像素数为 \(n_k\),灰度级 \(k\) 的像素数占总像素数的比例为 \(p_k\)
  • 对于x给定的阈值\(t\),灰度值被分为两类:
    • 前景类\(C_1\),灰度值在\([0, t]\)之间
    • 背景类\(C_2\),灰度值在\([t+1, L-1]\)之间
  • 前景类的像素数比例:\(w_1 = \sum_{i=0}^{t} p_i\)
  • 背景类的像素数比例:\(w_2 = \sum_{i=t+1}^{L-1} p_i\)
  • 前景类的灰度均值:\(u_1 = \sum_{i=0}^{t} i p_i / w_1\)
  • 背景类的灰度均值:\(u_2 = \sum_{i=t+1}^{L-1} i p_i / w_2\)
  • 类间方差:\(\sigma_b^2 = w_1 w_2 (u_1 - u_2)^2\)

4. 代码实现

  • 简洁实现,使用opencv计算灰度直方图

    def otsu_threshold(image):
        # 计算灰度直方图
        hist = cv2.calcHist([image], [0], None, [256], [0, 256]) # 计算灰度直方图
        hist = hist.ravel() / hist.sum() # 计算灰度直方图的概率
    
        # 计算前景和背景的类间方差
        max_var = 0
        best_threshold = 0
        for threshold in range(256):
            w1 = np.sum(hist[:threshold])
            w2 = np.sum(hist[threshold+1:])
            u1 = np.sum(hist[:threshold] * np.arange(256)) / w1
            u2 = np.sum(hist[threshold+1:] * np.arange(threshold+1, 256)) / w2
            var = w1 * w2 * (u1 - u2) ** 2
            if var > max_var:
                max_var = var
                best_threshold = threshold
    return best_threshold

  • 一般数据的分割

    def _otsu_threshold(data):
        hist, bins = np.histogram(data, bins=50) # 可以指定bins的数量t
        bin_centers = (bins[:-1] + bins[1:]) / 2
        
        # OTSU算法实现
        total = hist.sum()
        sum_total = sum(bin_centers * hist)
        
        max_variance = 0
        threshold = 0
        
        sum_b = 0
        count_b = 0
        
        for i in range(len(hist)):
            count_b += hist[i]
            if count_b == 0:
                continue
                
            count_f = total - count_b
            if count_f == 0:
                break
                
            sum_b += bin_centers[i] * hist[i]
            mean_b = sum_b / count_b
            mean_f = (sum_total - sum_b) / count_f
            
            variance = count_b * count_f * (mean_b - mean_f) ** 2
            if variance > max_variance:
                max_variance = variance
                threshold = bin_centers[i]
                
        return threshold


文章作者: 庞贝堡垒
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 庞贝堡垒 !
评论
  目录