对于给定的阈值\(T\),可以将图像分为目标和背景。其中背景点数占图像比例为 \(p_0\),平均灰度值为 \(m_0\)。而目标点数占图像比例为 \(p_1\),平均灰度值为 \(m_1\),其中满足
\[p_0 + p_1 = 1
\]
整幅图像的平均灰度值为常数,跟阈值无关,且为
\[\overline m = p_0m_0 + p_1m_1
\]
类间方差为
\[\sigma^2 = p_0(m_0 - \overline m)^2 + p_1(m_1 - \overline m)^2
\]
代入 \(p_0 + p_1 = 1\) 和 \(\overline m\),可化简为
\[\sigma^2 = p_0p_1(m_0 - m_1)^2
\]
遍历灰度值,找出能使 \(\sigma^2\) 最大的值。
大津法步骤
(1) 初始化方差为 \(S = -1\);
(2) 对灰度值为 \(0~255\) 的整数的图像, 遍历每个灰度值 \(T\),每次做第(3)步操作;
(3) 计算以 \(T\) 为阈值时候的类间方差,如果大于 \(S\),更新 \(S\) 并记录 \(T\);
(4) 获得使类间方差最大的 \(S\)。
效果
![drawing](https://img2020.cnblogs.com/blog/2014621/202103/2014621-20210328184810416-409244712.jpg)
实现
1. 调用 OpenCV库
img = cv.imread(img_path, 0) # img_path 为图片路径
th, img_bin = cv.threshold(img, -1, 255, cv.THRESH_OTSU) # img_bin 为二值化结果
2. 自己实现
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
def show(img):
if img.ndim == 2:
plt.imshow(img, cmap='gray')
else:
img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
plt.imshow(img)
plt.show()
# 正式开始
img = cv.imread('pic/eagle500x500.jpg', 0)
Sigma = -1
T = 0
for t in range(0, 256):
bg = img[img <= t]
obj = img[img > t]
p0 = bg.size / img.size
p1 = obj.size / img.size
m0 = 0 if bg.size == 0 else bg.mean()
m1 = 0 if obj.size == 0 else obj.mean()
sigma = p0 * p1 * (m0 - m1)**2
if sigma > Sigma:
Sigma = sigma
T = t
T = int(T)
# 此时 T 即为最佳阈值
print(f"Best threshold = {T}")
说明:
- 未经许可,谢绝转载。
- 本教程为《数字图像处理Python OpenCV实战》的配套代码相关内容。
免费视频教程为0-6章(标题号≤6),可在此处点击观看。
所有课件及源代码可在此处下载:
链接:https://pan.baidu.com/s/198PySe_vebO3e06idHSQ6g
提取码:11o4
有问题可在QQ群(1079300899)指出,进群答案:数字图像处理。在本文评论指出可能导致回复很晚。