4. 指纹图像二值化
任务说明
本案例将上一阶段增强处理后的指纹灰度图像转换为二值图像,使脊线(纹线凸起部分)与谷线(纹线间凹陷部分)分离为黑白两色,为后续细化和特征提取提供清晰的输入。输入为8位灰度指纹图像,输出为单通道二值图像(0或255)。
实现方案
采用全局阈值与局部自适应阈值相结合的策略:先使用Otsu方法计算全局最优阈值,再对图像分块计算局部均值,通过加权融合得到每个像素的最终阈值,从而兼顾光照不均和脊线粗细变化的影响。核心处理流程如下:
- 读取灰度指纹图像;
- 使用Otsu算法计算全局阈值;
- 将图像划分为16×16像素的块,计算每块均值作为局部阈值;
- 对每个像素,将全局阈值与所在块局部阈值按权重0.5:0.5融合,得到自适应阈值;
- 像素值大于等于阈值置255(脊线),否则置0(谷线)。
代码实现
import cv2
import numpy as np
def adaptive_binarize(image_path, block_size=16, weight_global=0.5):
"""
指纹图像自适应二值化
:param image_path: 输入灰度图像路径
:param block_size: 局部块大小(像素)
:param weight_global: 全局阈值权重,局部阈值权重 = 1 - weight_global
:return: 二值图像 (0和255)
"""
# 读取灰度图
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
if img is None:
raise ValueError(f"无法读取图像: {image_path}")
# 1. Otsu全局阈值
_, t_global = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 2. 分块局部均值
h, w = img.shape
t_local = np.zeros_like(img, dtype=np.float32)
for y in range(0, h, block_size):
for x in range(0, w, block_size):
block = img[y:y+block_size, x:x+block_size]
block_mean = np.mean(block)
t_local[y:y+block_size, x:x+block_size] = block_mean
# 3. 阈值融合
weight_local = 1.0 - weight_global
threshold_map = weight_global * t_global + weight_local * t_local
# 4. 像素比较生成二值图
binary = np.where(img >= threshold_map, 255, 0).astype(np.uint8)
return binary
if __name__ == "__main__":
# 输入增强后的指纹图像(示例路径,请替换为实际文件)
input_path = "enhanced_fingerprint.png"
output_path = "binary_fingerprint.png"
result = adaptive_binarize(input_path, block_size=16, weight_global=0.5)
cv2.imwrite(output_path, result)
print(f"二值化完成,结果已保存至: {output_path}")
落地与验证
运行环境:Python 3.8+,需安装OpenCV(pip install opencv-python numpy)。
执行方式:将增强后的指纹图像命名为enhanced_fingerprint.png放在脚本同目录,运行python binarize.py,输出文件为binary_fingerprint.png。
验证方法:用图像查看工具打开输出图像,观察脊线是否呈现为连续白色纹路、谷线为黑色背景。可通过以下客观指标辅助判定:
- 计算二值图像中白色像素占比,正常指纹脊线占比约30%~45%;
- 沿垂直于脊线方向取一条像素剖面,应观察到黑白交替的方波模式,且脊线宽度(白色连续段)在5~15像素范围内;
- 若图像中出现大面积全黑或全白区域,或脊线断裂严重,可调整
block_size(8~32)或weight_global(0.3~0.7)后重新运行。
判定标准:输出图像中脊线连续、谷线清晰分离,无大面积噪声块,且上述占比与剖面检查符合指纹形态特征,即视为通过。