大津算法,也被称作最大类间方差法,是一种自动确定二值化阈值的算法。
在这里作者不介绍算法推导的过程,算法推导过程网络上有许多介绍,这里只给出算法最终推导出的结论:
使得左侧 的值最大,就可以得到最好的二值化阈值 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
输出图像在此不予展示