图像分割——大津法(Otsu)
大津法又叫最大类间方差法,是于1979年由日本学者大津展之提出的一种对图像进行二值化的高效算法,是在判别与最小二乘法原理的基础上推导出来的。
算法原理
把直方图在某一阈值处分割为两组,当前分成的两组间方差最大。
假设我们有一张图像,其灰度值为1~m级,灰度值 i 的像素数为 ni 。
我们可以得到
像素总数
N
=
∑
i
=
0
m
n
i
N=\sum_{i=0}^{m} n_i
N=∑i=0mni
各灰度级的概率
p
i
=
n
i
N
pi=\frac{n_i}{N}
pi=Nni。
然后用阈值T将其分为两组
C
0
=
∣
1
∽
T
∣
C_0=\mid1\backsim T\mid
C0=∣1∽T∣和
C
1
=
∣
T
+
1
∽
m
∣
C_1=\mid T+1 \backsim m \mid
C1=∣T+1∽m∣。
我们就可以得到:
C0的概率
w
0
=
w
(
T
)
=
∑
i
=
1
T
p
i
w_0=w(T)=\sum_{i=1}^T p_i
w0=w(T)=∑i=1Tpi
C1的概率
w
1
=
1
−
w
0
=
∑
i
=
T
+
1
m
p
i
w_1=1-w_0=\sum_{i=T+1}^m p_i
w1=1−w0=∑i=T+1mpi
C0的平均值
μ
0
=
μ
(
T
)
w
(
T
)
=
∑
i
=
1
T
i
∗
p
i
w
0
\mu_0=\frac{\mu(T)}{w(T)}=\sum_{i=1}^T \frac{i*p_i}{w_0}
μ0=w(T)μ(T)=∑i=1Tw0i∗pi
C1的平均值
μ
1
=
μ
−
μ
(
T
)
1
−
w
(
T
)
=
∑
i
=
T
+
1
m
i
∗
p
i
w
1
\mu_1=\frac{\mu-\mu(T)}{1-w(T)}=\sum_{i=T+1}^m \frac{i*p_i}{w_1}
μ1=1−w(T)μ−μ(T)=∑i=T+1mw1i∗pi
其中
μ
\mu
μ是整个图像的灰度平均值,
μ
=
w
0
μ
0
+
w
1
μ
1
\mu=w_0\mu_0+w_1\mu_1
μ=w0μ0+w1μ1
两组间的方差为:
δ
2
=
w
0
(
μ
0
−
μ
)
2
+
w
1
(
μ
1
−
μ
)
2
=
w
0
w
1
(
μ
1
−
μ
0
)
2
\delta^2=w_0(\mu_0-\mu)^2+w_1(\mu_1-\mu)^2=w_0w_1(\mu_1-\mu_0)^2
δ2=w0(μ0−μ)2+w1(μ1−μ)2=w0w1(μ1−μ0)2
=
[
μ
w
(
T
)
−
μ
(
T
)
]
2
w
(
T
)
[
1
−
w
(
T
)
]
= \frac{ [\mu w_(T)-\mu(T)]^2}{w(T)[1-w(T)]}
=w(T)[1−w(T)][μw(T)−μ(T)]2
实现代码:
import cv2
import numpy as np
import matplotlib.pyplot as plt
gray=cv2.imread('lenaGray.bmp',cv2.IMREAD_GRAYSCALE)
cv2.imshow('gray',gray)
N=gray.size
pro=np.array([0]*256)
for i in range(gray.shape[0]):
for j in range(gray.shape[1]):
pro[gray[i,j]]+=1
pro=pro/N
T=0
delta=0
thresh=0
while T<=256:
w0=pro[0:T].sum()
w1=pro[T+1:256].sum()
u0=(pro[0:T]*range(1,T+1)).sum()/w0
u1=(pro[T:256]*range(T+1,257)).sum()/w1
u=w0*u0+w1*u1
v=w0*w1*np.square(u1-u0)
if v>delta:
delta=v
thresh=T
T+=1
otsu=np.zeros(gray.shape,np.uint8)
for i in range(gray.shape[0]):
for j in range(gray.shape[1]):
if gray[i,j]>thresh:
otsu[i,j]=255
cv2.imshow('Otsu',otsu)
cv2.waitKey(0)
cv2.destroyAllWindows()