提示:内容整理自:https://github.com/gzr2017/ImageProcessing100Wen
CV小白从0开始学数字图像处理
04大津二值化算法(Otsu’s Method)
使用大津算法来二值化图像。大津算法,也被称作最大类间方差法,是一种可以自动确定二值化中阈值的算法,从类内方差和类间方差的比值计算得来:
- 小于阈值 t 的类记作 0,大于阈值 t 的类记作 1;
- w0 和 w1 是被阈值 t 分开的两个类中的像素数占总像素数的比率(满足 w0+w1=1);
- S0^2, S1^2 是这两个类中像素值的方差;
- M0, M1 是这两个类的像素值的平均值;
也就是说:
类内方差:Sw^2 = w0 * S0^2 + w1 * S1^2
类间方差:Sb^2 = w0 * (M0 - Mt)^2 + w1 * (M1 - Mt)^2 = w0 * w1 * (M0 - M1) ^2
图像所有像素的方差:St^2 = Sw^2 + Sb^2 = (const)
根据以上的式子,我们用以下的式子计算分离度:
分离度 X = Sb^2 / Sw^2 = Sb^2 / (St^2 - Sb^2)
也就是说:
argmax_{t} X = argmax_{t} Sb^2
换言之,如果使 Sb^2 = w0 * w1 * (M0 - M1) ^2 最大,就可以得到最好的二值化阈值 t。
代码如下:
1.引入库
CV2计算机视觉库
import cv2
import numpy as np
2.读入数据
img = cv2.imread("imori.jpg").astype(np.float)
H, W, C = img.shape
3.灰度化
out = 0.2126 * img[..., 2] + 0.7152 * img[..., 1] + 0.0722 * img[..., 0]
out = out.astype(np.uint8)
4.确定阈值
max_sigma = 0
max_t = 0
for _t in range(1, 255):
v0 = out[np.where(out < _t)]
m0 = np.mean(v0) if len(v0) > 0 else 0.
w0 = len(v0) / (H * W)
v1 = out[np.where(out >= _t)]
m1 = np.mean(v1) if len(v1) > 0 else 0.
w1 = len(v1) / (H * W)
sigma = w0 * w1 * ((m0 - m1) ** 2)
if sigma > max_sigma:
max_sigma = sigma
max_t = _t
5.二值化
print("threshold >>", max_t)
th = max_t
out[out < th] = 0
out[out >= th] = 255
6.保存结果
cv2.imwrite("out.jpg", out)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()