【Labelme数据操作】LabelMe标注批量复制工具 - 完整教程

1. 脚本功能介绍

本脚本用于批量复制LabelMe标注信息,特别适用于以下场景:

  • 您有一批图片,其中物体位置、形状、大小基本相同
  • 您已经使用LabelMe标注了第一张图片
  • 您希望将第一张图片的标注信息快速复制到其他图片中
  • 需要自动适应不同图片的尺寸信息

核心功能:

  • 读取源JSON标注文件
  • 自动获取目标图片的尺寸信息
  • 保留所有标注形状、标签、颜色等信息
  • 为每张目标图片生成对应的LabelMe JSON标注文件
  • 支持多种常见图片格式

2. 环境依赖

2.1 安装必要的Python库

bash 复制代码
pip install opencv-python tqdm

2.2 依赖库说明

  • opencv-python: 用于读取图片获取尺寸信息
  • tqdm: 提供进度条显示,直观展示处理进度
  • json: 处理LabelMe的JSON标注文件
  • os: 文件路径操作
  • argparse: 命令行参数解析(当前版本已硬编码参数,但保留了扩展性)

3. 代码结构说明

3.1 主要函数

  • copy_labelme_annotations(): 核心功能函数,负责复制标注
  • main(): 程序入口,配置参数并调用核心函数

3.2 当前配置(您修改后的版本)

python 复制代码
def main():
    source_json="../1765555160.json"
    copy_labelme_annotations(
        source_json_path=source_json,
        image_dir="../bbbb",
        output_dir="../bbbb"
    )

当前配置说明:

  • 源标注文件:../1765555160.json
  • 图片目录:../bbbb
  • 输出目录:../bbbb(标注文件将保存在同一目录)

4. 使用方法

4.1 方法一:直接运行(推荐新手使用)

  1. 创建目录结构

    复制代码
    your_project/
    ├── copy_annotations.py    # 本脚本
    ├── 1765555160.json        # 您的源标注文件
    └── bbbb/                  # 存放所有图片的目录
        ├── image1.jpg
        ├── image2.jpg
        ├── image3.jpg
        └── ... 
  2. 将脚本参数修改为您实际的路径

    python 复制代码
    def main():
        source_json="../1765555160.json"  # 修改为您的源JSON文件路径
        copy_labelme_annotations(
            source_json_path=source_json,
            image_dir="../bbbb",         # 修改为您的图片目录
            output_dir="../bbbb"         # 修改为输出目录
        )
  3. 运行脚本

    bash 复制代码
    python copy_annotations.py

4.2 方法二:命令行参数方式(推荐高级用户)

如果您希望使用命令行参数,可以将main()函数修改为:

python 复制代码
def main():
    parser = argparse.ArgumentParser(description='批量复制LabelMe标注')
    parser.add_argument('--source_json', required=True, help='源标注JSON文件路径')
    parser.add_argument('--image_dir', required=True, help='图片目录路径')
    parser.add_argument('--output_dir', default=None, help='输出目录路径(可选,默认与image_dir相同)')
    
    args = parser.parse_args()
    
    copy_labelme_annotations(
        source_json_path=args.source_json,
        image_dir=args.image_dir,
        output_dir=args.output_dir
    )

命令行使用示例:

bash 复制代码
python copy_annotations.py \
    --source_json ../1765555160.json \
    --image_dir ../bbbb \
    --output_dir ../bbbb

5. 参数详细说明

5.1 函数参数

参数名 类型 必需 说明
source_json_path str 源标注JSON文件路径,包含第一张图片的标注信息
image_dir str 存放所有图片的目录路径
output_dir str 输出目录路径,如果为None则使用image_dir

5.2 支持的图片格式

脚本支持以下图片格式(不区分大小写):

  • .jpg / .jpeg
  • .png
  • .bmp
  • .tiff / .tif

5.3 JSON文件结构说明

生成的JSON文件包含以下关键字段:

  • version: LabelMe版本号
  • flags: 标签标志
  • shapes: 标注形状列表(点、线、矩形、多边形等)
  • imagePath: 对应的图片文件名
  • imageHeight: 图片高度
  • imageWidth: 图片宽度
  • imageData: None(不包含图像数据,减小文件大小)

6. 运行示例

6.1 预期输出

复制代码
源标注文件: ../1765555160.json
检测到 5 个标注对象
找到 15 张图片,将为 14 张图片复制标注
复制标注: 100%|██████████| 14/14 [00:02<00:00,  6.21it/s]
完成! 已为 14 张图片创建标注文件

6.2 生成的文件

../bbbb/目录下,每张图片都会生成对应的JSON文件:

复制代码
bbbb/
├── image1.jpg
├── image1.json    # 自动生成
├── image2.jpg
├── image2.json    # 自动生成
├── ...
└── 1765555160.jpg # 源图片(不会重复生成)

7. 注意事项

7.1 重要前提条件

图片内容相似性 :所有图片中的物体位置、形状、大小应基本相同

图片格式一致性 :确保图片是脚本支持的格式

路径正确性:检查所有路径是否存在,特别是源JSON文件和图片目录

7.2 常见问题及解决

问题1:无法读取图片
复制代码
警告: 无法读取图片 ../bbbb/image1.jpg, 跳过

解决方法:

  • 检查图片路径是否正确
  • 确认图片文件未损坏
  • 检查是否有权限读取该文件
问题2:JSON格式错误
复制代码
JSONDecodeError: Expecting value: line 1 column 1 (char 0)

解决方法:

  • 用文本编辑器打开源JSON文件,检查是否是有效的JSON格式
  • 确保JSON文件是UTF-8编码
  • 重新使用LabelMe保存标注文件
问题3:标注位置不准确

解决方法:

  • 如果图片尺寸差异较大,复制的标注可能位置不准确
  • 建议在LabelMe中手动调整位置
  • 或者使用图像配准算法先对齐图片

7.3 性能优化

  • 大图片处理:如果图片很大,处理速度会变慢,建议先缩小图片尺寸
  • 批量处理:一次处理大量图片时,确保有足够的内存
  • 文件备份:运行前建议备份原始标注文件,防止意外覆盖

8. 高级用法

8.1 自定义修改标注

如果您需要在复制过程中修改标注,可以在循环中添加自定义逻辑:

python 复制代码
# 在复制形状标注的循环中添加
for shape in source_data['shapes']:
    new_shape = shape.copy()
    
    # 示例:修改所有矩形的标签
    if new_shape['shape_type'] == 'rectangle':
        new_shape['label'] = 'modified_' + new_shape['label']
    
    # 示例:缩放所有坐标(适应不同尺寸)
    scale_x = width / source_data['imageWidth']
    scale_y = height / source_data['imageHeight']
    new_points = [[x * scale_x, y * scale_y] for x, y in new_shape['points']]
    new_shape['points'] = new_points
    
    new_data['shapes'].append(new_shape)

8.2 与其他工具集成

bash 复制代码
# 1. 先复制标注
python copy_annotations.py --source_json template.json --image_dir images

# 2. 然后用LabelMe验证和微调
labelme images/

9. 完整代码(带注释版本)

python 复制代码
import json
import os
import cv2
from tqdm import tqdm
import argparse

def copy_labelme_annotations(source_json_path, image_dir, output_dir=None):
    """
    将第一张图片的labelme标注信息复制到同一目录下的其他图片

    参数:
        source_json_path: 第一张已标注图片对应的JSON文件路径
        image_dir: 图片所在的目录
        output_dir: 输出目录,如果为None则使用image_dir
    
    功能流程:
        1. 读取源JSON文件
        2. 获取所有目标图片
        3. 为每张目标图片:
           - 读取图片获取尺寸
           - 创建新的标注数据
           - 复制标注形状
           - 保存JSON文件
    """
    # 读取源JSON文件
    with open(source_json_path, 'r', encoding='utf-8') as f:
        source_data = json.load(f)

    print(f"源标注文件: {source_json_path}")
    print(f"检测到 {len(source_data['shapes'])} 个标注对象")

    # 获取源图片信息
    source_image_path = source_data['imagePath']
    source_image_name = os.path.basename(source_image_path)

    # 设置输出目录
    if output_dir is None or output_dir.strip() == "":
        output_dir = image_dir

    # 创建输出目录(如果不存在)
    os.makedirs(output_dir, exist_ok=True)

    # 获取所有图片文件
    image_extensions = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.tif']
    all_images = []
    for f in os.listdir(image_dir):
        ext = os.path.splitext(f)[1].lower()
        if ext in image_extensions:
            all_images.append(f)

    # 排除源图片
    target_images = [img for img in all_images if img != source_image_name]

    print(f"找到 {len(all_images)} 张图片,将为 {len(target_images)} 张图片复制标注")

    # 处理每张目标图片
    successful_count = 0
    for image_name in tqdm(target_images, desc="复制标注"):
        image_path = os.path.join(image_dir, image_name)

        # 读取图片获取尺寸
        try:
            img = cv2.imread(image_path)
            if img is None:
                print(f"警告: 无法读取图片 {image_path}, 跳过")
                continue

            height, width = img.shape[:2]

            # 创建新的标注数据
            new_data = {
                "version": source_data.get("version", "5.0.1"),
                "flags": source_data.get("flags", {}),
                "shapes": [],
                "imagePath": image_name,
                "imageData": None,  # 不包含图像数据以减小文件大小
                "imageHeight": height,
                "imageWidth": width
            }

            # 复制形状标注
            for shape in source_data['shapes']:
                new_shape = shape.copy()
                # 确保shape_type字段存在
                if 'shape_type' not in new_shape:
                    new_shape['shape_type'] = 'polygon'
                new_data['shapes'].append(new_shape)

            # 生成输出JSON文件名
            output_json_name = os.path.splitext(image_name)[0] + '.json'
            output_json_path = os.path.join(output_dir, output_json_name)

            # 保存新的JSON文件
            with open(output_json_path, 'w', encoding='utf-8') as f:
                json.dump(new_data, f, ensure_ascii=False, indent=2)
            
            successful_count += 1

        except Exception as e:
            print(f"处理图片 {image_name} 时出错: {str(e)}")
            continue

    print(f"完成! 成功为 {successful_count}/{len(target_images)} 张图片创建标注文件")
    if successful_count < len(target_images):
        print(f"警告: 有 {len(target_images) - successful_count} 张图片处理失败,请检查日志")

def main():
    """
    主函数 - 当前配置版本
    使用前请根据实际情况修改以下路径:
    """
    
    # ====== 请在此处修改您的路径配置 ======
    source_json = "../1765555160.json"    # 源标注JSON文件路径
    image_dir = "../bbbb"                # 图片目录路径
    output_dir = "../bbbb"               # 输出目录路径(可与image_dir相同)
    # ======================================
    
    print("=" * 50)
    print("LabelMe标注批量复制工具")
    print("=" * 50)
    print(f"配置信息:")
    print(f"  源标注文件: {source_json}")
    print(f"  图片目录: {image_dir}")
    print(f"  输出目录: {output_dir}")
    print("-" * 50)
    
    # 检查文件和目录是否存在
    if not os.path.exists(source_json):
        print(f"错误: 源标注文件不存在 - {source_json}")
        return
    
    if not os.path.exists(image_dir):
        print(f"错误: 图片目录不存在 - {image_dir}")
        return
    
    copy_labelme_annotations(
        source_json_path=source_json,
        image_dir=image_dir,
        output_dir=output_dir
    )

if __name__ == "__main__":
    main()

10. 总结

这个脚本能够大幅提升标注效率,特别适用于:

  • 工业检测中的相似产品图片
  • 监控视频中的连续帧
  • 产品展示的多角度照片
  • 任何具有重复模式的图像数据集

使用流程总结:

  1. 标注第一张图片(使用LabelMe)
  2. 配置脚本参数(修改路径)
  3. 运行脚本批量生成标注
  4. 使用LabelMe验证和微调标注
  5. 导出为所需格式(COCO、YOLO等)

通过这个工具,您可以将原本需要几小时的标注工作缩短到几分钟,大大提高数据准备效率!

相关推荐
涔溪3 小时前
CSS 网格布局(Grid Layout)核心概念、基础语法、常用属性、实战示例和进阶技巧全面讲解
前端·css
2401_878454533 小时前
浏览器工作原理
前端·javascript
sunxunyong3 小时前
doris运维命令
java·运维·数据库
Guheyunyi3 小时前
智慧消防管理系统如何重塑安全未来
大数据·运维·服务器·人工智能·安全
西陵3 小时前
为什么说 AI 赋能前端开发,已经不是选择题,而是必然趋势?
前端·架构·ai编程
by__csdn5 小时前
Vue3 setup()函数终极攻略:从入门到精通
开发语言·前端·javascript·vue.js·性能优化·typescript·ecmascript
天天扭码5 小时前
前端如何实现RAG?一文带你速通,使用RAG实现长期记忆
前端·node.js·ai编程
Luna-player5 小时前
在前端中,<a> 标签的 href=“javascript:;“ 这个是什么意思
开发语言·前端·javascript
lionliu05195 小时前
js的扩展运算符的理解
前端·javascript·vue.js