You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 04:05:25