一、数据集重命名与标注对齐
问题背景
每个数据集的图片和标注均从0
开始命名(如0.jpg
、0.xml
),跨数据集会导致文件名冲突(如类别 A 的0.jpg
和类别 B 的0.jpg
同名)。需通过添加类别标识 + 全局序号解决冲突,并处理缺失标注的图片。
1. 重命名规则设计
- 图片命名:
[类别名]_[全局序号].[后缀]
(如apple_001.jpg
、banana_002.png
)。- 类别名:用数据集对应的类别名称(如
watermelon
、apple
等,需确保唯一)。 - 全局序号:每个类别内部从
1
开始递增(如类别 A 的图片为A_001.jpg
、A_002.jpg
…)。
- 类别名:用数据集对应的类别名称(如
- 标注命名:与图片名一致(如
apple_001.xml
、banana_002.json
)。
2. 缺失标注的处理策略
- 目标:避免训练时因缺失标注导致错误。
- 方案:
- 过滤缺失标注的图片:仅保留同时存在图片和对应标注的文件。
- 标记无标注图片(可选):若需利用无标注数据,可标记为
unlabeled
类别(仅适用于半监督学习)。
3. Python 代码实现(重命名 + 标注对齐)
以下代码支持:
- 遍历所有数据集文件夹(图片 / 标注各 14 个)。
- 按类别重命名图片和标注,避免冲突。
- 过滤缺失标注的图片。
import os
import shutil
from glob import glob
def rename_and_align_datasets(
root_dir, # 数据集根目录(含28个文件夹:14个img_dir,14个ann_dir)
class_names, # 类别名列表(如['watermelon', 'apple', ...],长度14)
img_folder_suffix='', # 图片文件夹后缀(如'watermelon_images')
ann_folder_suffix='-label', # 标注文件夹后缀(如'watermelon_labels')
start_idx=0 # 每个类别内部的起始序号(如1→001)
):
# 遍历每个类别(共14个)
for class_idx, class_name in enumerate(class_names):
# 定义图片和标注文件夹路径
img_dir = os.path.join(root_dir, f"{class_name}{img_folder_suffix}")
ann_dir = os.path.join(root_dir, f"{class_name}{ann_folder_suffix}")
# 检查文件夹是否存在
if not os.path.exists(img_dir) or not os.path.exists(ann_dir):
print(f"警告:类别 {class_name} 的图片/标注文件夹缺失,跳过!")
continue
# 收集图片路径(支持jpg/png等格式)
img_extensions = ('.jpg', '.jpeg', '.png', '.bmp')
img_paths = []
for ext in img_extensions:
img_paths.extend(glob(os.path.join(img_dir, f'*{ext}'), recursive=False))
# 按文件名排序(确保0.jpg→001,1.jpg→002...)
img_paths.sort(key=lambda x: int(os.path.splitext(os.path.basename(x))[0]))
# 遍历图片,重命名并对齐标注
current_idx = start_idx
for img_path in img_paths:
# 获取原始文件名(如0.jpg→0)
old_name = os.path.splitext(os.path.basename(img_path))[0]
# 检查是否存在对应标注(假设标注与图片同名,后缀为.xml/json等)
ann_path = None
for ann_ext in ('.xml', '.json', '.txt'): # 支持常见标注格式
candidate_ann = os.path.join(ann_dir, f"{old_name}{ann_ext}")
if os.path.exists(candidate_ann):
ann_path = candidate_ann
break
# 缺失标注:跳过并提示
if not ann_path:
print(f"警告:图片 {img_path} 无对应标注,已跳过!")
continue
# 生成新文件名(如watermelon_001.jpg)
new_img_name = f"{class_name}_{current_idx:03d}{os.path.splitext(img_path)[1]}"
new_img_path = os.path.join(img_dir, new_img_name)
# 生成新标注名(如watermelon_001.xml)
new_ann_name = f"{class_name}_{current_idx:03d}{os.path.splitext(ann_path)[1]}"
new_ann_path = os.path.join(ann_dir, new_ann_name)
# 重命名图片和标注(避免覆盖已存在的文件)
if not os.path.exists(new_img_path) and not os.path.exists(new_ann_path):
shutil.move(img_path, new_img_path)
shutil.move(ann_path, new_ann_path)
print(f"重命名:{img_path} → {new_img_path}")
print(f"重命名标注:{ann_path} → {new_ann_path}")
else:
print(f"警告:{new_img_path} 或 {new_ann_path} 已存在,跳过!")
current_idx += 1
# 示例调用(替换为你的实际路径和类别名)
class_names = ['watermelon',
'apple','banana','grape','orange','pear','pomegranate',
'nectarine',
'mango',
'lychee',
'longan',
'durian',
'cantaloupe',
'blueberry'] # 14个类别
rename_and_align_datasets(
root_dir=r'C:\Users\29420\Desktop\1', # 数据集根目录(含28个文件夹)
class_names=class_names,
img_folder_suffix='', # 图片文件夹后缀(如'watermelon_imgs')
ann_folder_suffix='-label', # 标注文件夹后缀(如'watermelon_anns')
start_idx=0
)