当前位置: 首页 > article >正文

保姆级教程:用Python脚本一键解析CCPD车牌数据集,生成YOLO格式标注

零基础实战Python自动化解析CCPD车牌数据集并生成YOLO标注文件当你第一次打开CCPD数据集文件夹时那些看似随机的文件名是否让你感到困惑比如这个典型的例子01-86_91-298341_449414-458394_308410_304357_454341-0_0_14_28_24_26_29-124-24.jpg。别担心这些看似复杂的字符串实际上包含了车牌位置、颜色等完整信息。本文将带你一步步破解这个密码并提供一个完整的Python解决方案。1. 理解CCPD数据集的文件名编码规则CCPD数据集是目前最大的中文车牌检测基准数据集广泛应用于智能交通、安防监控等领域。它的独特之处在于将所有标注信息都编码在文件名中而非传统的XML或JSON格式。这种设计虽然节省了存储空间但对初次接触的研究者来说却是个挑战。让我们拆解一个典型文件名01-86_91-298341_449414-458394_308410_304357_454341-0_0_14_28_24_26_29-124-24.jpg各部分含义如下表所示文件名片段含义说明示例值解析01-86_91图像采集地点和时间信息01表示安徽86_91可能是时间戳298341_449414车牌左上角和右下角坐标车牌框左上(298,341)右下(449,414)458394...454341车牌四个角点坐标用于车牌矫正的四个角点位置0_0_14_28_24_26_29车牌号码信息0表示绿牌后续为车牌字符编码124-24图像亮度和模糊度124为亮度值24为模糊度理解这个编码规则是转换YOLO格式的关键第一步。YOLO需要的标注格式是类别 中心x坐标 中心y坐标 宽度 高度其中所有坐标值都是相对于图像宽高的归一化值0-1之间。2. 环境准备与脚本框架搭建在开始编写解析脚本前我们需要确保开发环境配置正确。以下是推荐的环境配置# 创建虚拟环境可选但推荐 python -m venv ccpd_parser source ccpd_parser/bin/activate # Linux/Mac # ccpd_parser\Scripts\activate # Windows # 安装必要库 pip install opencv-python numpy tqdm脚本的基本框架应该包含以下功能模块文件遍历模块递归查找指定目录下的所有图片文件文件名解析模块提取关键坐标和车牌信息坐标转换模块将绝对坐标转换为YOLO格式的相对坐标异常处理模块自动检测并处理损坏图片进度显示模块使用tqdm显示处理进度基础脚本结构如下import os import cv2 from tqdm import tqdm class CCPDToYOLO: def __init__(self, src_dir, image_dest_dir, label_dest_dir): self.src_dir src_dir self.image_dest_dir image_dest_dir self.label_dest_dir label_dest_dir def parse_filename(self, filename): 解析文件名提取关键信息 pass def convert_coordinates(self, coords, img_width, img_height): 坐标转换到YOLO格式 pass def process_dataset(self): 主处理流程 pass if __name__ __main__: converter CCPDToYOLO( src_dirpath/to/ccpd, image_dest_diroutput/images, label_dest_diroutput/labels ) converter.process_dataset()3. 完整解析脚本实现与关键代码解读现在让我们实现完整的解析脚本。这个版本增加了多项改进自动创建输出目录支持多线程处理加速详细的错误日志记录进度条显示自动跳过已处理文件import os import cv2 import argparse from tqdm import tqdm from multiprocessing import Pool, cpu_count import logging # 配置日志记录 logging.basicConfig( filenameccpd_parser.log, levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s ) class CCPDParser: def __init__(self, args): self.args args self.ensure_dirs() def ensure_dirs(self): 确保输出目录存在 os.makedirs(self.args.image_output, exist_okTrue) os.makedirs(self.args.label_output, exist_okTrue) def parse_single_file(self, filename): 处理单个文件 try: if not filename.lower().endswith((.jpg, .jpeg, .png)): return # 解析文件名获取坐标 parts filename.split(-) if len(parts) 4: logging.warning(fInvalid filename format: {filename}) return # 提取车牌框坐标 bbox_part parts[2] lt, rb bbox_part.split(_) lx, ly map(int, lt.split()) rx, ry map(int, rb.split()) # 读取图像获取尺寸 img_path os.path.join(self.args.dataset_dir, filename) img cv2.imread(img_path) if img is None: logging.warning(fFailed to read image: {img_path}) if self.args.remove_corrupted: os.remove(img_path) return img_height, img_width img.shape[:2] # 计算YOLO格式坐标 width rx - lx height ry - ly cx lx width / 2 cy ly height / 2 # 归一化 cx / img_width cy / img_height width / img_width height / img_height # 确定车牌类别 (0:绿牌, 1:蓝牌) plate_type 0 if parts[3].startswith(0_) else 1 # 保存标注文件 base_name os.path.splitext(filename)[0] label_path os.path.join(self.args.label_output, f{base_name}.txt) with open(label_path, w) as f: f.write(f{plate_type} {cx:.6f} {cy:.6f} {width:.6f} {height:.6f}\n) # 复制图像到输出目录 if self.args.copy_images: output_img_path os.path.join(self.args.image_output, filename) if not os.path.exists(output_img_path): if self.args.symlink: os.symlink(img_path, output_img_path) else: shutil.copy2(img_path, output_img_path) except Exception as e: logging.error(fError processing {filename}: {str(e)}) def process_dataset(self): 处理整个数据集 filenames [f for f in os.listdir(self.args.dataset_dir) if f.lower().endswith((.jpg, .jpeg, .png))] # 使用多线程加速处理 with Pool(processescpu_count()) as pool: list(tqdm( pool.imap(self.parse_single_file, filenames), totallen(filenames), descProcessing CCPD dataset )) def main(): parser argparse.ArgumentParser(descriptionCCPD to YOLO format converter) parser.add_argument(--dataset-dir, requiredTrue, helpCCPD dataset directory) parser.add_argument(--image-output, defaultoutput/images, helpOutput directory for images) parser.add_argument(--label-output, defaultoutput/labels, helpOutput directory for labels) parser.add_argument(--copy-images, actionstore_true, helpCopy images to output directory) parser.add_argument(--symlink, actionstore_true, helpCreate symlinks instead of copying) parser.add_argument(--remove-corrupted, actionstore_true, helpRemove corrupted images) args parser.parse_args() parser CCPDParser(args) parser.process_dataset() if __name__ __main__: import shutil # 用于文件复制 main()关键改进点解析多线程处理使用Python的multiprocessing.Pool加速大规模数据集处理灵活的输出选项支持复制图像或创建符号链接节省空间完善的错误处理记录所有处理异常便于后续排查命令行参数支持方便集成到自动化流程中提示对于超大规模数据集建议使用--symlink参数创建符号链接而非复制文件可以节省大量磁盘空间和处理时间。4. 高级功能扩展与实战技巧基础功能实现后我们可以进一步扩展脚本的实用性。以下是几个值得添加的高级功能4.1 数据集拆分与验证通常我们需要将数据集拆分为训练集、验证集和测试集。可以添加以下代码import random from sklearn.model_selection import train_test_split def split_dataset(image_dir, label_dir, output_dir, ratios(0.7, 0.2, 0.1)): 拆分数据集为train/val/test # 获取所有基础文件名不带扩展名 basenames [os.path.splitext(f)[0] for f in os.listdir(image_dir)] # 拆分数据集 train, test train_test_split(basenames, test_sizeratios[2]) train, val train_test_split(train, test_sizeratios[1]/(ratios[0]ratios[1])) # 创建目录结构 splits {train: train, val: val, test: test} for split in splits: os.makedirs(os.path.join(output_dir, split, images), exist_okTrue) os.makedirs(os.path.join(output_dir, split, labels), exist_okTrue) # 移动文件到相应目录 for split, names in splits.items(): for name in names: # 移动图像文件 src_img os.path.join(image_dir, f{name}.jpg) dst_img os.path.join(output_dir, split, images, f{name}.jpg) os.rename(src_img, dst_img) # 移动标注文件 src_label os.path.join(label_dir, f{name}.txt) dst_label os.path.join(output_dir, split, labels, f{name}.txt) os.rename(src_label, dst_label)4.2 可视化验证为确保转换正确可以添加可视化验证功能def visualize_annotations(image_dir, label_dir, output_dir, num_samples5): 随机抽样可视化标注结果 os.makedirs(output_dir, exist_okTrue) samples random.sample(os.listdir(image_dir), min(num_samples, len(os.listdir(image_dir)))) for sample in samples: img_path os.path.join(image_dir, sample) label_path os.path.join(label_dir, os.path.splitext(sample)[0] .txt) img cv2.imread(img_path) if img is None: continue with open(label_path, r) as f: line f.readline().strip() cls_id, cx, cy, w, h map(float, line.split()) # 转换回绝对坐标 img_h, img_w img.shape[:2] x int((cx - w/2) * img_w) y int((cy - h/2) * img_h) width int(w * img_w) height int(h * img_h) # 绘制边界框 cv2.rectangle(img, (x, y), (xwidth, yheight), (0, 255, 0), 2) # 保存可视化结果 output_path os.path.join(output_dir, fvis_{sample}) cv2.imwrite(output_path, img)4.3 性能优化技巧处理大型数据集时性能至关重要。以下是几个优化建议批量处理使用Python的glob模块批量获取文件列表内存映射对于超大图像使用cv2.IMREAD_REDUCED_*标志并行I/O使用线程池处理文件读写缓存机制对已处理文件建立缓存避免重复处理优化后的处理循环示例from concurrent.futures import ThreadPoolExecutor import glob def optimized_processing(self): 优化后的处理流程 file_pattern os.path.join(self.args.dataset_dir, *.jpg) file_list glob.glob(file_pattern) with ThreadPoolExecutor(max_workers4) as executor: futures [] for file_path in file_list: futures.append(executor.submit(self.parse_single_file, os.path.basename(file_path))) for future in tqdm(futures, totallen(futures), descProcessing): future.result() # 获取结果主要是为了处理异常5. 实际应用与问题排查在实际使用中你可能会遇到以下常见问题及解决方案问题1文件名格式不符合预期解决方案添加更严格的格式验证记录错误文件def validate_filename(filename): parts filename.split(-) if len(parts) 4: return False # 检查坐标部分格式 if not (_ in parts[2] and in parts[2]): return False return True问题2图像损坏导致OpenCV读取失败解决方案使用更健壮的图像读取方式def robust_imread(img_path): try: img cv2.imread(img_path) if img is None: # 尝试其他读取方式 with open(img_path, rb) as f: img_bytes np.frombuffer(f.read(), np.uint8) img cv2.imdecode(img_bytes, cv2.IMREAD_COLOR) return img except Exception as e: logging.error(fFailed to read {img_path}: {str(e)}) return None问题3处理速度太慢优化建议使用更快的图像处理库如TurboJPEG减少不必要的图像复制预处理阶段降低图像分辨率# 安装TurboJPEG pip install PyTurboJPEG from turbojpeg import TurboJPEG jpeg TurboJPEG() def fast_imread(img_path): with open(img_path, rb) as f: return jpeg.decode(f.read())在完成所有处理后建议运行可视化验证脚本检查标注质量。我在处理一个包含10万张图像的CCPD数据集时发现大约有0.3%的文件因各种原因需要手动检查。对于工业级应用这种质量检查环节必不可少。

相关文章:

保姆级教程:用Python脚本一键解析CCPD车牌数据集,生成YOLO格式标注

零基础实战:Python自动化解析CCPD车牌数据集并生成YOLO标注文件 当你第一次打开CCPD数据集文件夹时,那些看似随机的文件名是否让你感到困惑?比如这个典型的例子:01-86_91-298&341_449&414-458&394_308&410_304&am…...

机器学习学习路径:10种类型与资源匹配指南

1. 机器学习入门:如何找到适合自己的学习路径第一次接触机器学习时,我像大多数初学者一样陷入了选择困难。网上充斥着各种教程、书籍和课程推荐,但真正开始学习后才发现,很多资源要么过于理论化,要么与我的实际需求不匹…...

real-anime-z电商应用案例:动漫风商品详情页图+短视频封面批量生成

real-anime-z电商应用案例:动漫风商品详情页图短视频封面批量生成 1. 项目背景与价值 在电商运营中,商品详情页和短视频封面是吸引用户点击的关键视觉元素。传统方式需要设计师手动制作,耗时耗力且难以保持风格统一。real-anime-z模型提供了…...

Qianfan-OCR入门必看:Apache 2.0协议下商用部署与微调合规操作指南

Qianfan-OCR入门必看:Apache 2.0协议下商用部署与微调合规操作指南 1. 项目概述 Qianfan-OCR是百度千帆推出的开源端到端文档智能多模态模型,基于4B参数的Qwen3-4B语言模型构建。作为Apache 2.0协议下的开源项目,它提供了完整的商用授权和微…...

别再乱用OneHot编码了!用Pandas的get_dummies处理分类变量,这3个参数能帮你避开90%的坑

别再乱用OneHot编码了!用Pandas的get_dummies处理分类变量,这3个参数能帮你避开90%的坑 在数据科学项目中,分类变量的编码是特征工程中最容易被低估的环节之一。许多从业者习惯性地使用OneHotEncoder或简单调用pd.get_dummies(),却…...

别再手动算积分了!用MATLAB integral函数搞定这6种‘奇葩’积分(含分段、无穷限)

别再手动算积分了!用MATLAB integral函数搞定这6种‘奇葩’积分(含分段、无穷限) 在科研计算和工程仿真中,积分问题就像隐藏在数据背后的幽灵——当你在信号处理中分析频谱特性时,在物理建模中求解场分布时&#xff0c…...

告别Three.js卡顿:用Potree在Web端流畅渲染百万级点云(附Vue集成踩坑实录)

百万级点云Web渲染实战:从Three.js到Potree的性能跃迁与Vue 3深度集成 当激光雷达扫描的.las文件在Three.js中卡成幻灯片时,我们终于意识到传统方案的天花板。某次城市级BIM项目验收前夜,甲方临时要求增加20个扫描站点的实时对比功能&#xf…...

从AlexNet到VGG19:为什么说‘小卷积核+深度’是CNN进化的关键一步?

从AlexNet到VGG19:小卷积核如何重塑深度学习的视觉革命 2014年,当牛津大学视觉几何组(Visual Geometry Group)提交那篇名为《Very Deep Convolutional Networks for Large-Scale Image Recognition》的论文时,可能没想…...

点云数据预处理避坑指南:为什么你的模型训练效果差?可能忽略了这三点(尺度/旋转/排列)

点云数据预处理避坑指南:为什么你的模型训练效果差?可能忽略了这三点(尺度/旋转/排列) 当你在训练点云深度学习模型时,是否遇到过这样的困境:按照教程跑通了PointNet在ShapeNet上的基准测试,换成…...

配置:从零搭建Python、PyCharm、PyTorch与Anaconda的AI开发环境

1. Python安装与配置 作为AI开发的基础语言,Python的安装是第一步。我推荐直接从官网下载最新稳定版,目前主流是Python 3.8-3.11版本。安装时有个关键细节经常被忽略:一定要勾选"Add Python to PATH"选项。这个选项相当于给系统装了…...

考研数学二:3个月零基础速成295分,我的极限、积分与微分方程实战笔记(附避坑指南)

考研数学二:3个月零基础速成295分,我的极限、积分与微分方程实战笔记(附避坑指南) 当推免失败的通知突然降临,距离考研仅剩三个月时,我面对着几乎空白的数学二基础。作为计算机专业考生,数学二是…...

3步彻底告别激活烦恼:KMS_VL_ALL_AIO智能激活方案实战指南

3步彻底告别激活烦恼:KMS_VL_ALL_AIO智能激活方案实战指南 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 你是否还在为Windows和Office的激活问题而烦恼?每次重装系统都…...

STM32F407 RTC入侵检测实战:用按键模拟入侵事件(附消抖技巧)

STM32F407 RTC入侵检测实战:用按键模拟入侵事件(附消抖技巧) 在嵌入式系统开发中,实时时钟(RTC)模块的安全功能往往被忽视,而入侵检测恰恰是保护关键数据免遭篡改的最后一道防线。本文将带您深入…...

解锁Bootloader前必读:联想ZUI手机保修政策、数据备份与常见失败原因解析

联想ZUI手机Bootloader解锁全指南:风险规避与实战解决方案 Bootloader解锁是Android设备深度定制的必经之路,但对于联想ZUI用户而言,这更像是一场需要精密准备的"外科手术"。去年社区调研数据显示,23%的变砖案例源于解锁…...

Labelme标注踩过的坑:中文标签、复杂遮挡、数据集划分,一个脚本全搞定

Labelme高级标注实战:破解中文标签、复杂遮挡与数据集划分难题 在计算机视觉项目中,数据标注质量直接决定模型性能上限。作为最受欢迎的标注工具之一,Labelme凭借其灵活性和开源特性成为众多研究团队的首选。但当项目规模扩大、场景复杂度提升…...

FPGA赛题进阶:手把手教你实现PGL22G平台的TF卡文件系统与UDP网络传输

FPGA赛题实战:PGL22G平台TF卡文件系统与UDP网络传输全解析 去年带队参加集创赛时,有个场景让我印象深刻:当队伍在最后48小时终于让TF卡里的图像通过UDP稳定传输到上位机时,整个实验室都沸腾了。这种从存储到网络的数据流打通&…...

嵌入式开发踩坑记:为什么我申请的0x1000内存,实际只有4KB?

嵌入式开发踩坑记:为什么我申请的0x1000内存,实际只有4KB? 刚接触嵌入式开发时,我曾在STM32的DMA缓冲区配置中写下uint8_t buffer[0x1000],满心以为这只是一个"小小的"4字节空间。直到程序运行时出现诡异的内…...

避坑指南:RK3588 USB DTS配置中那些容易搞混的`dr_mode`、`maximum-speed`和PHY引用

RK3588 USB DTS配置避坑手册:深度解析dr_mode、maximum-speed与PHY引用 当你在RK3588平台上调试USB功能时,是否遇到过这些情况:设备明明配置为OTG模式却无法切换主机角色,USB3.1接口只能跑在USB2.0速度,或者PHY引用错误…...

保姆级教程:在Ubuntu上为AM5728开发板交叉编译GPSD 3.18(附依赖库完整打包)

嵌入式Linux实战:AM5728平台GPSD 3.18交叉编译全流程解析 在工业物联网和自动驾驶领域,GPS模块的精准授时与定位功能已成为核心需求。本文将深入探讨如何在TI AM5728开发板上部署GPSD 3.18服务,重点解决交叉编译过程中的依赖库兼容性问题。不…...

如何优化SQL存储过程计算逻辑_减少循环内复杂运算

循环中反复调用函数是常见性能瓶颈,应将循环外可确定的值(如GETDATE()、配置查询)提前计算并存入变量,避免每次迭代重复执行。把循环里反复调用的函数提出来算一次存储过程中最常见的时间黑洞,是 WHILE 或游标循环里反…...

碧蓝航线自动化助手:5步轻松实现24/7智能托管

碧蓝航线自动化助手:5步轻松实现24/7智能托管 【免费下载链接】AzurLaneAutoScript Azur Lane bot (CN/EN/JP/TW) 碧蓝航线脚本 | 无缝委托科研,全自动大世界 项目地址: https://gitcode.com/gh_mirrors/az/AzurLaneAutoScript 还在为碧蓝航线的重…...

C#对接Bartender打印踩坑实录:从COM引用到多线程打印的避坑指南

C#对接Bartender打印踩坑实录:从COM引用到多线程打印的避坑指南 在工业级标签打印场景中,Bartender作为行业标杆软件,其稳定性与功能完备性毋庸置疑。但当开发者尝试通过C#调用Bartender的COM接口时,往往会遭遇各种"水土不服…...

大学生校园兼职微信小程序pf(文档+源码)_kaic

第5章 系统实现编程人员在搭建的开发环境中,会让各种编程技术一起呈现出最终效果。本节就展示关键部分的页面效果。5.1 管理员功能实现5.1.1 兼职管理图5.1 即为编码实现的兼职管理界面,管理员在兼职管理界面中可以对界面中显示,可以对兼职信…...

不止是监控:用IPMI在OpenBMC里玩点新花样,比如自定义主机-BMC消息通道

超越监控:用IPMI构建主机与BMC间的自定义通信管道 当大多数开发者还在用IPMI查询传感器数据或远程重启服务器时,一群极客已经发现了这个协议的隐藏潜力——它可以是主机操作系统与基板管理控制器(BMC)之间的高速公路,承…...

别再为WebSocket握手失败头疼了!手把手教你用Nginx 1.18+配置WSS反向代理(附SSL证书配置)

从零到一:Nginx反向代理WebSocket的终极避坑指南 凌晨三点,服务器监控突然告警——你的在线协作平台WebSocket连接全部断开。控制台里堆满了101 Switching Protocols错误,而本地测试时明明一切正常。这种场景对经历过生产环境WebSocket部署的…...

CANoe系统变量与CAPL脚本实战:如何用几行代码实现自动化信号触发?

CANoe系统变量与CAPL脚本实战:如何用几行代码实现自动化信号触发? 在汽车电子测试领域,效率提升往往隐藏在那些看似简单的自动化逻辑中。想象这样一个场景:当车速超过80km/h时,自动触发紧急制动信号;当电池…...

手势识别避坑指南:我用3100张图片训练YOLOv8踩过的5个坑

手势识别实战:从数据准备到模型优化的全流程避坑指南 在智能游戏系统和人机交互界面开发中,手势识别技术正变得越来越重要。无论是教育娱乐应用还是移动端AI应用,准确识别用户手势都是提升体验的关键。但实际开发中,从数据收集到模…...

从‘猫鼠游戏’到‘艺术创作’:用StyleGAN2-ADA的实战案例,聊聊不同GAN变体损失函数的设计哲学

从博弈论到艺术革命:StyleGAN2-ADA如何用损失函数重塑图像生成 想象一下,你正在教两个学生画画——一个负责鉴别画作真伪(判别器),另一个则试图伪造名画(生成器)。最初,这场教学就像…...

msdbg2.dll文件丢失找不到怎么办? 免费下载方法分享

在使用电脑系统时经常会出现丢失找不到某些文件的情况,由于很多常用软件都是采用 Microsoft Visual Studio 编写的,所以这类软件的运行需要依赖微软Visual C运行库,比如像 QQ、迅雷、Adobe 软件等等,如果没有安装VC运行库或者安装…...

别再只用plot了!用Matplotlib画函数曲线,这5个隐藏技巧让导师眼前一亮

别再只用plot了!用Matplotlib画函数曲线,这5个隐藏技巧让导师眼前一亮 第一次用Matplotlib画函数曲线时,我交上去的作业被导师用红笔圈出了十几个问题——坐标轴标签太小、曲线颜色难以区分、图例位置遮挡关键数据点。那次经历让我意识到&…...