算法步骤

全局二值化容易受阴影影响,所以可以局部二值化。自适应阈值分割的本质就是局部二值化。
具体操作步骤如下:
(1) 对某个像素值,原来为 \(S\),取其周围的 \(n\times n\) 的区域,求区域均值或高斯加权值,记为 \(T\)
(2) 对 \(8\) 位图像,如果 \(S > T\),则该像素点二值化为 \(255\), 否则为 \(0\)
优化:
(1) 在实际操作中,通过卷积操作,即均值模糊或高斯模糊,实现求区域均值或高斯加权值;
(2) 上面步骤中,增加超参数 \(C\)\(C\) 可以为任何实数,当 \(S > T- C\) 时,把原像素二值化为 \(255\)
(3) 也可以设置超参数 \(\alpha\in [0,1]\),当 \(S > (1-\alpha) T\) 时把原像素点二值化为 \(255\),通常取 \(\alpha=0.15\)

效果

左图为原始灰度图,右图为自适应阈值化结果。
drawing

实现

1. 调用OpenCV函数

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

img = cv.imread(img_path, 0) # img_path 为图像路径
img_bin = cv.adaptiveThreshold(img, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, 
                            cv.THRESH_BINARY, 21, 6)

plt.imshow(np.hstack([img, img_bin]), cmap='gray')
plt.show()

2. 自己实现

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

img = cv.imread(img_path, 0) # img_path 换为图片路径

C = 6
winSize = 21

img_blur = cv.blur(img, (winSize, winSize))
img_bin = np.uint8(img > img_blur.astype(np.int) - C) * 255 # 此时的 img_bin 即为最终阈值化结果

3. 自己实现(方法二)

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

img = cv.imread(img_path, 0) # img_path 换为图片路径

alpha = 0.05
winSize = 21

img_blur = cv.GaussianBlur(img, (winSize, winSize), 5)
img_bin = np.uint8(img > (1 - alpha) * img_blur) * 255 # 此时的 img_bin 即为最终阈值化结果

说明:

  1. 未经许可,谢绝转载。
  2. 本教程为《数字图像处理Python OpenCV实战》的配套代码相关内容。
    免费视频教程为0-6章(标题号≤6),可在此处点击观看。
    所有课件及源代码可在此处下载:
    链接:https://pan.baidu.com/s/198PySe_vebO3e06idHSQ6g
    提取码:11o4
    有问题可在QQ群(1079300899)指出,进群答案:数字图像处理。在本文评论指出可能导致回复很晚。