init repo
This commit is contained in:
128
ocr_captcha.py
Normal file
128
ocr_captcha.py
Normal file
@@ -0,0 +1,128 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user