使用OpenCV与Pytesseract实现车牌识别失败求助
车牌识别代码问题排查与解决
核心问题分析
从代码逻辑和输出结果来看,无法识别到正确车牌的根源是轮廓筛选与裁剪逻辑错误,导致没有定位到真正的车牌区域,后续Tesseract自然无法输出有效识别结果。
具体问题点及修复方案
1. 循环过早终止,未遍历候选轮廓
代码在for c in cnts循环中,处理第一个轮廓后就执行break直接跳出循环,完全没有机会遍历后续轮廓去寻找符合矩形特征的车牌区域,这也是裁剪图显示无关区域的原因。
修复:
将break移到找到符合四边形条件的轮廓之后,确保只在定位到车牌时才终止循环:
i = 7 found_plate = False for c in cnts: perimeter = cv2.arcLength(c, True) approx = cv2.approxPolyDP(c, 0.02 * perimeter, True) if len(approx) == 4: screenCnt = approx # 裁剪并保存车牌区域 x, y, w, h = cv2.boundingRect(c) new_img = image[y:y+h, x:x+w] cv2.imwrite('./'+str(i)+'.png', new_img) found_plate = True break # 找到目标轮廓后再跳出
2. 轮廓绘制代码被阻断
原代码中绘制车牌轮廓的cv2.drawContours语句位于break之后,永远不会被执行,导致无法直观看到车牌定位效果。需将这部分代码移到找到screenCnt的逻辑块内:
if len(approx) == 4: screenCnt = approx # 绘制车牌轮廓 cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 3) cv2.imshow("image with detected license plate", image) cv2.waitKey(0) # 后续裁剪逻辑...
3. Tesseract识别缺少预处理优化
即使定位到车牌区域,直接用原图识别准确率极低,需对裁剪后的图像做增强处理:
Cropped_loc = './7.png' cropped_img = cv2.imread(Cropped_loc) # 预处理步骤:转灰度+二值化+去噪 gray_crop = cv2.cvtColor(cropped_img, cv2.COLOR_BGR2GRAY) _, thresh_crop = cv2.threshold(gray_crop, 127, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) thresh_crop = cv2.medianBlur(thresh_crop, 3) # 调用Tesseract时添加配置,限制识别范围和模式 plate = pytesseract.image_to_string(thresh_crop, lang='eng', config='--psm 8 --oem 3 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') print("Number plate is:", plate.strip())
其中config参数作用:
--psm 8:指定识别单个文本块tessedit_char_whitelist:仅允许识别字母和数字,过滤无关干扰字符
4. 轮廓近似参数可微调
原代码中cv2.approxPolyDP的0.018 * perimeter精度可能不匹配测试图,可尝试调整为0.02 * perimeter或0.015 * perimeter,找到最适合的轮廓近似度。
完整修复后代码示例
import cv2 import imutils import pytesseract pytesseract.pytesseract.tesseract_cmd = '/usr/bin/tesseract' image = cv2.imread('test.jpg') image = imutils.resize(image, width=300) cv2.imshow("original image", image) cv2.waitKey(0) gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) cv2.imshow("greyed image", gray_image) cv2.waitKey(0) gray_image = cv2.bilateralFilter(gray_image, 11, 17, 17) cv2.imshow("smoothened image", gray_image) cv2.waitKey(0) edged = cv2.Canny(gray_image, 30, 200) cv2.imshow("edged image", edged) cv2.waitKey(0) cnts, new = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) image1 = image.copy() cv2.drawContours(image1, cnts, -1, (0, 255, 0), 3) cv2.imshow("contours", image1) cv2.waitKey(0) cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:30] screenCnt = None image2 = image.copy() cv2.drawContours(image2, cnts, -1, (0, 255, 0), 3) cv2.imshow("Top 30 contours", image2) cv2.waitKey(0) i = 7 found_plate = False for c in cnts: perimeter = cv2.arcLength(c, True) approx = cv2.approxPolyDP(c, 0.02 * perimeter, True) if len(approx) == 4: screenCnt = approx # 绘制车牌轮廓 cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 3) cv2.imshow("image with detected license plate", image) cv2.waitKey(0) # 裁剪车牌区域 x, y, w, h = cv2.boundingRect(c) new_img = image[y:y+h, x:x+w] cv2.imwrite('./'+str(i)+'.png', new_img) found_plate = True break if not found_plate: print("未检测到车牌轮廓") else: Cropped_loc = './7.png' cropped_img = cv2.imread(Cropped_loc) cv2.imshow("cropped", cropped_img) cv2.waitKey(0) # 预处理裁剪后的图像 gray_crop = cv2.cvtColor(cropped_img, cv2.COLOR_BGR2GRAY) _, thresh_crop = cv2.threshold(gray_crop, 127, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) thresh_crop = cv2.medianBlur(thresh_crop, 3) cv2.imshow("processed plate", thresh_crop) cv2.waitKey(0) # 调用Tesseract识别 plate = pytesseract.image_to_string(thresh_crop, lang='eng', config='--psm 8 --oem 3 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') print("Number plate is:", plate.strip()) cv2.destroyAllWindows()
额外优化建议
- 可添加车牌宽高比判断(通常车牌宽高比在2:1到5:1之间),进一步筛选轮廓:
aspect_ratio = float(w)/h if 2 < aspect_ratio < 5 and len(approx) == 4: # 符合特征,进行后续处理 - 调整
Canny边缘检测阈值(比如改为(50, 150)),提升边缘识别准确性
内容的提问来源于stack exchange,提问作者Mominul_Islam
相关产品推荐
相关产品推荐

