在验证码设计中,常见的一种防护方式是字符粘连:多个字符之间没有明显的空隙,甚至部分笔画重叠。这种情况使得传统 OCR 很难直接识别。本文将介绍一种基于投影分析与轮廓分割的处理流程,帮助我们从粘连验证码中分离出独立字符。
一、问题分析
粘连验证码的典型特征:
字符之间边界模糊,甚至部分笔画重叠;
更多内容访问ttocr.com或联系1436423940
简单的二值化无法区分不同字符;
OCR 在整体输入下容易输出错误结果。
解决思路:
通过二值化得到字符轮廓;
对二值图像进行垂直投影,寻找字符间的“谷值”;
在谷值附近切割,得到单个字符;
再逐一送入 OCR 识别。
二、实现步骤(Python 示例)
-
导入依赖
import cv2
import numpy as np
from matplotlib import pyplot as plt
import pytesseract -
读取与灰度化
img = cv2.imread("captcha_stick.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, binary = cv2.threshold(gray, 128, 255, cv2.THRESH_BINARY_INV)
cv2.imwrite("step1_binary.png", binary)
- 垂直投影计算
h, w = binary.shape
projection = np.sum(binary, axis=0)
plt.plot(projection)
plt.title("Vertical Projection")
plt.savefig("step2_projection.png")
- 根据投影谷值分割字符
找出投影中接近 0 的区域,作为切割点
threshold = np.max(projection) * 0.2
cuts = []
in_gap = False
for x, val in enumerate(projection):
if val < threshold and not in_gap:
cuts.append(x)
in_gap = True
elif val >= threshold and in_gap:
cuts.append(x)
in_gap = False
切割并保存字符
chars = []
for i in range(0, len(cuts)-1, 2):
roi = binary[:, cuts[i]:cuts[i+1]]
chars.append(roi)
cv2.imwrite(f"char_{i//2}.png", roi)
- OCR 单字符识别
for i, c in enumerate(chars):
text = pytesseract.image_to_string(c, config="--psm 10 --oem 3 -c tessedit_char_whitelist=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")
print(f"字符{i}: {text.strip()}")