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

[特殊字符]LabelMe标注转PaddleSeg数据集:多类掩码自动生成+配置文件输出(附完整Python脚本)

在深度学习中,数据集格式转换是一个绕不开的准备工作。本文分享一个完整的 Python 脚本,将 LabelMe 格式的图像分割数据.json标注)转换为 PaddleSeg 所需的格式。支持多类别、多边形标注、自动生成彩色掩码和配置文件,适用于分割任务的快速部署和训练准备。


✅ 项目背景

在使用 LabelMe 进行语义分割标注后,默认输出是 .json 文件,然而 PaddleSeg 框架训练模型需要 .jpg/.png 图像和灰度掩码对。本脚本帮助你:

  • 自动生成灰度掩码图(每类一个灰度值)

  • 可选生成彩色掩码图用于可视化

  • 创建训练集 / 验证集划分列表

  • 自动生成类别信息与数据集配置文件


📂输入目录结构(LabelMe格式)

input_dir/
├── image/
│   ├── xxx.jpg
│   └── ...
└── labels/├── xxx.json└── ...

🗂输出目录结构(PaddleSeg格式)

output_dir/
├── images/                ← 图像副本
├── labels/                ← 灰度标签图(掩码)
├── colored_masks/         ← 可视化彩色掩码(可选)
├── train_list.txt         ← PaddleSeg训练文件列表
├── val_list.txt           ← PaddleSeg验证文件列表
├── class_info.json        ← 类别定义与颜色说明
└── dataset_config.json    ← PaddleSeg数据集配置文件

🔨支持特性

  • ✅ 多类分割支持(自定义类别映射)

  • ✅ 多边形标注自动转换为掩码

  • ✅ 彩色掩码图自动生成

  • ✅ 自动划分训练/验证集

  • ✅ 输出JSON格式的类别定义与PaddleSeg配置


📌主要函数说明

1. convert_labelme_to_paddleseg(...)

核心转换函数,读取图像和标注,生成掩码和文件结构。

2. create_mask_from_polygons(...)

将LabelMe中多边形标注转换为灰度掩码图。

3. create_colored_mask(...)

按类别ID生成RGB彩色掩码(用于可视化)。

4. create_train_val_split(...)

自动划分训练集和验证集,输出 PaddleSeg 需要的 .txt 文件列表。


🧠类别定义与颜色映射(可修改)

class_mapping = {'bp': 1,  # 红色'kd': 2   # 绿色
}
color_map = {0: [0, 0, 0],       # 背景 - 黑色1: [255, 0, 0],     # bp - 红色2: [0, 255, 0],     # kd - 绿色
}

🖥使用示例(修改路径后直接运行)

if __name__ == "__main__":input_dir = r"C:\Users\WIN10\Desktop\seg_change\bp"output_dir = r"c:\Users\WIN10\Desktop\seg_change\paddleseg_bp"class_mapping = {'bp': 1,'kd': 2}convert_labelme_to_paddleseg(input_dir, output_dir, class_mapping, generate_colored_masks=True)create_train_val_split(output_dir, train_ratio=0.8)

🎉运行结果

运行后终端会输出:

转换完成!
成功处理: 123 个文件
错误: 0 个文件
输出目录: paddleseg_bp
训练集: 98 个样本
验证集: 25 个样本

📦完整代码

完整代码:

import os
import json
import cv2
import numpy as np
from PIL import Image, ImageDraw
import shutil
from pathlib import Pathdef load_labelme_json(json_path):"""加载LabelMe JSON文件"""try:with open(json_path, 'r', encoding='utf-8') as f:data = json.load(f)return dataexcept Exception as e:print(f"加载JSON文件失败 {json_path}: {e}")return Nonedef create_mask_from_polygons(image_shape, shapes, class_mapping):"""从多边形创建分割掩码"""height, width = image_shape[:2]mask = np.zeros((height, width), dtype=np.uint8)for shape in shapes:if shape['shape_type'] == 'polygon':label = shape['label']if label in class_mapping:class_id = class_mapping[label]points = shape['points']# 转换为PIL可用的格式polygon_points = [(int(x), int(y)) for x, y in points]# 创建PIL图像用于绘制多边形pil_image = Image.fromarray(mask)draw = ImageDraw.Draw(pil_image)draw.polygon(polygon_points, fill=class_id)mask = np.array(pil_image)return maskdef create_colored_mask(mask, class_mapping, color_map=None):"""创建彩色掩码用于可视化"""if color_map is None:# 默认颜色映射color_map = {0: [0, 0, 0],       # 背景 - 黑色1: [255, 0, 0],     # bp - 红色2: [0, 255, 0],     # kd - 绿色}height, width = mask.shapecolored_mask = np.zeros((height, width, 3), dtype=np.uint8)for class_id, color in color_map.items():colored_mask[mask == class_id] = colorreturn colored_maskdef convert_labelme_to_paddleseg(input_dir, output_dir, class_mapping=None, generate_colored_masks=True):"""将LabelMe格式转换为PaddleSeg格式"""if class_mapping is None:# 默认类别映射:背景=0, bp=1, kd=2class_mapping = {'bp': 1, 'kd': 2}input_path = Path(input_dir)output_path = Path(output_dir)# 创建输出目录images_dir = output_path / 'images'labels_dir = output_path / 'labels'images_dir.mkdir(parents=True, exist_ok=True)labels_dir.mkdir(parents=True, exist_ok=True)# 如果需要生成彩色掩码,创建彩色掩码目录if generate_colored_masks:colored_masks_dir = output_path / 'colored_masks'colored_masks_dir.mkdir(parents=True, exist_ok=True)# 获取所有图像和标注文件image_dir = input_path / 'image'label_dir = input_path / 'labels'if not image_dir.exists() or not label_dir.exists():print(f"错误:找不到图像目录 {image_dir} 或标注目录 {label_dir}")return# 获取所有图像文件image_files = list(image_dir.glob('*.jpg')) + list(image_dir.glob('*.png'))processed_count = 0error_count = 0# 定义颜色映射color_map = {0: [0, 0, 0],       # 背景 - 黑色1: [255, 0, 0],     # bp - 红色2: [0, 255, 0],     # kd - 绿色}for image_file in image_files:try:# 对应的JSON文件json_file = label_dir / f"{image_file.stem}.json"if not json_file.exists():print(f"警告:找不到对应的标注文件 {json_file}")continue# 加载图像image = cv2.imread(str(image_file))if image is None:print(f"错误:无法加载图像 {image_file}")error_count += 1continue# 加载标注labelme_data = load_labelme_json(json_file)if labelme_data is None:error_count += 1continue# 创建掩码mask = create_mask_from_polygons(image.shape, labelme_data.get('shapes', []), class_mapping)# 保存图像和掩码output_image_path = images_dir / image_file.nameoutput_mask_path = labels_dir / f"{image_file.stem}.png"# 复制图像shutil.copy2(image_file, output_image_path)# 保存灰度掩码cv2.imwrite(str(output_mask_path), mask)# 生成并保存彩色掩码if generate_colored_masks:colored_mask = create_colored_mask(mask, class_mapping, color_map)colored_mask_path = colored_masks_dir / f"{image_file.stem}_colored.png"cv2.imwrite(str(colored_mask_path), cv2.cvtColor(colored_mask, cv2.COLOR_RGB2BGR))processed_count += 1if processed_count % 50 == 0:print(f"已处理 {processed_count} 个文件...")except Exception as e:print(f"处理文件时出错 {image_file}: {e}")error_count += 1print(f"\n转换完成!")print(f"成功处理: {processed_count} 个文件")print(f"错误: {error_count} 个文件")print(f"输出目录: {output_path}")# 创建类别信息文件create_class_info_file(output_path, class_mapping, color_map)# 创建数据集配置文件create_dataset_config(output_path, processed_count, len(class_mapping) + 1)def create_class_info_file(output_dir, class_mapping, color_map=None):"""创建类别信息文件"""class_info = {'num_classes': len(class_mapping) + 1,  # +1 for background'class_mapping': {'background': 0, **class_mapping},'class_names': ['background'] + list(class_mapping.keys())}# 添加颜色映射信息if color_map:class_info['color_mapping'] = color_mapclass_info['color_description'] = {0: 'background - black',1: 'bp - red', 2: 'kd - green'}class_info_path = output_dir / 'class_info.json'with open(class_info_path, 'w', encoding='utf-8') as f:json.dump(class_info, f, ensure_ascii=False, indent=2)print(f"类别信息已保存到: {class_info_path}")def create_dataset_config(output_dir, total_samples, num_classes):"""创建数据集配置文件"""config = {'dataset_info': {'total_samples': total_samples,'image_dir': 'images','label_dir': 'labels','colored_mask_dir': 'colored_masks','image_format': 'jpg','label_format': 'png'},'paddleseg_config': {'dataset_root': str(output_dir),'train_dataset': {'type': 'Dataset','dataset_root': str(output_dir),'train_path': 'train_list.txt','num_classes': num_classes,'transforms': [{'type': 'ResizeStepScaling', 'min_scale_factor': 0.5, 'max_scale_factor': 2.0, 'scale_step_size': 0.25},{'type': 'RandomPaddingCrop', 'crop_size': [512, 512]},{'type': 'RandomHorizontalFlip'},{'type': 'RandomDistort'},{'type': 'Normalize'}]},'val_dataset': {'type': 'Dataset','dataset_root': str(output_dir),'val_path': 'val_list.txt','num_classes': num_classes,'transforms': [{'type': 'Normalize'}]}}}config_path = output_dir / 'dataset_config.json'with open(config_path, 'w', encoding='utf-8') as f:json.dump(config, f, ensure_ascii=False, indent=2)print(f"数据集配置已保存到: {config_path}")def create_train_val_split(output_dir, train_ratio=0.8):"""创建训练和验证集分割文件"""images_dir = Path(output_dir) / 'images'labels_dir = Path(output_dir) / 'labels'# 获取所有图像文件image_files = list(images_dir.glob('*.jpg')) + list(images_dir.glob('*.png'))# 随机打乱np.random.shuffle(image_files)# 分割split_idx = int(len(image_files) * train_ratio)train_files = image_files[:split_idx]val_files = image_files[split_idx:]# 创建训练集列表train_list_path = Path(output_dir) / 'train_list.txt'with open(train_list_path, 'w') as f:for img_file in train_files:label_file = labels_dir / f"{img_file.stem}.png"if label_file.exists():f.write(f"images/{img_file.name} labels/{label_file.name}\n")# 创建验证集列表val_list_path = Path(output_dir) / 'val_list.txt'with open(val_list_path, 'w') as f:for img_file in val_files:label_file = labels_dir / f"{img_file.stem}.png"if label_file.exists():f.write(f"images/{img_file.name} labels/{label_file.name}\n")print(f"训练集: {len(train_files)} 个样本")print(f"验证集: {len(val_files)} 个样本")print(f"训练集列表: {train_list_path}")print(f"验证集列表: {val_list_path}")def main():# 输入和输出路径input_dir = r"C:\Users\WIN10\Desktop\seg_change\bp"output_dir = r"c:\Users\WIN10\Desktop\seg_change\paddleseg_bp"# 类别映射(支持多类分割)class_mapping = {'bp': 1,  # bp类别映射为1'kd': 2   # kd类别映射为2,背景为0}print("开始转换LabelMe数据为PaddleSeg格式...")print(f"输入目录: {input_dir}")print(f"输出目录: {output_dir}")print(f"类别映射: {class_mapping}")# 执行转换(启用彩色掩码生成)convert_labelme_to_paddleseg(input_dir, output_dir, class_mapping, generate_colored_masks=True)# 创建训练验证集分割print("\n创建训练验证集分割...")create_train_val_split(output_dir, train_ratio=0.8)print("\n转换完成!数据集已准备好用于PaddleSeg训练。")print("\n使用说明:")print("1. 图像文件保存在: paddleseg_dataset/images/")print("2. 标签掩码保存在: paddleseg_dataset/labels/")print("3. 彩色掩码保存在: paddleseg_dataset/colored_masks/")print("4. 训练集列表: paddleseg_dataset/train_list.txt")print("5. 验证集列表: paddleseg_dataset/val_list.txt")print("6. 类别信息: paddleseg_dataset/class_info.json")print("7. 数据集配置: paddleseg_dataset/dataset_config.json")print("\n类别说明:")print("- 背景: 0 (黑色)")print("- bp标签: 1 (红色)")print("- kd标签: 2 (绿色)")if __name__ == "__main__":main()

💡结语

本脚本适用于:

  • PaddleSeg语义分割模型训练前数据准备

  • 多类别图像分割任务标注转换

  • 可视化检查和配置文件自动化生成

欢迎交流指正,若对你有帮助请点个赞 👍 或收藏 🌟,后续我会分享 PaddleSeg 训练流程 + 推理部署代码。


http://www.dtcms.com/a/275626.html

相关文章:

  • Apache Iceberg数据湖高级特性及性能调优
  • 玩转rhel9 Apache
  • linux 系统找出磁盘IO占用元凶 —— 筑梦之路
  • Java零基础笔记12(Java编程核心:面向对象编程高级{常用API、GUI编程})
  • PyTorch多层感知机模型构建与MNIST分类训练
  • 【BurpSuite 2025最新版插件开发】基础篇10(完):日志记录与调试
  • 请求服务端获取broker的机房归属信息异常
  • 剑指offer56_数组中唯一只出现一次的数字
  • JavaScript加强篇——第七章 浏览器对象与存储要点
  • NLP:RNN文本生成案例分享
  • 关于 验证码系统 详解
  • S7-200 SMART PLC:硬件、原理及接线特点全解析
  • Transformer基础
  • Linux驱动09 --- 环境搭建
  • 零基础 “入坑” Java--- 九、类和对象(二)
  • 【YOLOv8-obb部署至RK3588】模型训练→转换RKNN→开发板部署
  • 详解梯度消失和梯度爆炸(反向传播)?
  • 2025年亚太杯(中文赛项)数学建模B题【疾病的预测与大数据分析】原创论文讲解(含完整python代码)
  • 【Java入门到精通】(三)Java基础语法(下)
  • # win11 连接共享打印机报错:0x00000040 或者 0x00000709或者 x0000011b 的解决方法
  • ubuntu系统宝塔进程守护管理器开机启动失败问题
  • 设计模式:单一职责原则
  • 注解驱动的知识中枢:MCPServer赋能AI业务的技术架构与实践
  • Mastercam 2026中文版网盘资源下载与安装教程共享
  • JAVA--双亲委派机制
  • 历史数据分析——云南白药
  • Matplotlib 全面使用指南 -- 紧密布局指南 Tight layout guide
  • Leetcode力扣解题记录--第3题(滑动窗口)
  • Python 实战:构建 Git 自动化助手
  • pgsql模板是什么?