TensorFlow CNN OCR识别波斯车牌字符错误的排查与优化咨询
波斯车牌OCR识别错误排查与优化方案
我基于FastAPI构建波斯车牌识别Web API,采用YOLOv8检测车牌边界框(检测结果正确),但自定义TensorFlow CNN模型的OCR步骤输出错误或随机字符(如输出“1سیب32لف”而非“56ب123 24”)。
当前实现流程
- 车牌检测:使用ultralytics的YOLOv8检测车牌区域,可视化验证结果正确。
- 预处理:裁剪车牌区域,应用Otsu阈值处理,通过霍夫直线校正旋转,基于固定宽度比例分割字符。
- OCR模型:训练了两个CNN模型(plate_trainer.py和hand_written_trainer.py),分别识别波斯数字(0-9)与字母(如‘ب’‘س’),当前使用simple_ocr_plates_model1.keras。
- 训练细节:基于约10000张标注字符图像(含波斯数字与字母)训练,加入旋转、缩放等数据增强,一个模型针对印刷车牌,另一个针对手写风格字符。
核心代码片段
import cv2 as cv import numpy as np import tensorflow as tf # Load CNN model ocr_model = tf.keras.models.load_model('models/simple_ocr_plates_model1.keras') class_names = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'ﺎ', 'ﺐ', ...] # 80+ Persian characters def segment_characters(cropped_img: np.ndarray, output_dir: str) -> list: h, w = cropped_img.shape chopfactors = [(40, 120), (100, 200), ...] # Scaled for plate width plate_letters = [] for i, (w1, w2) in enumerate(chopfactors): w1, w2 = int(w1 * w / 600), int(w2 * w / 600) if w1 >= w2 or w1 >= w: continue letter_patch = cropped_img[:, w1:w2] if letter_patch.shape[1] == 0: continue letter_patch_resized = cv.resize(letter_patch, (30, 30)) plate_letters.append(letter_patch_resized) return plate_letters def recognize_characters(plate_letters: list) -> list: plate_letters = np.array(plate_letters) plate_letters = np.expand_dims(plate_letters, axis=-1) / 255.0 predictions = ocr_model.predict(plate_letters, verbose=0) return [class_names[k] for k in np.argmax(predictions, axis=1)] # Example usage img = cv.imread("plate.jpg", cv.IMREAD_GRAYSCALE) # ... (cropping and rotation steps) cropped_img = adjust_cropping(rotated_img, output_dir) plate_letters = segment_characters(cropped_img, output_dir) plate_text = recognize_characters(plate_letters) print(plate_text) # Outputs: ['1', '2', '3'] instead of ['ب', '۱', '۲']
已尝试的排查动作
- 可视化分割后的字符补丁,确认字符分割正确。
- 测试两个CNN模型,印刷车牌模型表现略好,但均难以准确识别波斯字母。
- 增加数据量重新训练,验证准确率达约95%,但实际场景仍识别错误。
- 检查预处理步骤,阈值与缩放无明显问题,但怀疑归一化或分割存在隐患。
输出对比
预期:45 ب 123 11
实际:123ثثث۳ل
问题分析与优化方案
可能的原因
- 字符分割隐患:固定宽度比例分割无法适配不同车牌的字符间距、字体大小差异,波斯字符本身宽度有差异(如“ب”和“س”),固定比例易导致字符截断或包含多余背景,干扰模型识别。
- 训练数据与实际场景偏差:训练数据虽有10000张,但可能和实际场景的车牌在字体、光照、磨损、拍摄角度上差异极大——比如训练数据是清晰标准字体,实际场景存在模糊、阴影、污渍,导致验证准确率高但泛化能力差。
- 模型适配性不足:基础CNN结构可能不足以捕捉波斯字符的细微特征(如“ب”和“پ”的差异);分开训练数字、字母模型,但推理时未区分输入类型,易造成混淆。
- 预处理细节遗漏:
- 未针对性去除车牌边框、反光等噪声;
- 字符缩放时的插值方式导致边缘细节丢失;
- 未统一字符对比度、亮度,或存在方向/镜像错误。
优化措施
改进字符分割
- 替换固定比例分割为轮廓检测分割:对裁剪后的车牌做轮廓提取,过滤小噪声轮廓,按波斯文从右到左的顺序排序轮廓,提取外接矩形作为字符区域;
- 加入宽高比过滤:根据波斯车牌字符的标准宽高比,过滤不符合的轮廓,减少无效分割。
优化训练数据
- 补充实际场景样本:收集模糊、有污渍、不同光照下的车牌,裁剪字符标注后加入训练集;
- 增强针对性数据增强:加入轻微模糊、阴影、噪声模拟,以及±5度的微小旋转,提升模型泛化能力;
- 校验标注准确性:重点核查相似波斯字符(如“ث”和“ت”)的标注是否正确。
模型优化
- 更换为CRNN模型:循环卷积神经网络可处理序列字符,减少分割错误的影响,同时捕捉字符上下文信息;
- 合并数字与字母识别模型:使用单一多分类模型同时识别两类字符,避免模型切换的混淆;
- 加入注意力机制:让模型聚焦于字符的关键特征区域,提升相似字符的区分度。
完善预处理流程
- 噪声去除:阈值处理前加入高斯模糊或中值滤波;
- 优化缩放插值:使用
cv.INTER_CUBIC或cv.INTER_LANCZOS4插值,保留字符边缘细节; - 对比度增强:采用CLAHE(限制对比度自适应直方图均衡化)提升字符与背景的对比度;
- 方向校正:通过计算字符最小外接矩形角度,确保字符方向正确,无镜像或旋转错误。
推理阶段后处理
- 格式校验:根据波斯车牌的格式规则(如“数字+字母+数字+数字”结构),过滤连续相同字母等不符合规则的结果;
- 置信度过滤:只保留预测置信度高于0.8的结果,低置信度字符重新分割或标记为未知。
内容的提问来源于stack exchange,提问作者Saman Zare
相关产品推荐
相关产品推荐

