基于Python与OpenCV的车牌识别系统设计与实现(含颜色识别与图形界面)

一、系统架构设计

1.1 总体架构

系统采用模块化设计,主要分为以下几个模块:

  • 图像采集模块:负责从摄像头或视频文件读取图像
  • 预处理模块:对图像进行灰度化、二值化、降噪等处理
  • 车牌定位模块:使用边缘检测和形态学操作定位车牌区域
  • 字符分割模块:将车牌区域分割为单个字符
  • 字符识别模块:使用模板匹配或机器学习方法识别字符
  • 颜色识别模块:分析车牌区域颜色特征
  • GUI模块:提供用户交互界面

1.2 技术选型

  • 编程语言:Python 3.x
  • 图像处理库:OpenCV
  • GUI框架:Tkinter(轻量级)或PyQt(功能更丰富)
  • 开发环境:PyCharm或VS Code

二、车牌定位与识别实现

2.1 图像预处理

  1. import cv2
  2. import numpy as np
  3. def preprocess_image(img):
  4. # 转换为灰度图
  5. gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  6. # 高斯模糊降噪
  7. blurred = cv2.GaussianBlur(gray, (5, 5), 0)
  8. # Sobel边缘检测
  9. sobel = cv2.Sobel(blurred, cv2.CV_8U, 1, 0, ksize=3)
  10. # 二值化
  11. _, binary = cv2.threshold(sobel, 0, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)
  12. return binary

2.2 车牌定位

  1. def locate_license_plate(binary_img):
  2. # 形态学操作
  3. kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (17, 5))
  4. closed = cv2.morphologyEx(binary_img, cv2.MORPH_CLOSE, kernel)
  5. # 查找轮廓
  6. contours, _ = cv2.findContours(closed, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
  7. # 筛选符合车牌特征的轮廓
  8. candidates = []
  9. for contour in contours:
  10. rect = cv2.minAreaRect(contour)
  11. box = cv2.boxPoints(rect)
  12. box = np.int0(box)
  13. width = rect[1][0]
  14. height = rect[1][1]
  15. aspect_ratio = width / height if width > height else height / width
  16. # 车牌长宽比通常在2-5之间
  17. if 2 < aspect_ratio < 5:
  18. candidates.append(box)
  19. return candidates

2.3 字符分割与识别

  1. def segment_characters(plate_img):
  2. # 转换为灰度图并二值化
  3. gray = cv2.cvtColor(plate_img, cv2.COLOR_BGR2GRAY)
  4. _, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
  5. # 查找字符轮廓
  6. contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
  7. # 按x坐标排序
  8. characters = sorted(contours, key=lambda x: cv2.boundingRect(x)[0])
  9. return characters
  10. def recognize_characters(characters, template_dir):
  11. recognized_text = ""
  12. for char in characters:
  13. x, y, w, h = cv2.boundingRect(char)
  14. char_img = binary[y:y+h, x:x+w]
  15. # 加载模板并匹配
  16. best_score = -1
  17. best_char = "?"
  18. # 实际应用中应遍历模板目录下的所有字符模板
  19. for template_char in os.listdir(template_dir):
  20. template_path = os.path.join(template_dir, template_char)
  21. template = cv2.imread(template_path, 0)
  22. _, template = cv2.threshold(template, 127, 255, cv2.THRESH_BINARY)
  23. res = cv2.matchTemplate(char_img, template, cv2.TM_CCOEFF_NORMED)
  24. _, score, _, _ = cv2.minMaxLoc(res)
  25. if score > best_score:
  26. best_score = score
  27. best_char = template_char[0] # 假设模板文件名以字符开头
  28. recognized_text += best_char
  29. return recognized_text

三、车牌颜色识别实现

3.1 颜色空间转换

  1. def detect_plate_color(plate_img):
  2. # 转换为HSV颜色空间
  3. hsv = cv2.cvtColor(plate_img, cv2.COLOR_BGR2HSV)
  4. # 定义颜色范围(示例值,需根据实际情况调整)
  5. blue_lower = np.array([100, 50, 50])
  6. blue_upper = np.array([130, 255, 255])
  7. yellow_lower = np.array([20, 50, 50])
  8. yellow_upper = np.array([30, 255, 255])
  9. green_lower = np.array([40, 50, 50])
  10. green_upper = np.array([90, 255, 255])
  11. # 创建掩膜
  12. blue_mask = cv2.inRange(hsv, blue_lower, blue_upper)
  13. yellow_mask = cv2.inRange(hsv, yellow_lower, yellow_upper)
  14. green_mask = cv2.inRange(hsv, green_lower, green_upper)
  15. # 计算各颜色区域面积
  16. blue_area = cv2.countNonZero(blue_mask)
  17. yellow_area = cv2.countNonZero(yellow_mask)
  18. green_area = cv2.countNonZero(green_mask)
  19. # 判断颜色
  20. max_area = max(blue_area, yellow_area, green_area)
  21. if max_area == blue_area:
  22. return "蓝牌"
  23. elif max_area == yellow_area:
  24. return "黄牌"
  25. elif max_area == green_area:
  26. return "绿牌"
  27. else:
  28. return "未知颜色"

四、GUI开发

4.1 使用Tkinter实现简单GUI

  1. import tkinter as tk
  2. from tkinter import filedialog
  3. from PIL import Image, ImageTk
  4. class LicensePlateApp:
  5. def __init__(self, root):
  6. self.root = root
  7. self.root.title("车牌识别系统")
  8. # 创建控件
  9. self.load_btn = tk.Button(root, text="加载图像", command=self.load_image)
  10. self.load_btn.pack()
  11. self.process_btn = tk.Button(root, text="识别车牌", command=self.process_image)
  12. self.process_btn.pack()
  13. self.result_label = tk.Label(root, text="识别结果将显示在这里")
  14. self.result_label.pack()
  15. self.image_label = tk.Label(root)
  16. self.image_label.pack()
  17. self.original_img = None
  18. def load_image(self):
  19. file_path = filedialog.askopenfilename()
  20. if file_path:
  21. self.original_img = cv2.imread(file_path)
  22. img = Image.fromarray(cv2.cvtColor(self.original_img, cv2.COLOR_BGR2RGB))
  23. img = img.resize((400, 300), Image.ANTIALIAS)
  24. imgtk = ImageTk.PhotoImage(image=img)
  25. self.image_label.imgtk = imgtk
  26. self.image_label.configure(image=imgtk)
  27. def process_image(self):
  28. if self.original_img is not None:
  29. binary_img = preprocess_image(self.original_img)
  30. candidates = locate_license_plate(binary_img)
  31. if candidates:
  32. plate_img = self.original_img[
  33. min(p[1] for p in candidates[0]):max(p[1] for p in candidates[0]),
  34. min(p[0] for p in candidates[0]):max(p[0] for p in candidates[0])
  35. ]
  36. color = detect_plate_color(plate_img)
  37. characters = segment_characters(plate_img)
  38. # 假设有模板目录
  39. text = recognize_characters(characters, "templates")
  40. self.result_label.config(text=f"车牌号码: {text}\n车牌颜色: {color}")
  41. else:
  42. self.result_label.config(text="未检测到车牌")
  43. if __name__ == "__main__":
  44. root = tk.Tk()
  45. app = LicensePlateApp(root)
  46. root.mainloop()

五、性能优化与最佳实践

5.1 算法优化

  1. 并行处理:对于视频流处理,可使用多线程或多进程提高帧率
  2. 模板匹配优化:使用更高效的匹配算法或考虑深度学习模型
  3. 颜色识别阈值调整:根据实际光照条件调整HSV范围

5.2 代码结构优化

  1. 将各功能模块拆分为独立Python文件
  2. 使用类封装相关功能
  3. 添加详细的文档字符串和注释

5.3 测试与验证

  1. 收集不同光照条件下的车牌样本
  2. 测试不同角度和距离的车牌识别效果
  3. 验证颜色识别的准确率

六、扩展功能建议

  1. 增加深度学习支持:使用YOLO等模型提高检测准确率
  2. 支持多种车牌类型:扩展为识别新能源车牌等
  3. 添加数据库功能:存储识别记录
  4. 实现实时视频处理:从摄像头实时识别
  5. 添加网络功能:开发Web服务接口

七、总结

本文介绍了一个完整的基于Python和OpenCV的车牌识别系统实现方案,涵盖了从图像预处理到GUI开发的各个环节。该系统不仅能识别车牌号码,还能识别车牌颜色,适合作为计算机视觉相关的毕业设计项目。实际开发中,可根据具体需求调整算法参数和系统架构,以获得更好的识别效果。