网站首页 > 基础教程 正文
本文摘要
本文主要演示如何使用LabelImg标注菜品数据集,目前数据集有2000+已标注的菜品目标图片,用于后续的菜品目标深度学习模型训练(包含已标注数据集,点击原文链接,关注回复“源码或数据集”,免费获取)
原文链接:Yolov10菜品的目标检测模型训练及推理(包括数据集、训练及推理源码)
数据格式
目标检测的数据,在一张图像中,需要以最小外接矩形标记出各个目标区域的位置和类别,
一般的目标区域位置用一个矩形框来表示,一般用以下3种方式表达:
表达方式 | 说明 |
x1,y1,x2,y2 | (x1,y1)为左上角坐标,(x2,y2)为右下角坐标 |
x1,y1,w,h | (x1,y1)为左上角坐标,w为目标区域宽度,h为目标区域高度 |
xc,yc,w,h | (xc,yc)为目标区域中心坐标,w为目标区域宽度,h为目标区域高度 |
常见的目标检测数据集:
- VOC采用的[x1,y1,x2,y2],表示物体的最小外接矩形框,VOC数据指的是Pascal VOC比赛使用的数据。VOC数据是每个图像文件对应一个同名的xml文件,xml文件中标记物体框的坐标和类别等信息。
- COCO采用的[x1,y1,w,h],表示物体的最小外接矩形框,COCO数据是COCO比赛使用的数据。以json文件记录数据格式。
LabelImg可以标注VOC格式的数据,对图像做目标框的标注。
LabelImg标注工具下载
- 目标检测的数据标注,可以用LabelImg,下载地址:https://github.com/HumanSignal/labelImg/releases
- 建议直接下载其可执行程序,而不是通过pip安装使用。
- 是一款开源的图像标注工具,专门用于辅助计算机视觉任务的标注工作。它由python编写,并采用pyqt5作为图形用户界面的框架, LabelImg 是跨平台的,它可以在Windows、Linux 和 macOS 上运行,适应性强。
数据集准备与标注
目前对于菜品目标检测的已标注数据有2000+
打开labelImg,并打开images文件夹和xml文件夹,如下图所示:
点击画框create\nRectBox,调出十字光标,框”最小外接矩形框“,并输入标签,然后点击save,就保存了.xml标注文件
xml文件格式如下所示:
将LabelImg标注的数据集转为Yolo训练格式
yolo训练格式为与文件同名的.txt文件
0 0.5079166666666667 0.37916666666666665 0.0825 0.15
参数解释,从左到右,分别是:
class类名,例如:0表示label
中心横坐标与图像宽度比值
中心纵坐标与图像高度比值
bbox宽度与图像宽度比值
bbox高度与图像高度比值
知道规则后,我们使用如下脚本进行批量转换即可,核心代码如下所示:
import os
from lxml import etree
import shutil
def delete_folder(folder_path):
try:
shutil.rmtree(folder_path)
print(f'文件夹: {folder_path} 所有内容已删除!')
except Exception as e:
print(f'删除文件夹及其所有内容报错: {e}')
def xml_to_yolotxt(source_path, label_path, cls=''):
if not os.path.exists(label_path):
os.mkdir(label_path)
# 获取xml文件名称列表
files = os.listdir(source_path)
classes = get_classes(files, source_path)
print('---获取所有xml文件中的cls=', classes)
# classes = ['fire']
# 生成分类字典,列如{'apple':0,'banana':1}
class_dict = dict(zip(classes,range(len(classes))))
print('------生成分类字典=', class_dict)
# class_dict = {'fire': 1}
# class_dict = {cls: 0}
print('---------------begin convert----')
count = 0
if 1:
for file in files:
count = count + 1
# print('------------', file)
convert_xml2txt(file, source_path, label_path, class_dict, norm=True)
print('---------------finish convert----,count=', count)
def convert_xml2txt(file_name, source_path, label_path, class_dict, norm=False):
# 创建txt文件,并打开、写入
new_name = file_name.split('.')[0] + '.txt'
f = open(label_path+'/'+new_name,'w')
print('-----------------------name=', new_name)
with open(source_path+file_name,'rb') as fb:
# 开始解析xml文件,获取图像尺寸
xml = etree.HTML(fb.read())
width = int(xml.xpath('//size/width/text()')[0])
height = int(xml.xpath('//size/height/text()')[0])
# 获取对象标签
labels = xml.xpath('//object') # 单张图片中的目标数量 len(labels)
for label in labels:
name = label.xpath('./name/text()')[0]
label_class = class_dict[name]
xmin = int(label.xpath('./bndbox/xmin/text()')[0])
xmax = int(label.xpath('./bndbox/xmax/text()')[0])
ymin = int(label.xpath('./bndbox/ymin/text()')[0])
ymax = int(label.xpath('./bndbox/ymax/text()')[0])
# xyxy-->xywh,且归一化
if norm :
dw = 1 / width
dh = 1 / height
x_center = (xmin + xmax) / 2
y_center = (ymax + ymin) / 2
w = (xmax - xmin)
h = (ymax - ymin)
x, y, w, h = x_center * dw, y_center * dh, w * dw, h * dh
f.write(str(label_class)+' '+str(x)+' '+str(y)+' '+str(w)+' '+str(h)+' '+'\n')
#关闭文件
f.close()
# 获取分类名称列表
def get_classes(files, source_path):
class_set = set([])
for file in files:
with open(source_path+file,'rb') as fb:
#解析xml文件
xml = etree.HTML(fb.read())
labels = xml.xpath('//object')
for label in labels:
name = label.xpath('./name/text()')[0]
class_set.add(name)
return list(class_set)
if __name__ == '__main__':
source_path = 'C:/mysel/food_plate_images/annotations_xmls/'
label_path = 'C:/mysel/food_plate_images/labels/'
delete_folder(label_path)
xml_to_yolotxt(source_path, label_path)
Yolo
yolo训练目录文件结构
|── train # 训练集
| |── labels
│ ├── road0.txt
│ ├── road1.txt
│ ├── road2.txt
│ | ...
| |── images
│ ├── road0.jpg
│ ├── road1.jpg
│ ├── road2.jpg
│ | ...
|── val # 验证集
| |── labels
│ ├── road3.txt
│ ├── ...
| |── images
│ ├── road3.jpg
│ | ...
|── test # 测试集
| |── labels
│ ├── road4.txt
│ | ...
| |── images
│ ├── road4.jpg
│ | ...
使用脚本分数据集
使用脚本将所有数据按照80%、10%、10%分成训练集、验证集、测试集
import os
import shutil
import random
from math import ceil
# 定义源文件夹路径和目标文件夹路径
source_path_images = 'C:/ai_datasets/菜品目标检测数据集(餐盘标注2000+)/food_plate_images/images/'
source_path_labels = 'C:/ai_datasets/菜品目标检测数据集(餐盘标注2000+)/food_plate_images/labels/'
# 80% 的文件
train_folder_images = 'C:/ai_datasets/菜品目标检测数据集(餐盘标注2000+)/yolo_images/train/images'
train_folder_labels = 'C:/ai_datasets/菜品目标检测数据集(餐盘标注2000+)/yolo_images/train/labels'
# 10% 的文件
val_folder_images = 'C:/ai_datasets/菜品目标检测数据集(餐盘标注2000+)/yolo_images/val/images'
val_folder_labels = 'C:/ai_datasets/菜品目标检测数据集(餐盘标注2000+)/yolo_images/val/labels'
# 10% 的文件
test_folder_images = 'C:/ai_datasets/菜品目标检测数据集(餐盘标注2000+)/yolo_images/test/images'
test_folder_labels = 'C:/ai_datasets/菜品目标检测数据集(餐盘标注2000+)/yolo_images/test/labels'
def delete_folder(folder_path):
try:
shutil.rmtree(folder_path)
print(f'文件夹: {folder_path} 所有内容已删除!')
except Exception as e:
print(f'删除文件夹及其所有内容报错: {e}')
delete_folder(train_folder_images)
delete_folder(train_folder_labels)
delete_folder(val_folder_images)
delete_folder(val_folder_labels)
delete_folder(test_folder_images)
delete_folder(test_folder_labels)
# 确保目标文件夹存在,不存在则创建
os.makedirs(train_folder_images, exist_ok=True)
os.makedirs(train_folder_labels, exist_ok=True)
os.makedirs(val_folder_images, exist_ok=True)
os.makedirs(val_folder_labels, exist_ok=True)
os.makedirs(test_folder_images, exist_ok=True)
os.makedirs(test_folder_labels, exist_ok=True)
# 获取所有 .jpg 文件
jpg_files = [f for f in os.listdir(source_path_images) if f.endswith('.jpg')]
# 随机打乱文件顺序
random.shuffle(jpg_files)
# 计算每个文件夹的分配数量
total_files = len(jpg_files)
train_count = ceil(total_files * 0.8)
val_count = ceil(total_files * 0.1)
test_count = total_files - train_count - val_count
# 分配文件
train_files = jpg_files[:train_count]
val_files = jpg_files[train_count:train_count + val_count]
test_files = jpg_files[train_count + val_count:]
# 复制文件到对应文件夹
def copy_files(file_list, source_image_folder, destination_image_folder, source_txt_folder, dest_txt_folder):
for file_name in file_list:
print(f'处理---- file=', file_name)
# 处理 .jpg 文件
jpg_source_file = os.path.join(source_image_folder, file_name)
jpg_destination_file = os.path.join(destination_image_folder, file_name)
shutil.copy(jpg_source_file, jpg_destination_file)
# 处理对应的 .txt 文件
txt_file_name = file_name.replace('.jpg', '.txt')
txt_source_file = os.path.join(source_txt_folder, txt_file_name)
if os.path.exists(txt_source_file): # 如果存在对应的 .txt 文件
txt_destination_file = os.path.join(dest_txt_folder, txt_file_name)
shutil.copy(txt_source_file, txt_destination_file)
# 执行复制
copy_files(train_files, source_path_images, train_folder_images, source_path_labels, train_folder_labels)
copy_files(val_files, source_path_images, val_folder_images, source_path_labels, val_folder_labels)
copy_files(test_files, source_path_images, test_folder_images, source_path_labels, test_folder_labels)
Yolo data.yaml
train: C:/xxx/菜品目标检测数据集2600+/images/train
val: C:/xxx/菜品目标检测数据集2600+/images/val
test: C:/xxx/菜品目标检测数据集2600+/images/test
nc: 1
names: ["label"]
- 上一篇: JavaScript 内置对象——Math,你真的了解吗?
- 下一篇: Python异步IO原理
猜你喜欢
- 2024-12-12 JS逆向so easy?以Python方式进行签名算法还原(附案例分享)
- 2024-12-12 知识付费阿里云视频点播功能
- 2024-12-12 超强指南!Golang 并发编程
- 2024-12-12 python办公案例:使用联系人信息,如何制作通讯录VCF文件
- 2024-12-12 Linux C 编程 - 详解floor函数、ceil函数和round函数
- 2024-12-12 根据年月计算当月有哪几个周,及每周的起止日期
- 2024-12-12 借助云开发实现短信验证码的发送,你会了么
- 2024-12-12 游戏系统中的伪随机和真随机算法实现Python3
- 2024-12-12 Python tkinter 点名工具
- 2024-12-12 Ae随机表达式控制小数点位数
- 最近发表
- 标签列表
-
- gitpush (61)
- pythonif (68)
- location.href (57)
- tail-f (57)
- pythonifelse (59)
- deletesql (62)
- c++模板 (62)
- css3动画 (57)
- c#event (59)
- linuxgzip (68)
- 字符串连接 (73)
- nginx配置文件详解 (61)
- html标签 (69)
- c++初始化列表 (64)
- exec命令 (59)
- canvasfilltext (58)
- mysqlinnodbmyisam区别 (63)
- arraylistadd (66)
- node教程 (59)
- console.table (62)
- c++time_t (58)
- phpcookie (58)
- mysqldatesub函数 (63)
- window10java环境变量设置 (66)
- c++虚函数和纯虚函数的区别 (66)