Files
20260324-42433647/ocr_captcha.py
2026-04-25 21:50:03 +08:00

129 lines
3.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
验证码识别脚本
输入:验证码图片路径
输出:识别结果(打印到 stdout
预处理流程:
1. 灰度化
2. 去除水平干扰线(形态学开运算)
3. 二值化
4. 去噪
5. ddddocr 识别
"""
import sys
import cv2
import numpy as np
import ddddocr
def preprocess(img_path):
"""多种预处理方案"""
img = cv2.imread(img_path)
if img is None:
return []
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
results = []
# 方案1去水平线 + 二值化
# 用水平核做形态学开运算,提取水平线
h_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25, 1))
h_lines = cv2.morphologyEx(gray, cv2.MORPH_OPEN, h_kernel)
# 从原图减去水平线
no_lines = cv2.subtract(gray, h_lines)
# 二值化
_, binary1 = cv2.threshold(no_lines, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
results.append(binary1)
# 方案2自适应阈值
adaptive = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2)
results.append(adaptive)
# 方案3去水平线 + 自适应阈值
adaptive2 = cv2.adaptiveThreshold(no_lines, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2)
results.append(adaptive2)
# 方案4反色 + 去线 + 二值化
inverted = cv2.bitwise_not(gray)
h_lines_inv = cv2.morphologyEx(inverted, cv2.MORPH_OPEN, h_kernel)
no_lines_inv = cv2.subtract(inverted, h_lines_inv)
_, binary4 = cv2.threshold(no_lines_inv, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
results.append(binary4)
# 方案5中值滤波去噪 + OTSU
median = cv2.medianBlur(gray, 3)
_, binary5 = cv2.threshold(median, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
results.append(binary5)
# 方案6放大 + 去线 + 锐化
big = cv2.resize(gray, None, fx=3, fy=3, interpolation=cv2.INTER_CUBIC)
h_kernel_big = cv2.getStructuringElement(cv2.MORPH_RECT, (75, 1))
h_lines_big = cv2.morphologyEx(big, cv2.MORPH_OPEN, h_kernel_big)
no_lines_big = cv2.subtract(big, h_lines_big)
_, binary6 = cv2.threshold(no_lines_big, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 去小噪点
kernel_small = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))
binary6 = cv2.morphologyEx(binary6, cv2.MORPH_OPEN, kernel_small)
results.append(binary6)
# 方案7原图直接用
results.append(gray)
# 方案8: 原始彩色图ddddocr 有时对彩色图效果更好)
results.append(img)
return results
def main():
if len(sys.argv) < 2:
print("用法: python3 ocr_captcha.py <图片路径>", file=sys.stderr)
sys.exit(1)
img_path = sys.argv[1]
ocr = ddddocr.DdddOcr(show_ad=False)
# 先直接用原图试
with open(img_path, 'rb') as f:
raw_result = ocr.classification(f.read())
if raw_result and len(raw_result) == 4 and raw_result.isalnum():
print(raw_result)
return
# 多种预处理方案
preprocessed = preprocess(img_path)
best = raw_result
for i, processed in enumerate(preprocessed):
try:
if len(processed.shape) == 3:
_, buf = cv2.imencode('.png', processed)
else:
_, buf = cv2.imencode('.png', processed)
result = ocr.classification(buf.tobytes())
if result and len(result) == 4 and result.isalnum():
print(result)
return
# 记录最佳结果
if result and len(result) >= 3 and (not best or len(result) == 4):
best = result
except Exception:
continue
# 返回最佳结果
if best:
print(best[:4] if len(best) > 4 else best)
else:
print("FAIL", file=sys.stderr)
sys.exit(1)
if __name__ == '__main__':
main()