Otsu算法(大津法)-动态阈值
Otsu算法简介
Otsu算法是一种图像二值化的算法,它的主要思想是将图像分成背景和前景两部分,背景和前景之间的差别越大越好,也就是说背景越黑,前景越白越好,这样的话,我们就可以通过阈值来将图像二值化,阈值的选取就是Otsu算法的核心。
原始论文1979:A threshold selection method from gray-level histograms
虽然Otsu算法是图像中确定阈值的方法,但也可以应用到其他方面。比如点云根据强度值进行分割,就可以使用Otsu算法。本质上Otsu就是通过统计学的方法将输入根据某个值分成两个类。
Otsu算法只能将输入分割成两类,其本质是确定一个阈值,使得用该阈值分割出来的两类的类间(between-class)方差最大,类内(within-class)方差最小。类间方差越大,说明两类之间的差别越大,类内方差越小,说明类内的差别越小。
数学形式
均值和概率
这里主要参考原始论文中的数学形式,以及维基百科中的数学形式。
假设图片中的所有像素灰度值可以分成\(L\)个等级,\([1,2,...,L]\)。比如通常对于8bit灰度图像,我们可以用256个等级表示灰度值。等级\(i\)的像素数为\(n_i\),总像素数为\(N\),\(N=n_1+n_2+\cdot\cdot\cdot+n_L\)。每个等级的像素出现的概率如下:
\[ p_i=\frac{n_i}{N}, \quad p_i\geq 0, \sum_{i=1}^{L}p_i=1\tag{1} \]
确定阈值\(k\)后可以将像素分成两类\(C_0,C_1\) \(C_0\)表示像素等级在\([1,...,k]\)的像素,\(C_1\)表示像素等级在\([k+1,...,L]\)的像素
两个类的像素比例为:
\[ \begin{aligned} &w_0=Pr(C_0)=\sum_{i=1}^{k}p_i=w(k)\\ &w_1=Pr(C_1)=\sum_{i=k+1}^{L}p_i=1-w(k)\\ \end{aligned}\tag{2} \]
并且
\[ w_0+w_1=1\tag{3} \]
两个类的平均灰度值为: \[ \begin{aligned} &\mu_0=E(C_0)=\sum_{i=1}^{k} i\cdot \frac{p_i}{w_0}=\mu(k)/w(k)\\ &\mu_1=E(C_1)=\sum_{i=k+1}^{L} i\cdot \frac{p_i}{w_1}=\frac{\mu_T - \mu(k)}{1 - w(k)}\\ \end{aligned}\tag{4} \]
其中,\(\mu(k)\)是等级为\(1-k\)像素的一阶累积矩(first-order cumulative moments),\(\mu_T\)是总的平均灰度值。
\[ \mu(k)=\sum_{i=1}^{k}i\cdot p_i\tag{5} \]
\[ \mu_T=\sum_{i=1}^{L}i\cdot p_i\tag{6} \]
\(w(k)\)是等级为\(1-k\)像素的概率和
\[ w(k)=\sum_{i=1}^{k}p_i\tag{7} \]
根据上面关系,我们还可以得到:
\[ w_0\mu_0+w_1\mu_1 = \mu_T\tag{8} \]
类内/类间方差
两个类各自的方差
根据上面的定义,我们可以得到两个类各自的方差
\[ \sigma_0^2=\sum_{i=1}^{k}(i-\mu_0)^2\cdot \frac{p_i}{w_0}\tag{9} \]
\[ \sigma_1^2=\sum_{i=k+1}^{L}(i-\mu_1)^2\cdot \frac{p_i}{w_1}\tag{10} \]
总体方差
像素总体的方差为:
\[ \sigma_T^2=\sum_{i=1}^{L}(i-\mu_T)^2\cdot p_i\tag{13} \]
类内方差
因此,我们可以得到类内(within-class)方差的公式:
\[ \sigma_w^2=w_0\sigma_0^2+w_1\sigma_1^2\tag{11} \]
类间方差
类间(between-class)方差为:
\[ \begin{aligned} \sigma_b^2&=w_0(\mu_0-\mu_T)^2+w_1(\mu_1-\mu_T)^2\\ &=w_0w_1(\mu_0-\mu_1)^2\\ &=w(k)(1-w(k))[\frac{\mu(k)}{w(k)}-\frac{\mu_T-\mu(k)}{1-w(k)}]^2\\ &=\frac{[\mu(k)(1-w(k))-(\mu_T-\mu(k))w(k)]^2}{w(k)(1-w(k))}\\ &=\frac{[\mu(k)-\mu_Tw(k)]^2}{w(k)[1-w(k)]} \end{aligned}\tag{12} \]
类内方差与类间方差的关系
根据公式(11-13),我们可以得到:
\[ \sigma_T^2=\sigma_w^2+\sigma_b^2\tag{14} \]
Otsu算法的目标
Otsu算法的目标是找到一个阈值\(k\),使得类间方差\(\sigma_b^2\)最大,也就是说,找到一个阈值\(k\),使得类内方差\(\sigma_w^2\)最小。
Otsu算法步骤
- 统计每个像素等级的像素数量,并计算每个像素等级的概率\(p_i\),\(i\in[1,...,L]\)。
- 计算每个像素等级的概率和\(w(k)\),\(k\in[1,...,L]\)。
- 计算每个像素等级的平均灰度值\(\mu(k)\),\(k\in[1,...,L]\)。
- 计算总的平均灰度值\(\mu_T\)。
- 根据公式(4)可以计算出每个像素等级的平均灰度值\(\mu_0\)和\(\mu_1\),\(k\in[1,...,L]\)。
- 遍历所有像素等级\([1,2,3...,L]\) 6.1 根据公式(12)计算类间方差\(\sigma_b^2\)。 6.2 如果\(\sigma_b^2\)大于之前的最大值,则更新最大值,并记录当前的像素等级\(k\)
算法实现-python
1 | import numpy as np |