总体功能概述
该程序通过 摄像头实时采集视频帧,利用 OpenCV 的 Haar Cascade 模型 检测车牌区域,
然后用 HyperLPR3 识别出车牌号。识别结果会在视频画面上实时显示,并且高亮显示车牌位置。
它具有以下特性:
-
✅ 自动识别并修复中文路径问题(模型文件无法加载的常见错误)
-
✅ 支持中文字体显示(通过
platech.ttf
) -
✅ 实时摄像头捕获与识别
-
自动路径修复 能自动识别中文目录并将模型复制到英文临时目录,彻底解决加载失败问题。 实时识别 使用 OpenCV 实时检测车牌,HyperLPR3 进行车牌识别。 中文输出 支持中文车牌号显示,不乱码。 稳定可靠 各关键点都有错误检测与提示,防止程序崩溃。 视觉友好 半透明矩形与小预览窗口让识别结果一目了然。
-
程序启动 → 自动切换工作目录
-
检查并加载模型文件(复制到英文临时路径)
-
打开摄像头并设置参数
-
循环读取每一帧图像:
-
检测车牌位置
-
调用 HyperLPR3 识别车牌
-
绘制车牌框、显示识别结果
-
-
按下
Q
键退出运行后效果,运行后效果。
代码:
import cv2
import hyperlpr3 as lpr3
import numpy as np
from PIL import Image, ImageDraw, ImageFont
import os
import shutil
import tempfile
import sys
# === 自动切换工作目录为脚本所在目录 ===
os.chdir(os.path.dirname(os.path.abspath(__file__)))
# === 车牌检测模型路径 ===
cascade_filename = 'haarcascade_russian_plate_number.xml'
src_cascade_path = os.path.join(os.getcwd(), cascade_filename)
# 检查模型文件是否存在
if not os.path.exists(src_cascade_path):
print(f"❌ 没有找到模型文件: {src_cascade_path}")
sys.exit(1)
# === 如果路径中含有中文,复制到系统临时目录(纯英文路径) ===
if any('\u4e00' <= ch <= '\u9fff' for ch in src_cascade_path):
tmp_cascade_path = os.path.join(tempfile.gettempdir(), cascade_filename)
shutil.copy(src_cascade_path, tmp_cascade_path)
print(f"⚙️ 检测到中文路径,已复制模型到临时目录: {tmp_cascade_path}")
cascade_path = tmp_cascade_path
else:
cascade_path = src_cascade_path
# === 加载 Haar 模型 ===
plateCascade = cv2.CascadeClassifier(cascade_path)
if plateCascade.empty():
print(f"❌ 无法加载分类器文件: {cascade_path}")
sys.exit(1)
else:
print("✅ 成功加载车牌检测模型!")
# === 初始化车牌识别器 ===
catcher = lpr3.LicensePlateCatcher()
# === 摄像头设置 ===
frameWidth, frameHeight = 640, 480
minArea = 500
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, frameWidth)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, frameHeight)
cap.set(cv2.CAP_PROP_EXPOSURE, 0.1)
cap.set(cv2.CAP_PROP_GAIN, 0.1)
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 0)
# === 字体路径(中文显示) ===
font_path = "C:/Users/Administrator/Desktop/python/fonts/platech.ttf"
font_size = 20
chinese_font = ImageFont.truetype(font_path, font_size)
# === 初始化变量 ===
prev_plate_info = ""
snapshot = None
plate_info_x, plate_info_y = 0, 0
plate_info_width, plate_info_height = 450, 30
rect_thickness = -1
rect_color = (0, 0, 255)
rect_opacity = 0.5
tracked_plate_position = None
print("🚗 车牌识别系统启动中... 按 Q 键退出")
# === 主循环 ===
while True:
success, img = cap.read()
if not success:
print("⚠️ 无法读取摄像头,请检查设备连接。")
break
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
numberPlates = plateCascade.detectMultiScale(imgGray, 1.1, 4)
plate_info_str = prev_plate_info
for (x, y, w, h) in numberPlates:
area = w * h
if area > minArea:
plate_info = catcher(img[y:y + h, x:x + w])
if plate_info:
plate_info_str = str(plate_info[0])
prev_plate_info = plate_info_str
plate_img = img[y:y + h, x:x + w]
snapshot = cv2.resize(plate_img, (180, 100))
tracked_plate_position = (x, y, w, h)
if tracked_plate_position is not None:
x, y, w, h = tracked_plate_position
overlay = img.copy()
cv2.rectangle(overlay, (x, y), (x + w, y + h), rect_color, rect_thickness)
cv2.addWeighted(overlay, rect_opacity, img, 1 - rect_opacity, 0, img)
pil_img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(pil_img)
draw.rectangle([(plate_info_x, plate_info_y),
(plate_info_x + plate_info_width, plate_info_y + plate_info_height)],
fill="black")
draw.text((plate_info_x + 5, plate_info_y + 5), plate_info_str, font=chinese_font, fill="red")
img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)
if snapshot is not None:
img[10:110, frameWidth - 190:frameWidth - 10] = snapshot
cv2.imshow("Result", img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
模型文件:https://github.com/opencv/opencv/blob/master/data/haarcascades/haarcascade_russian_plate_number.xml