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 方法一:直接运行(推荐新手使用)
-
创建目录结构
your_project/ ├── copy_annotations.py # 本脚本 ├── 1765555160.json # 您的源标注文件 └── bbbb/ # 存放所有图片的目录 ├── image1.jpg ├── image2.jpg ├── image3.jpg └── ... -
将脚本参数修改为您实际的路径
pythondef main(): source_json="../1765555160.json" # 修改为您的源JSON文件路径 copy_labelme_annotations( source_json_path=source_json, image_dir="../bbbb", # 修改为您的图片目录 output_dir="../bbbb" # 修改为输出目录 ) -
运行脚本
bashpython 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. 总结
这个脚本能够大幅提升标注效率,特别适用于:
- 工业检测中的相似产品图片
- 监控视频中的连续帧
- 产品展示的多角度照片
- 任何具有重复模式的图像数据集
使用流程总结:
- 标注第一张图片(使用LabelMe)
- 配置脚本参数(修改路径)
- 运行脚本批量生成标注
- 使用LabelMe验证和微调标注
- 导出为所需格式(COCO、YOLO等)
通过这个工具,您可以将原本需要几小时的标注工作缩短到几分钟,大大提高数据准备效率!