跳至主要內容

使用Matlab/Python实现Otsu算法

Vang-z算法图像MatlabPython约 965 字大约 3 分钟...

摘要

Otsu算法open in new window[1]是在1979年提出的, 它通过最大化类间方差来对图像进行分割。换句话说, Otsu算法是一种非参数分割方法, 根据像素的强度将图像分成不同的区域。本文将分为两个部分来介绍Otsu算法, 首先通过回顾文献中数学公式理解Otsu算法的原理, 最后再使用Matlabopen in new window/Pythonopen in new window实现其细节。

数学描述[2]

假设 LL 是一个 MNM*N 大小的图像的像素强度级别:

n=n0+n1+...+nL1 n = n_0 + n_1 + ... + n_{L-1}

Phi=nin,i=0L1Phi=1 Ph_i = \frac{n_i}{n}, \sum_{i=0}^{L-1}Ph_i=1

其中, nn 表示图像像素的总数, nin_i 表示强度级别 ii 的像素数, 所有强度级别的概率分布由 PhiPh_i 表示。

考虑二分类问题时, 假设存在一个阈值 thth, 其中 thth 介于 00L1L-1 之间, 那么图像可以根据 thth 分为两个类别, 第一个类别 C1C_1 包含所有像素强度级别在 00 ~ thth 之间的像素,而 C2C_2 包含剩余的像素。

ω1(th)=i=0thPhi,ω2(th)=i=th+1L1Phi=1Ph1(th) \omega_1(th) = \sum_{i=0}^{th}Ph_i, \omega_2(th) = \sum_{i=th+1}^{L-1}Ph_i = 1 - Ph_1(th)

其中, ω1(th)\omega_1(th)ω2(th)\omega_2(th) 分别表示 C1C_1C2C_2 的累积概率分布。

μ1(th)=i=0thiP(iC1)=i=0thiP(C1i)P(i)P(C1)=1ω1(th)i=0thiPhi \mu_1(th) = \sum_{i=0}^{th}iP(i|C_1) = \sum_{i=0}^{th}\frac{iP(C_1|i)P(i)}{P(C_1)} = \frac{1}{\omega_1(th)}\sum_{i=0}^{th}iPh_i

μ2(th)=i=th+1L1iP(iC2)=i=th+1L1iP(C2i)P(i)P(C2)=1ω2(th)i=th+1L1iPhi \mu_2(th) = \sum_{i=th+1}^{L-1}iP(i|C_2) = \sum_{i=th+1}^{L-1}\frac{iP(C_2|i)P(i)}{P(C_2)} = \frac{1}{\omega_2(th)}\sum_{i=th+1}^{L-1}iPh_i

μth=i=0thiPhi,μT=i=0L1iPhi \mu_th = \sum_{i=0}^{th}iPh_i, \mu_T = \sum_{i=0}^{L-1}iPh_i

其中, μ1(th)\mu_1(th)μ2(th)\mu_2(th) 分别表示 C1C_1C2C_2 的平均像素强度。μth\mu_th 表示从 00 ~ thth 的平均像素强度。μT\mu_T 表示整个图像的平均像素强度。因此, 最大化类别间方差的目标函数如下所示:

ω1(th)+ω2(th)=1 \omega_1(th) + \omega_2(th) = 1

ω1(th)μ1(th)+ω2(th)μ2(th)=μT \omega_1(th) \cdot \mu_1(th) + \omega_2(th) \cdot \mu_2(th) = \mu_T

δB2(th)=max{δB2(th)},0thL1 \delta_B^2(th^*) = max\{\delta_B^2(th)\}, 0 \leq th \leq L-1

根据上述公式, 我们可以在 00 ~ L1L-1 中找到一个 thth^* 来最大化 σB2σ_B^2 , 从而实现有效的图像分割。

代码实现

function fit = otsu(N, level, x, prob)
    fit = zeros(1, N);
    for j = 1:N
        fit(j) = sum(prob(1:x(j, 1) - 1)) * (sum((1:x(j, 1) - 1) .* ... 
                 prob(1:x(j, 1) - 1) / sum(prob(1:x(j, 1) - 1))) - ...
                 sum((1:255) .* prob(1:255)) ) ^ 2;
        for jlevel = 2:level - 1
            fit(j) = fit(j) + sum(prob(x(j, jlevel - 1):x(j, jlevel) - 1)) * ...
                     (sum((x(j, jlevel - 1):x(j, jlevel) - 1) .* ...
                     prob(x(j, jlevel - 1):x(j, jlevel) - 1) / ...
                     sum(prob(x(j, jlevel - 1):x(j, jlevel) - 1))) - ...
                     sum((1:255) .* prob(1:255))) ^ 2;
        end
        fit(j) = fit(j) + sum(prob(x(j, level - 1):255)) * ...
                 (sum((x(j, level - 1):255) .* prob(x(j, level - 1):255) / ...
                 sum(prob(x(j, level - 1):255))) - sum((1:255) .* prob(1:255))) ^ 2;
        if isnan(fit(j)) || isinf(fit(j))
            fit(j) = eps;
        end
    end
    fit = fit';
end

参考文献


  1. Otsu, N. A threshold selection method from gray-level histograms. IEEE transactions on systems, 9, 62-66 (1979).open in new window ↩︎

  2. Wang, Z., Mo, Y. & Cui, M. An Efficient Multilevel Threshold Image Segmentation Method for COVID-19 Imaging Using Q-Learning Based Golden Jackal Optimization. J Bionic Eng, 20, 2276–2316 (2023).open in new window ↩︎

评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.8