文章目录
- 一、CCPD数据集进行处理
- 1.1 从文件夹构建txt格式数据集
- 1.2 运行脚本按照8:2划分训练集,测试集
- 二 、YOLOV11训练模型
- 2.1 编写car_plate.yaml文件
- 2.2 编写train脚本:
- 2.3 训练过程
- 三、PaddleOCR识别车牌号
- 3.1 安装paddleocr,以及paddlepadddle-cpu还是gpu往下看,先勿操作
- 3.1.1 安装paddlepadddle-gpu(CPU和GPU选一个就行)
- 3.1.2 安装cpu版本的(CPU和GPU选一个就行)
- 3.1.3 安装paddleocr
- 3.2 安装过程
- 3.2.1 paddleocr安装过程如下
- 3.2.2 PaddlePaddle安装过程如下
- **3.2 代码示例**
实现思路:yolov11提取车牌坐标,进行分割,然后使用PaddleOCR进行识别!
图片:
完整源码获取方式关注底部wx公号,私信获得(有偿)
一、CCPD数据集进行处理
下载链接:https://github.com/detectRecog/CCPD
打开readme文件,查找百度网盘链接,在此不再赘述!
数据集比较大,
数据集说明:
CCPD2019车牌数据集是采集人员在合肥停车场采集、手工标注得来,采集时间在早7:30到晚10:00之间。且拍摄车牌照片的环境复杂多变,包括雨天、雪天、倾斜、模糊等。CCPD数据集包含将近30万张图片、图片尺寸为720x1160x3,共包含8种类型图片,每种类型、数量及类型说明如下表:
类型 | 图片数 | 说明 |
---|---|---|
ccpd_base | 199996 | 正常车牌 |
ccpd_challenge | 50003 | 比较有挑战的车牌 |
ccpd_db | 10132 | 光线较暗或较亮车牌 |
ccpd_fn | 20967 | 距离摄像头较远或较近 |
ccpd_np | 3036 | 没上牌的新车 |
ccpd_rotate | 10053 | 水平倾斜20-50度,垂直倾斜-10-10度 |
ccpd_tilt | 30216 | 水平倾斜15-45度,垂直倾斜-15-45度 |
ccpd_weather | 9999 | 雨天、雪天或大雾的车牌 |
ccpd_blur | 20611 | 模糊的车牌 |
cppd_newenergy | 11776 | 新能源车牌 |
总共283037张车牌图像
图片命名:“025-95_113-154&383_386&473-386&473_177&454_154&383_363&402-0_0_22_27_27_33_16-37-15.jpg”
解释:
025:车牌区域占整个画面的比例;
95_113: 车牌水平和垂直角度, 水平95°, 竖直113°
154&383_386&473:标注框左上、右下坐标,左上(154, 383), 右下(386, 473)
86&473_177&454_154&383_363&402:标注框四个角点坐标,顺序为右下、左下、左上、右上
0_0_22_27_27_33_16:车牌号码映射关系如下: 第一个0为省份 对应省份字典provinces中的’皖’,;第二个0是该车所在地的地市一级代码,对应地市一级代码字典alphabets的’A’;后5位为字母和文字, 查看车牌号ads字典,如22为Y,27为3,33为9,16为S,最终车牌号码为皖AY339S
省份:[“皖”, “沪”, “津”, “渝”, “冀”, “晋”, “蒙”, “辽”, “吉”, “黑”, “苏”, “浙”, “京”, “闽”, “赣”, “鲁”, “豫”, “鄂”, “湘”, “粤”, “桂”, “琼”, “川”, “贵”, “云”, “藏”, “陕”, “甘”, “青”, “宁”, “新”]
地市:[‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’, ‘H’, ‘J’, ‘K’, ‘L’, ‘M’, ‘N’, ‘P’, ‘Q’, ‘R’, ‘S’, ‘T’, ‘U’, ‘V’, ‘W’,‘X’, ‘Y’, ‘Z’]
车牌字典:[‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’, ‘H’, ‘J’, ‘K’, ‘L’, ‘M’, ‘N’, ‘P’, ‘Q’, ‘R’, ‘S’, ‘T’, ‘U’, ‘V’, ‘W’, ‘X’,‘Y’, ‘Z’, ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’]
最新的CCPD2020又补充了1万多张新能源汽车数据,都在下面的官网,感兴趣的可以去下载。
由于数据量过大,我从各个类型里面随机抽取10%,最终重构以后得到最终的数据集!
最终的数据集数据量如下:
类型 | 图片数 | 说明 |
---|---|---|
ccpd_base | 19999 | 正常车牌 |
ccpd_challenge | 5000 | 比较有挑战的车牌 |
ccpd_db | 1013 | 光线较暗或较亮车牌 |
ccpd_fn | 2096 | 距离摄像头较远或较近 |
ccpd_np | 303 | 没上牌的新车 没有坐标信息,忽略 |
ccpd_rotate | 1005 | 水平倾斜20-50度,垂直倾斜-10-10度 |
ccpd_tilt | 3021 | 水平倾斜15-45度,垂直倾斜-15-45度 |
ccpd_weather | 999 | 雨天、雪天或大雾的车牌 |
ccpd_blur | 2061 | 模糊的车牌 |
cppd_newenergy | 1177 | 新能源车牌 |
1.1 从文件夹构建txt格式数据集
去除重复图片+未上牌新车,将所有图片放在一个datasets文件夹里面,共35885张图片,然后运行下述代码:
import os
import cv2def parse_filename(filename):"""解析CCPD文件名,提取车牌边界框坐标"""try:except Exception as e:print(f"解析文件名失败: {filename}, 错误: {e}")return Nonedef convert_to_yolo_format():"""将边界框转换为YOLO格式(归一化)"""def process_ccpd_dataset(image_dir, label_dir):"""处理CCPD数据集,生成YOLO格式的标签文件"""print("CCPD 数据集处理完成,标签已生成。")# 使用示例
image_dir = "datasets-car" # 替换为CCPD图片目录
label_dir = "datasets-car_labels" # 生成的YOLO标签目录
process_ccpd_dataset(image_dir, label_dir)
1.2 运行脚本按照8:2划分训练集,测试集
import os
import random
import shutil# 设置文件夹路径
source_images_dir = "car_plate/Image_Files" # 原始图片目录
source_labels_dir = "car_plate/XML_Files" # 原始标签目录
datasets_dir = "datasets-carplate" # 输出数据集目录# 输出目录# 创建 datasets 文件夹路径# 设置划分比例
train_ratio = 0.8 # 80% 训练集
val_ratio = 0.2 # 20% 验证集# 获取所有图片文件和标签文件# 检查一致性
assert len(image_files) == len(label_files), "图片文件与标签文件数量不一致!"
for img_file, lbl_file in zip(image_files, label_files):assert os.path.splitext(img_file)[0] == os.path.splitext(lbl_file)[0], f"文件名不匹配:{img_file} 和 {lbl_file}"# 随机打乱文件
combined = list(zip(image_files, label_files))
random.shuffle(combined)
image_files, label_files = zip(*combined)# 划分数据集# 复制文件
def copy_files(file_list, source_dir, target_dir):for file in file_list:shutil.copy(os.path.join(source_dir, file), os.path.join(target_dir, file))# 复制训练集
copy_files(train_images, source_images_dir, train_images_dir)
copy_files(train_labels, source_labels_dir, train_labels_dir)# 复制验证集
copy_files(val_images, source_images_dir, val_images_dir)
copy_files(val_labels, source_labels_dir, val_labels_dir)# 检查分割后的文件数量和一致性
def validate_dataset(images_dir, labels_dir):print(f"验证通过:{images_dir} 和 {labels_dir} 完全匹配!")# 验证所有子集
print("Dataset splitting complete and validation passed!")
最终得到处理后的数据集!
二 、YOLOV11训练模型
2.1 编写car_plate.yaml文件
train: D:\Users\15204\Desktop\yolov11_car_plate_detection\datasets\images\train
val: D:\Users\15204\Desktop\yolov11_car_plate_detection\datasets\images\valnc: 1# Classes
names: ['car_plate']
2.2 编写train脚本:
基于yolov11n.pt预训练权重
开始训练!!
拿一个训练了20轮的模型看了看,的确不错可以,
可以看出来模型结果挺不错的!!!
2.3 训练过程
Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size40/50 2.39G 0.808 0.3246 0.9742 5 640: 100%|██████████| 1795/1795 [05:45<00:00, 5.19it/s]Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 225/225 [00:37<00:00, 6.04it/s]all 7177 7177 0.998 0.998 0.994 0.836Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size45/50 2.38G 0.7623 0.2749 0.9641 4 640: 100%|██████████| 1795/1795 [05:39<00:00, 5.28it/s]Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 225/225 [00:38<00:00, 5.85it/s]all 7177 7177 0.998 0.998 0.994 0.837Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size46/50 2.41G 0.7575 0.2714 0.9656 4 640: 100%|██████████| 1795/1795 [05:43<00:00, 5.22it/s]Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 225/225 [00:37<00:00, 6.00it/s]all 7177 7177 0.998 0.998 0.994 0.837Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size47/50 2.38G 0.7532 0.2661 0.9609 4 640: 100%|██████████| 1795/1795 [05:43<00:00, 5.23it/s]Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 225/225 [00:39<00:00, 5.75it/s]all 7177 7177 0.998 0.998 0.994 0.838Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size48/50 2.39G 0.7472 0.2633 0.9582 4 640: 100%|██████████| 1795/1795 [05:40<00:00, 5.27it/s]Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 225/225 [00:38<00:00, 5.89it/s]all 7177 7177 0.998 0.998 0.994 0.838Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size50/50 2.41G 0.7383 0.2556 0.9533 4 640: 100%|██████████| 1795/1795 [05:41<00:00, 5.26it/s]Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 225/225 [00:37<00:00, 6.06it/s]all 7177 7177 0.998 0.998 0.994 0.838
三、PaddleOCR识别车牌号
选择百度的paddleocr进行识别,理由如下:
3.1 安装paddleocr,以及paddlepadddle-cpu还是gpu往下看,先勿操作
3.1.1 安装paddlepadddle-gpu(CPU和GPU选一个就行)
我的电脑支持gpu就安装了gpu版本的,
如果你使用的是 GPU,需要安装 PaddlePaddle 的 GPU 版本:
使用下述代码:
python
import torch #导入pytorch库
print(torch.cuda.is_available()) #查看是否有cuda
print(torch.backends.cudnn.is_available()) #查看是否有cudnn
print(torch.version.cuda) #打印cuda的版本
print(torch.backends.cudnn.version()) #打印cudnn的版本
输出结果如下:
可以直到CUDA版本为12.1
需要查看对应的关系如下:
CUDA 11.2 | paddlepaddle-gpu==2.4.2 |
---|
CUDA 11.6 | paddlepaddle-gpu==2.5.0 |
---|
CUDA 11.7 | paddlepaddle-gpu==2.6.0 |
---|
CUDA 12.x | paddlepaddle-gpu==2.6.0 |
---|
pip install paddlepaddle-gpu==2.6.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
3.1.2 安装cpu版本的(CPU和GPU选一个就行)
pip install paddlepaddle -i https://mirror.baidu.com/pypi/simple # 安装 PaddlePaddle
3.1.3 安装paddleocr
pip install paddleocr
3.2 安装过程
3.2.1 paddleocr安装过程如下
3.2.2 PaddlePaddle安装过程如下
3.2 代码示例
测试了一个demo.py程序,将前面的图片传过去看看效果:
from paddleocr import PaddleOCR, draw_ocr
import cv2
import matplotlib.pyplot as plt# 初始化 PaddleOCR(lang="ch" 表示支持中文)
ocr = PaddleOCR(use_angle_cls=True, lang="ch") # 读取车牌图片
image_path = "license_plate.jpg" # 替换成你的车牌图片路径
image = cv2.imread(image_path)# 进行 OCR 识别
results = ocr.ocr(image, cls=True)# 解析识别结果
for line in results:for word_info in line:text, confidence = word_info[1][0], word_info[1][1]print(f"识别结果: {text}, 置信度: {confidence:.4f}")# 可视化结果
boxes = [word[0] for line in results for word in line] # 文字框
txts = [word[1][0] for line in results for word in line] # 文字内容
scores = [word[1][1] for line in results for word in line] # 置信度# 绘制检测结果
image_with_boxes = draw_ocr(image, boxes, txts, scores, font_path="path/to/chinese.ttf") # 需要指定中文字体路径
plt.imshow(image_with_boxes)
plt.axis("off")
plt.show()