数字图像处理之阈值分割
1.直方图阈值分割
算法描述:根据图像灰度直方图,人工寻找阈值
算法特点:适用于双峰直方图
代码
1 2 3 4 5 6 7 8 9 10 11
| plt.hist(img.ravel(), 256, [0, 256]) plt.show()
plt.hist(img.flatten(), np.arange(-0.5, 256, 1), color='g') plt.show()
_, img_bin = cv.threshold(img, 125, 255, cv.THRESH_BINARY) _, img_bin = cv.threshold(img, 125, 255, cv.THRESH_BINARY_INV) show(img_bin)
show(img_bin)
|
2.三角法阈值分割
算法思想:几何法,适用单峰图像
1 2 3
| th, img_bin = cv.threshold(img, 0, 255, cv.THRESH_TRIANGLE) print(th) show(np.hstack([img, img_bin]))
|
3.迭代法阈值分割
算法步骤:
- 选取初始分割阈值,通常可选取图像灰度平均值T
- 根据阈值T将图像像素分割为前景和背景,分别求出两者平均灰度T~0~和T~1~
- 计算新域值T` = (T~0~+T~1~) /2
- 若T==T’,则迭代结束,T为最终值。否则令T == T’ 转第(2)步
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| img = cv.imread('pic/eagle500x500.jpg', 0)
T = img.mean()
while True: t0 = img[img < T].mean() t1 = img[img >= T].mean() t = (t0 + t1) / 2 if abs(T - t) < 1: break T = t T = int(T)
print(f"Best threshold = {T}")
|
4.大津法阈值分割
算法思想:最大类间方差法
对于初始阈值T,可以将图像分为目标和背景,其中背景占图像比例为p0,平均值为m0,而目标点数占图像比例为p1,平均值为m1
类间方差为:
带入p~0~+p~1~=1
遍历灰度值,找出能使σ最大的值
1 2 3 4
| th, img_bin = cv.threshold(img, -1, 255, cv.THRESH_OTSU) print(th) show(img_bin)
|
代码复现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 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 print(f"Best threshold = {T}")
|
5.自适应阈值分割
算法思想:局部二值化
全局二值化容易受阴影影响,所以可以使用局部二值化
- 对某像素值,原来为S,取其周围nxn的区域,求区域均值或高斯加权值,记为T
- 如果S>T,则该点为255,否则为0
1 2 3
| img_bin = cv.adaptiveThreshold(img, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY, 21, 6)
show(img_bin)
|
算法复现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| img = cv.imread('pic/page760x900.jpg', 0)
C = 6 winSize = 21
img_blur = cv.blur(img, (winSize, winSize)) img_bin = np.uint8(img > img_blur.astype(np.int) - C) * 255
show(img_bin)
img = cv.imread('pic/page760x900.jpg', 0)
alpha = 0.05 winSize = 21
img_blur = cv.GaussianBlur(img, (winSize, winSize), 5) img_bin = np.uint8(img > (1 - alpha) * img_blur) * 255
show(img_bin)
|