如何用OpenCV Python提取车牌并筛选显示最小含文本矩形
解决车牌提取:过滤无文本矩形与最小矩形查找问题
嘿,我来帮你搞定这个车牌提取的麻烦!你现在的代码能找到矩形,但会误抓挡风玻璃这类无文本区域,核心问题是没有把矩形区域的文本检测作为筛选条件,另外关于最小矩形的查找,OpenCV也有现成的实用方法,咱们一步步来调整:
一、问题根源分析
你当前的逻辑是找面积前10的轮廓里的四边形,但这种方法太宽泛了——挡风玻璃、车门装饰框这类规则四边形都会被误识别,因为你没验证这些区域里是否有车牌特有的字符文本。
二、核心改进思路
- 筛选有文本的矩形:对每个候选轮廓提取的区域,用Tesseract做文本检测,只保留能识别出符合车牌格式文本的区域
- 精准定位最小矩形:用OpenCV的
cv2.minAreaRect()和cv2.boxPoints()来获取轮廓的最小外接矩形,比你当前用极值点裁剪的方式更准确
三、修改后的完整代码
import matplotlib.pyplot as plt import cv2 import numpy as np from PIL import Image import pytesseract # 配置Tesseract路径 pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files (x86)\Tesseract-OCR\tesseract.exe' def is_plate_text(text): """判断文本是否符合车牌格式(以国内蓝牌为例:汉字+字母+字母/数字组合)""" if not text or len(text.strip()) < 5: return False # 简单的格式校验,你可以根据需求调整(比如适配不同地区车牌) has_chinese = any('\u4e00' <= char <= '\u9fff' for char in text) has_alnum = any(char.isalnum() for char in text) return has_chinese and has_alnum def main(img_path): # 读取并预处理图像 img = cv2.imread(img_path, cv2.IMREAD_COLOR) if img is None: print("无法读取图像,请检查路径") return img = cv2.resize(img, (600, 400)) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 双边滤波:去噪同时保留边缘 gray = cv2.bilateralFilter(gray, 13, 15, 15) # Canny边缘检测 edged = cv2.Canny(gray, 30, 200) # 查找所有轮廓 contours, hierarchy = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) # 按面积倒序取前20个(避免漏过小车牌) contours = sorted(contours, key=cv2.contourArea, reverse=True)[:20] plate_contours = [] for c in contours: # 计算轮廓周长,多边形逼近 peri = cv2.arcLength(c, True) approx = cv2.approxPolyDP(c, 0.02 * peri, True) # 先筛选四边形 if len(approx) == 4: # 获取最小外接矩形 rect = cv2.minAreaRect(c) box = cv2.boxPoints(rect) box = np.int0(box) # 裁剪矩形区域 x, y, w, h = cv2.boundingRect(approx) cropped = gray[y:y+h, x:x+w] # 预处理裁剪区域,提升Tesseract识别率 cropped = cv2.threshold(cropped, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1] cropped = cv2.resize(cropped, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC) # 用Tesseract识别文本,指定只识别字母数字和汉字 custom_config = r'--oem 3 --psm 8 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789甲乙丙丁戊己庚辛壬癸子丑寅卯辰巳午未申酉戌亥京津冀晋蒙辽吉黑沪苏浙皖闽赣鲁豫鄂湘粤桂琼渝川黔滇藏陕甘青宁新' text = pytesseract.image_to_string(cropped, config=custom_config) # 校验文本是否符合车牌格式 if is_plate_text(text): plate_contours.append(box) print(f"识别到车牌文本:{text.strip()}") # 绘制所有符合条件的车牌矩形 if plate_contours: for box in plate_contours: cv2.drawContours(img, [box], 0, (0, 0, 255), 3) plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) plt.show() else: print("未找到包含有效文本的车牌区域") # 调用示例 if __name__ == "__main__": main("your_car_image.jpg")
四、关键细节说明
1. 文本筛选逻辑
- 我写了
is_plate_text()函数来校验识别出的文本是否符合车牌格式,你可以根据目标地区的车牌规则调整(比如欧美车牌不需要汉字校验) - Tesseract的配置里指定了字符白名单,减少无关字符的干扰,同时用
psm 8模式让它只识别单个文本块,更适合车牌场景
2. 最小矩形查找
cv2.minAreaRect(c):输入轮廓,返回一个包含中心坐标、宽高、旋转角度的元组,这就是该轮廓的最小外接矩形cv2.boxPoints(rect):把矩形的四个角点转换为可绘制的数组格式- 相比你之前用极值点裁剪的方式,这个方法能准确获取旋转后的最小矩形,不会把多余区域包含进去
3. 预处理优化
- 用OTSU自动阈值二值化,比固定阈值更适配不同光照的图像
- 把裁剪区域放大2倍,提升Tesseract的识别精度
五、额外建议
- 如果你的场景里车牌有固定颜色(比如国内蓝牌),可以先做颜色筛选(提取蓝色区域),再找轮廓,能进一步减少误检
- 可以尝试用
cv2.RETR_EXTERNAL模式查找轮廓,只保留最外层轮廓,避免内部干扰
内容的提问来源于stack exchange,提问作者Leo Bogod




