import cv2 as cv
import numpy as np
def adaptive_threshold(gray: np.ndarray, whs: int = None, sub_threshold: float = 0.15):
"""
基于积分图像的自适应阈值二值化算法
:param gray: 输入的灰度图像
:param whs: 滑动窗口的半宽高(默认为图像宽度的1/10)
:param sub_threshold: 自定义子阈值,需要通过实验对比确定
:return: 二值化图像
"""
# 计算积分图像
integral_image = cv.integral(gray, cv.CV_32F)
# 创建滑动窗口
height = gray.shape[0]
width = gray.shape[1]
window_half_size = int(width / 10) if whs is None else whs
binary = np.zeros((height, width), dtype=np.uint8)
# 开始二值化
for j in range(height):
for i in range(width):
# 定义滑动窗口的角点
x1 = i - window_half_size
x2 = i + window_half_size
y1 = j - window_half_size
y2 = j + window_half_size
# 检查滑动窗口的边界
x1 = 0 if x1 < 0 else x1
y1 = 0 if y1 < 0 else y1
x2 = width - 1 if x2 > width else x2
y2 = height - 1 if y2 > height else y2
count = (x2 - x1) * (y2 - y1)
# \mbox{I}_W=\mbox{I}(x_2,y_2)-\mbox{I}(x_1-1,y_2)-\mbox{I}(x_2,y_1-1)+\mbox{I}(x_1-1,y_1-1)
summed = integral_image[y2, x2] - integral_image[y1, x2] - integral_image[y2, x1] + integral_image[y1, x1]
binary[j, i] = 0 if int(gray[j, i] * count) < int(summed * (1.0 - sub_threshold)) else 255
return binary