如何用labelimg标注yolo数据集,并利用工具自动划分数据集
·
如何用LabelImg标注YOLO数据集,并利用工具自动划分数据集
一、引言:什么是YOLO数据集标注?在计算机视觉领域,YOLO(You Only Look Once)是一种高效的目标检测算法。要训练一个YOLO模型,首先需要准备好标注好的数据集。标注数据意味着在图像中标记出目标物体的位置和类别。LabelImg是一款免费开源的图像标注工具,支持YOLO格式的标注输出。本文将带你从零开始,使用LabelImg完成数据标注,并利用Python脚本自动划分训练集与验证集。## 二、基础概念:YOLO标注格式解析YOLO格式的标注文件是一个文本文件(.txt),每一行代表一个目标物体,格式如下:class_id x_center y_center width height其中:- class_id:类别编号(从0开始)- x_center, y_center:边界框中心点的相对坐标(值在0到1之间)- width, height:边界框的相对宽度和高度(值在0到1之间)例如,一张图片中有一个猫(类别0)和一个狗(类别1),标注文件内容可能为:0 0.5 0.4 0.3 0.21 0.2 0.6 0.15 0.25## 三、LabelImg安装与基本使用### 3.1 安装LabelImgLabelImg支持Windows、Linux和macOS。最简便的安装方式是通过pip:bashpip install labelimg如果遇到依赖问题,也可以从GitHub克隆源码安装:bashgit clone https://github.com/tzutalin/labelImg.gitcd labelImgpip install -r requirements/requirements-linux-python3.txtmake qt5py3python labelImg.py### 3.2 配置标注模式启动LabelImg后,需要设置输出格式为YOLO:1. 点击菜单栏 View → Auto Save mode(自动保存)2. 点击 File → Change Output Dir 选择标注文件保存目录3. 点击 File → Change Saved Classes 或直接编辑 classes.txt 文件,写入类别名称(每行一个)例如,创建一个 classes.txt 文件:personcardogcat### 3.3 标注流程1. 点击 Open Dir 选择包含图片的文件夹2. 点击 Create RectBox 或按快捷键 w 开始绘制矩形框3. 框选目标后,在弹出的对话框中选择类别4. 按 Ctrl+S 保存标注(如果开启了自动保存模式则自动保存)5. 按 d 切换到下一张图片标注完成后,每个图片会生成一个同名的 .txt 文件,例如 image1.jpg 对应 image1.txt。## 四、YOLO数据集目录结构一个标准的YOLO数据集目录结构如下:dataset/├── images/│ ├── train/│ │ ├── img1.jpg│ │ └── img2.jpg│ └── val/│ ├── img3.jpg│ └── img4.jpg├── labels/│ ├── train/│ │ ├── img1.txt│ │ └── img2.txt│ └── val/│ ├── img3.txt│ └── img4.txt└── data.yaml````data.yaml` 文件内容示例:yamltrain: ./dataset/images/trainval: ./dataset/images/valnc: 4names: [‘person’, ‘car’, ‘dog’, ‘cat’]## 五、自动划分数据集的Python脚本当我们手动标注完所有图片后,通常需要将数据划分为训练集和验证集。下面是一个完整的Python脚本,它可以自动完成这个任务。### 5.1 基础版本:简单随机划分pythonimport osimport randomimport shutildef split_dataset(source_images_dir, source_labels_dir, output_dir, train_ratio=0.8): “”" 将标注好的数据集划分为训练集和验证集 参数: source_images_dir: 原始图片文件夹路径 source_labels_dir: 原始标注文件文件夹路径 output_dir: 输出数据集根目录 train_ratio: 训练集比例,默认0.8 “”" # 获取所有图片文件名(假设为.jpg格式) image_files = [f for f in os.listdir(source_images_dir) if f.endswith(‘.jpg’)] random.shuffle(image_files) # 随机打乱 # 计算划分点 split_point = int(len(image_files) * train_ratio) train_files = image_files[:split_point] val_files = image_files[split_point:] # 创建输出目录结构 for subset in [‘train’, ‘val’]: os.makedirs(os.path.join(output_dir, ‘images’, subset), exist_ok=True) os.makedirs(os.path.join(output_dir, ‘labels’, subset), exist_ok=True) # 复制训练集文件 for filename in train_files: # 复制图片 src_img = os.path.join(source_images_dir, filename) dst_img = os.path.join(output_dir, ‘images’, ‘train’, filename) shutil.copy2(src_img, dst_img) # 复制对应的标注文件(将.jpg替换为.txt) label_filename = filename.replace(‘.jpg’, ‘.txt’) src_label = os.path.join(source_labels_dir, label_filename) dst_label = os.path.join(output_dir, ‘labels’, ‘train’, label_filename) if os.path.exists(src_label): shutil.copy2(src_label, dst_label) # 复制验证集文件(同理) for filename in val_files: src_img = os.path.join(source_images_dir, filename) dst_img = os.path.join(output_dir, ‘images’, ‘val’, filename) shutil.copy2(src_img, dst_img) label_filename = filename.replace(‘.jpg’, ‘.txt’) src_label = os.path.join(source_labels_dir, label_filename) dst_label = os.path.join(output_dir, ‘labels’, ‘val’, label_filename) if os.path.exists(src_label): shutil.copy2(src_label, dst_label) print(f"数据集划分完成!训练集:{len(train_files)}张,验证集:{len(val_files)}张")# 使用示例if name == “main”: # 假设标注好的图片在 ./raw_data/images 中,标注在 ./raw_data/labels 中 split_dataset( source_images_dir=“./raw_data/images”, source_labels_dir=“./raw_data/labels”, output_dir=“./dataset”, train_ratio=0.8 )### 5.2 进阶版本:自动生成data.yaml并验证完整性下面的脚本增加了更多功能:自动生成 `data.yaml` 文件、检查每个图片是否有对应的标注文件、支持多种图片格式。pythonimport osimport randomimport shutilfrom pathlib import Pathclass YOLODatasetSplitter: “”“YOLO数据集自动划分工具”“” def init(self, source_dir, output_dir, classes_file, train_ratio=0.8, val_ratio=0.2, seed=42): “”" 初始化划分器 参数: source_dir: 源数据目录(包含images和labels子文件夹) output_dir: 输出数据集目录 classes_file: 类别名称文件路径 train_ratio: 训练集比例 val_ratio: 验证集比例(剩余部分为测试集,可选) seed: 随机种子,保证可复现 “”" self.source_dir = Path(source_dir) self.output_dir = Path(output_dir) self.classes_file = Path(classes_file) self.train_ratio = train_ratio self.val_ratio = val_ratio self.seed = seed # 支持的图片格式 self.image_extensions = [‘.jpg’, ‘.jpeg’, ‘.png’, ‘.bmp’] def run(self): “”“执行数据集划分”“” random.seed(self.seed) # 读取类别名称 with open(self.classes_file, ‘r’) as f: class_names = [line.strip() for line in f if line.strip()] print(f"检测到 {len(class_names)} 个类别:{class_names}“) # 获取所有图片文件 images_dir = self.source_dir / ‘images’ image_files = [] for ext in self.image_extensions: image_files.extend(list(images_dir.glob(f’{ext}‘))) # 过滤出有对应标注文件的图片 valid_images = [] labels_dir = self.source_dir / ‘labels’ for img_path in image_files: label_path = labels_dir / f"{img_path.stem}.txt" if label_path.exists(): valid_images.append(img_path) else: print(f"警告:图片 {img_path.name} 缺少标注文件,已跳过") print(f"有效图片数量:{len(valid_images)}“) random.shuffle(valid_images) # 计算划分数量 total = len(valid_images) train_count = int(total * self.train_ratio) val_count = int(total * self.val_ratio) # 划分数据集 train_images = valid_images[:train_count] val_images = valid_images[train_count:train_count + val_count] test_images = valid_images[train_count + val_count:] # 剩余作为测试集 # 复制文件到目标目录 for subset_name, subset_images in [(‘train’, train_images), (‘val’, val_images), (‘test’, test_images)]: if not subset_images: continue # 创建子目录 (self.output_dir / ‘images’ / subset_name).mkdir(parents=True, exist_ok=True) (self.output_dir / ‘labels’ / subset_name).mkdir(parents=True, exist_ok=True) for img_path in subset_images: # 复制图片 shutil.copy2(img_path, self.output_dir / ‘images’ / subset_name / img_path.name) # 复制标注文件 label_path = labels_dir / f”{img_path.stem}.txt" shutil.copy2(label_path, self.output_dir / ‘labels’ / subset_name / f"{img_path.stem}.txt") print(f"{subset_name}集:{len(subset_images)}张图片") # 生成data.yaml文件 yaml_content = f"“”# YOLO数据集配置文件# 自动生成于 {import(‘datetime’).datetime.now().strftime(’%Y-%m-%d %H:%M:%S’)}train: {self.output_dir / ‘images’ / ‘train’}val: {self.output_dir / ‘images’ / ‘val’}test: {self.output_dir / ‘images’ / ‘test’} if (self.output_dir / ‘images’ / ‘test’).exists() else '‘nc: {len(class_names)}names: {class_names}“”" with open(self.output_dir / ‘data.yaml’, ‘w’) as f: f.write(yaml_content.strip()) print(f"数据集划分完成!配置文件已生成:{self.output_dir / ‘data.yaml’}“)# 使用示例if name == “main”: splitter = YOLODatasetSplitter( source_dir=”./raw_data", output_dir=“./yolo_dataset”, classes_file=“./raw_data/classes.txt”, train_ratio=0.7, val_ratio=0.15, seed=2024 ) splitter.run()## 六、高级用法:数据增强与平衡处理在实际项目中,我们可能还需要处理类别不平衡问题或进行数据增强。以下是一些高级技巧:### 6.1 检查数据集平衡性pythondef analyze_dataset(labels_dir): “”“分析数据集中各类别样本数量”“” from collections import Counter class_counts = Counter() for label_file in Path(labels_dir).glob(’.txt’): with open(label_file, ‘r’) as f: for line in f: class_id = int(line.split()[0]) class_counts[class_id] += 1 print(“类别分布:”) for class_id, count in class_counts.most_common(): print(f” 类别 {class_id}: {count} 个实例")### 6.2 使用Albumentations进行数据增强pythonimport albumentations as Aimport cv2# 定义增强流水线transform = A.Compose([ A.HorizontalFlip(p=0.5), A.RandomBrightnessContrast(p=0.2), A.Rotate(limit=20, p=0.3), A.BboxParams(format=‘yolo’)])# 应用增强(需配合标注框一起转换)def augment_image(image_path, label_path): image = cv2.imread(image_path) with open(label_path, ‘r’) as f: bboxes = [list(map(float, line.strip().split())) for line in f] transformed = transform(image=image, bboxes=bboxes) return transformed[‘image’], transformed[‘bboxes’]```## 七、总结本文详细介绍了使用LabelImg标注YOLO数据集的完整流程,包括:1. 基础概念:理解了YOLO标注格式(class_id, x_center, y_center, width, height)2. 工具使用:掌握了LabelImg的安装、配置和标注操作方法3. 数据集划分:提供了两个Python脚本,从基础的文件复制到高级的自动生成配置文件4. 进阶技巧:介绍了数据平衡性分析和数据增强方法通过本文的学习,你应该能够:- 使用LabelImg高效标注自定义数据集- 编写Python脚本自动划分训练集/验证集/测试集- 生成符合YOLO训练要求的目录结构和配置文件- 对数据集进行质量检查和增强处理记住,一个好的数据集是训练优秀模型的基础。建议在标注完成后,仔细检查标注质量,确保每个目标都被正确框选和分类。祝你训练顺利!
更多推荐


所有评论(0)