尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Python+OpenCV车牌识别:从环境搭建到完整项目实战

Python+OpenCV车牌识别:从环境搭建到完整项目实战 1. 先搞清楚这个项目到底能帮你解决什么问题如果你刚接触Python和图像处理看到“车牌号识别”可能会觉得很高深担心自己搞不定。其实这个项目的核心价值在于它提供了一个从零开始、可运行、能出结果的完整实践案例。它解决的就是一个最经典的计算机视觉入门问题如何让程序看懂图片里的文字车牌。对于新手来说最大的障碍往往不是算法本身而是“环境怎么配”、“代码怎么跑”、“报错了怎么办”。这个项目把Python和OpenCV这两个工具组合起来正好能让你跨过这道坎。OpenCV负责处理图像比如找到车牌的位置、把字符切分开Python则负责组织逻辑和调用现成的识别库。你不需要从零推导数学公式而是学习如何像一个工程师一样把成熟的“轮子”组装起来解决一个具体问题。所以它最适合两类人一是想通过一个有趣的项目入门Python和OpenCV的编程新手二是需要快速验证一个车牌识别原型用于课程设计、毕业设计或某个小应用的开发者。最值得关注的不是识别率有多高那需要更复杂的模型而是整个流程能否在你的电脑上顺利跑通以及你能否理解每一步在做什么。2. 动手之前先把环境准备好在开始写代码之前90%的坑都出在环境上。很多人卡在ModuleNotFoundError: No module named cv2找不到OpenCV这一步就放弃了。下面我按实测顺序带你走一遍最稳妥的准备流程。2.1 Python环境别在系统Python里瞎折腾强烈建议使用Anaconda或Miniconda来管理Python环境。这能让你为这个项目创建一个独立、干净的环境避免和系统或其他项目的包版本冲突。安装Miniconda或Anaconda去官网下载对应你操作系统Windows/macOS/Linux的安装包。安装时记得勾选“Add Anaconda to my PATH environment variable”将Anaconda添加到环境变量这样后续在命令行里使用会方便很多。创建专属环境打开命令行Windows用cmd或Anaconda PromptmacOS/Linux用Terminal执行以下命令创建一个名为plate_recognition名字可自定的Python 3.8环境3.7-3.9都比较稳定conda create -n plate_recognition python3.8激活环境创建成功后激活这个环境。conda activate plate_recognition激活后命令行的前缀通常会变成(plate_recognition)表示你正在这个独立环境中操作。2.2 安装核心库OpenCV和Pytesseract环境激活后我们安装两个核心库。安装OpenCV在激活的plate_recognition环境中使用pip安装OpenCV的Python版本。这是最通用、问题最少的方法。pip install opencv-python这个命令会安装OpenCV的主模块。如果你想用一些额外的、非免费的算法模块这个车牌项目通常用不到可以安装opencv-contrib-python但新手用opencv-python就够了。安装PytesseractOpenCV负责找到车牌、预处理图像但识别上面的字符我们需要一个OCR光学字符识别引擎。这里选用Tesseract而pytesseract是它的Python封装。pip install pytesseract但是只安装Python包是不够的pytesseract只是一个调用接口你必须先安装Tesseract OCR引擎本体。安装Tesseract OCR引擎Windows去 GitHub - UB-Mannheim/tesseract 下载安装程序。安装时记下安装路径例如C:\Program Files\Tesseract-OCR。安装完成后需要将这个路径比如C:\Program Files\Tesseract-OCR添加到系统的PATH环境变量中或者稍后在代码里指定tesseract_cmd的完整路径。macOS使用Homebrew安装最方便brew install tesseract。Linux (Ubuntu/Debian)使用aptsudo apt install tesseract-ocr。如果需要中文识别可以额外安装tesseract-ocr-chi-sim。验证安装在命令行中先确保环境已激活然后依次输入python进入Python交互模式再输入import cv2 print(cv2.__version__) import pytesseract print(pytesseract.get_tesseract_version())如果都能成功打印出版本号没有报错那么核心环境就准备好了。2.3 准备测试图片和代码框架在你喜欢的位置比如桌面创建一个项目文件夹例如CarPlateRecognition。在里面做两件事找几张清晰的、包含车牌的图片命名为test1.jpgtest2.jpg等放进文件夹。最好从网上找一些国内车牌的正面照背景不要太杂乱。这是你的“测试数据”。创建一个Python脚本比如plate_recognition.py。用任何文本编辑器或IDE如VSCode打开它。在VSCode中记得在左下角选择我们刚创建的plate_recognition这个Conda环境作为解释器。3. 从单张图片开始拆解识别全流程现在我们一步步把车牌识别的逻辑写出来。别想着一步到位先确保每一步都能跑通能看到中间结果。3.1 读取图片和预处理打开plate_recognition.py开始编写import cv2 import pytesseract import numpy as np # 如果你的Tesseract没在系统PATH里需要指定路径Windows示例 # pytesseract.pytesseract.tesseract_cmd r‘C:\Program Files\Tesseract-OCR\tesseract.exe’ def recognize_plate(image_path): # 1. 读取图片 img cv2.imread(image_path) if img is None: print(f“错误无法读取图片 {image_path}”) return None # 显示原始图片 cv2.imshow(‘Original Image’, img) cv2.waitKey(0) cv2.destroyAllWindows() # 2. 预处理转为灰度图 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) cv2.imshow(‘Gray Image’, gray) cv2.waitKey(0) # 3. 降噪使用高斯模糊 blurred cv2.GaussianBlur(gray, (5, 5), 0) cv2.imshow(‘Blurred Image’, blurred) cv2.waitKey(0) # 4. 边缘检测Canny算子帮助找到车牌轮廓 edged cv2.Canny(blurred, 50, 200) cv2.imshow(‘Edged Image’, edged) cv2.waitKey(0) cv2.destroyAllWindows() return img, gray, blurred, edged # 测试一下 image_path ‘test1.jpg’ # 替换成你的图片名 original, gray, blurred, edged recognize_plate(image_path)运行这段代码你会看到图片依次变为灰度、模糊、边缘检测后的效果。预处理的目的是简化图像信息突出车牌区域的轮廓为下一步定位做准备。如果在这一步你的图片显示不出来大概率是图片路径不对或者OpenCV的GUI后端在某些环境如某些服务器或无GUI的WSL下不支持imshow可以暂时注释掉显示部分或者用cv2.imwrite(‘step1_gray.jpg’, gray)保存中间结果来查看。3.2 定位车牌区域这是最关键也最不稳定的一步。我们假设车牌是一个矩形轮廓并且其宽高比在一定范围内。def locate_plate(edged_img, original_img): # 1. 在边缘图中寻找轮廓 # cv2.RETR_EXTERNAL 只检测外轮廓 # cv2.CHAIN_APPROX_SIMPLE 压缩水平、垂直和对角线方向只保留端点 contours, _ cv2.findContours(edged_img.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 2. 根据轮廓面积和宽高比筛选 plate_contours [] for contour in contours: # 计算轮廓的矩形边界框 x, y, w, h cv2.boundingRect(contour) aspect_ratio w / float(h) # 中国车牌常见宽高比大约在 3:1 到 4:1 之间面积也不能太小 if 2.5 aspect_ratio 5.0 and w 80 and h 20: plate_contours.append((x, y, w, h)) # 3. 如果没有找到尝试另一种方法形态学操作轮廓查找 if not plate_contours: print(“未通过边缘检测找到车牌尝试形态学方法...”) # 对灰度图进行自适应二值化 gray cv2.cvtColor(original_img, cv2.COLOR_BGR2GRAY) binary cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2) # 定义矩形核进行闭运算先膨胀后腐蚀连接车牌字符区域 kernel cv2.getStructuringElement(cv2.MORPH_RECT, (15, 5)) closed cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel) # 再次寻找轮廓 contours2, _ cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for contour in contours2: x, y, w, h cv2.boundingRect(contour) aspect_ratio w / float(h) if 2.5 aspect_ratio 5.0 and w 80 and h 20: plate_contours.append((x, y, w, h)) # 4. 如果找到多个候选区域通常取面积最大的那个 if plate_contours: # 按面积排序 plate_contours.sort(keylambda rect: rect[2]*rect[3], reverseTrue) x, y, w, h plate_contours[0] # 从原图上截取车牌区域 plate_img original_img[y:yh, x:xw] # 绘制矩形框并显示 result_img original_img.copy() cv2.rectangle(result_img, (x, y), (xw, yh), (0, 255, 0), 2) # 绿色框线宽2 cv2.imshow(‘Detected Plate’, result_img) cv2.imshow(‘Cropped Plate’, plate_img) cv2.waitKey(0) cv2.destroyAllWindows() return plate_img else: print(“未找到车牌区域”) return None # 接续上一步 plate_region locate_plate(edged, original)这一步的参数如宽高比2.5-5.0最小宽度80需要根据你的测试图片微调。如果图片中车牌倾斜、光照不均或背景复杂定位可能会失败。这时不要急着改代码先保存每一步的中间图像cv2.imwrite分析是边缘没检测好还是轮廓筛选条件太严格。3.3 车牌区域二次处理与字符识别截取到车牌区域后直接扔给Tesseract识别效果往往不好需要对车牌区域图像进行二次处理。def recognize_characters(plate_img): if plate_img is None: return “” # 1. 将车牌区域转为灰度并增强对比度 plate_gray cv2.cvtColor(plate_img, cv2.COLOR_BGR2GRAY) # 使用CLAHE限制对比度自适应直方图均衡化改善光照不均 clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(8,8)) plate_gray clahe.apply(plate_gray) # 2. 二值化将图像转为黑白突出字符 # 尝试自适应阈值它对光照变化更鲁棒 plate_binary cv2.adaptiveThreshold(plate_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2) # 或者使用大津法Otsu‘s全局阈值 # _, plate_binary cv2.threshold(plate_gray, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU) cv2.imshow(‘Processed Plate for OCR’, plate_binary) cv2.waitKey(0) cv2.destroyAllWindows() # 3. 配置Tesseract参数 # ‘-l eng’ 使用英文语言包识别数字和字母。如需中文可安装‘chi_sim’后使用‘-l chi_sim’ # ‘--psm 7’ 表示将图像视为单行文本这对车牌很有效。 # ‘--oem 3’ 使用默认的OCR引擎模式。 custom_config r‘--oem 3 --psm 7 -c tessedit_char_whitelist0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ京沪津渝冀晋蒙辽吉黑苏浙皖闽赣鲁豫鄂湘粤桂琼川贵云藏陕甘青宁新’ # 上面的白名单whitelist限制了只识别数字、字母和省份简称能减少误识别。 # 4. 调用Tesseract进行OCR识别 text pytesseract.image_to_string(plate_binary, configcustom_config) # 清理识别结果去除空格、换行等无关字符 text ‘‘.join(text.split()) return text # 接续上一步 if plate_region is not None: plate_number recognize_characters(plate_region) print(f“识别出的车牌号码是{plate_number}”) else: print(“未获取到车牌区域无法识别。”)关键点在这里--psm页面分割模式和白名单是大幅提升Tesseract车牌识别准确率的关键。psm 7告诉它这是单行文本。白名单则限制了输出字符的范围避免了将“0”识别成“O”或将噪声识别成奇怪字符。如果识别结果为空或乱码首先检查plate_binary二值化后的图像是否清晰字符是否完整、黑白分明。4. 把流程封装成函数处理批量图片单张图片跑通后我们就可以把它封装成一个函数方便处理多张图片并加入简单的错误处理和结果保存。import os def process_single_image(image_path, output_dir‘results’): “”“处理单张图片返回识别结果和标记后的图片”“” print(f“\n处理图片{image_path}”) # 1. 读取和预处理 img cv2.imread(image_path) if img is None: print(f“ 错误无法读取图片”) return None, None # 这里可以调用之前写好的 locate_plate 和 recognize_characters 函数或将其逻辑整合 # 为了清晰我们假设有两个函数find_plate_region 和 ocr_plate plate_img find_plate_region(img) # 你需要将之前的定位逻辑封装成这个函数 if plate_img is None: print(f“ 未检测到车牌”) # 仍然返回原图但标记为未检测到 result_img img.copy() cv2.putText(result_img, ‘No Plate Detected’, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) return ‘No Plate Detected’, result_img # 2. 字符识别 plate_number ocr_plate(plate_img) # 你需要将之前的识别逻辑封装成这个函数 # 3. 在原图上绘制结果 # 这里需要知道车牌在原图的位置所以find_plate_region函数最好返回位置信息(x,y,w,h)和截取图 # 我们假设 find_plate_region 返回 (plate_img, (x, y, w, h)) plate_img, (x, y, w, h) find_plate_region(img) result_img img.copy() cv2.rectangle(result_img, (x, y), (xw, yh), (0, 255, 0), 2) cv2.putText(result_img, plate_number, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2) print(f“ 识别结果{plate_number}”) return plate_number, result_img def batch_process(input_dir‘test_images’, output_dir‘results’): “”“批量处理一个文件夹内的所有图片”“” if not os.path.exists(output_dir): os.makedirs(output_dir) supported_formats (’.jpg‘, ’.jpeg‘, ’.png‘, ’.bmp‘) results [] for filename in os.listdir(input_dir): if filename.lower().endswith(supported_formats): image_path os.path.join(input_dir, filename) plate_text, result_img process_single_image(image_path, output_dir) # 保存结果图片 if result_img is not None: output_path os.path.join(output_dir, f‘result_{filename}’) cv2.imwrite(output_path, result_img) print(f“ 结果已保存至{output_path}”) results.append({‘file’: filename, ‘plate’: plate_text}) # 简单汇总 print(“\n 批量处理完成 ) for res in results: print(f“{res[‘file’]}: {res[‘plate’]}”) # 可以将结果保存为CSV文件 import csv csv_path os.path.join(output_dir, ‘results.csv’) with open(csv_path, ‘w’, newline‘’, encoding‘utf-8-sig’) as f: writer csv.DictWriter(f, fieldnames[‘file’, ‘plate’]) writer.writeheader() writer.writerows(results) print(f“详细结果已保存至{csv_path}”) # 运行批量处理 if __name__ ‘__main__’: # 确保有一个名为‘test_images’的文件夹里面放你的测试图片 batch_process(input_dir‘test_images’)这个批量处理框架做了几件重要的事自动遍历文件夹、为每张图片保存可视化结果、将文本结果汇总成CSV表格。这是从实验脚本走向实用工具的关键一步。5. 识别效果不佳这是你的排查清单如果你的识别率不高或者根本检测不到车牌别灰心这太正常了。按照以下顺序排查大部分问题都能解决图片质量是根本问题图片模糊、倾斜、光照过暗/过曝、车牌区域占比太小。对策换用更清晰、正面的车牌图片测试。可以先用人眼看看图片里的车牌是否清晰可辨。定位失败找不到绿色框问题edged图像里车牌的轮廓不闭合或不明显宽高比aspect_ratio或最小宽度w/h参数不适合你的图片。排查用cv2.imwrite保存grayedgedclosed如果用了形态学这些中间图像。看看车牌区域在这些图里是否被突出显示。调整cv2.Canny的阈值50, 200。如果边缘太碎提高下限如果边缘没连上降低下限。调整宽高比和最小尺寸。打印所有候选轮廓的(w, h, aspect_ratio)看看你真实车牌的数值是多少然后调整筛选条件。尝试不同的预处理组合比如在Canny前试试cv2.bilateralFilter双边滤波保边去噪。字符识别错误有框但识别不对问题plate_binary二值化图像中字符断裂、粘连或背景有噪声。排查重点观察cv2.imshow(‘Processed Plate for OCR’, plate_binary)显示的结果。字符应该是清晰、连贯的白色或黑色线条。尝试不同的二值化方法注释掉adaptiveThreshold改用cv2.threshold配合cv2.THRESH_OTSU。调整adaptiveThreshold的参数blockSize和C。在二值化前可以尝试使用cv2.morphologyEx进行开运算先腐蚀后膨胀去除小噪点或闭运算连接断裂字符。最关键的一步调整Tesseract的--psm模式。对于车牌7单行文本或8单个单词可能更合适。可以尝试6统一区块文本或10单个字符。用命令tesseract --help-psm查看所有模式。检查并扩充白名单tessedit_char_whitelist。如果你要识别新能源车牌带字母D/F记得加入。如果是纯数字可以只放数字。环境或路径问题问题ModuleNotFoundError 或Tesseract报错。排查确认你的终端或IDE激活了正确的Conda环境plate_recognition。在终端输入python -c “import cv2; import pytesseract; print(‘OK’)”测试导入。对于Tesseract如果报错pytesseract.pytesseract.TesseractNotFoundError请取消代码中pytesseract.pytesseract.tesseract_cmd的注释并将其路径修改为你电脑上的真实安装路径。6. 想更进一步这些方向可以优化这个基础版本能跑通但离“鲁棒”和“实用”还有距离。如果你有兴趣深入可以从以下几个方向尝试优化更稳定的车牌定位目前的轮廓筛选方法很基础。可以研究颜色空间HSV筛选。中国车牌主要是蓝底、黄底、绿底新能源和白底黑字。在HSV空间里可以较好地分离出这些颜色区域再结合轮廓分析能大幅提升在复杂背景下的定位成功率。字符分割对于光照不均或污损的车牌二值化后字符可能粘连。可以在识别前先利用投影法水平/垂直像素投影将每个字符精确地切割出来再分别识别这能提高Tesseract的准确率。使用深度学习模型OpenCV的dnn模块可以加载训练好的深度学习模型如YOLO、SSD、EAST文本检测器CRNN识别模型进行端到端的车牌检测与识别。这需要下载预训练模型文件代码会更复杂但准确率和适应性会强很多。这是工业级方案的方向。图形界面GUI使用tkinter或PyQt为你的程序做一个简单的界面允许用户选择图片、查看识别结果和标记框体验会好很多。视频流处理将上述流程放在一个循环里处理摄像头捕获的每一帧cv2.VideoCapture就可以实现实时车牌识别。注意要加入帧间去重避免对同一车牌重复输出。最后也是最实际的建议不要一开始就追求完美的识别率。先把整个流程在3-5张差异较大的图片上跑通理解每一行代码的作用。然后收集更多有挑战性的图片雨天、夜间、倾斜、污损用它们来测试和调整你的参数与算法。这个过程才是这个项目带给你的真正价值——学会如何将一个复杂的视觉问题拆解成一个个可编程、可调试的步骤。
返回列表