大津算法,也被称作最大类间方差法,是一种自动确定二值化阈值的算法。
在这里作者不介绍算法推导的过程,算法推导过程网络上有许多介绍,这里只给出算法最终推导出的结论:
使得左侧 的值最大,就可以得到最好的二值化阈值 t
其中,和 是被阈值分开的两个类中的像素数占总像素数的比率。和 分别是这两个类的像素值的平均值。
废话不多说,直接上python代码:
import cv2
import numpy as np
def BGR2GRAY(img):
b = img[:, :, 0].copy()
g = img[:, :, 1].copy()
r = img[:, :, 2].copy()
# Gray scale
out = 0.2126 * r + 0.7152 * g + 0.0722 * b
out = out.astype(np.uint8)
return out
# Otsu Binarization
def otsu_binarization(img, th=128):
max_sigma = 0
max_t = 0
# determine threshold
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
# Binarization
print("threshold >>", max_t)
th = max_t
out[out < th] = 0
out[out >= th] = 255
return out
# Read image
img = cv2.imread("../paojie.jpg").astype(np.float32)
H, W, C =img.shape
# Grayscale
out = BGR2GRAY(img)
# Otsu's binarization
out = otsu_binarization(out)
# Save result
cv2.imwrite("out.jpg", out)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()
输出:
threshold >> 157
原图
大津二值化后图像
当然,opencv已经为我们实现了 Otsu's binarization 算法,我们可以直接调用它:
import cv2
import numpy as np
def BGR2GRAY(img):
b = img[:, :, 0].copy()
g = img[:, :, 1].copy()
r = img[:, :, 2].copy()
# Gray scale
out = 0.2126 * r + 0.7152 * g + 0.0722 * b
out = out.astype(np.uint8)
return out
# Read image
img = cv2.imread("../paojie.jpg").astype(np.float32)
# Grayscale
out = BGR2GRAY(img)
# Otsu's binarization of Opencv
ret2,th2 = cv2.threshold(out,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
print("threshold >>", ret2)
# Save result
cv2.imwrite("out.jpg", th2)
cv2.imshow("result", th2)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果类似
threshold >> 156.0
输出图像在此不予展示
参考:https://www.cnblogs.com/wojianxin/p/12493658.html
参考:https://www.jianshu.com/p/67522af22197