当我们已经有了YOLO格式的训练集和验证集的txt文件时,这两个里面均存储了图片地址,图片地址也对应于标签地址:
图片地址:
bash
/data/YOLO/images/1.jpg
/data/YOLO/images/2.jpg
标签地址:
bash
/data/YOLO/labels/1.txt
/data/YOLO/labels/2.txt
path/to/coco/
annotations/ # annotation json files
train/ # train images
val/ # val images
python
import os
import json
import shutil
from PIL import Image
from tqdm import tqdm
def create_coco_structure(base_dir):
"""
创建 COCO 数据集所需的基本目录结构。
"""
train_dir = os.path.join(base_dir, 'train')
val_dir = os.path.join(base_dir, 'val')
annotations_dir = os.path.join(base_dir, 'annotations')
os.makedirs(train_dir, exist_ok=True)
os.makedirs(val_dir, exist_ok=True)
os.makedirs(annotations_dir, exist_ok=True)
print(f"成功创建目录结构 at '{base_dir}'")
return train_dir, val_dir, annotations_dir
def yolo_to_coco_converter(file_list_path, output_image_dir):
"""
将 YOLO 格式的数据集转换为 COCO 格式。
Args:
file_list_path (str): 包含图片绝对路径的 .txt 文件 (e.g., train.txt)。
output_image_dir (str): 转换后图片存放的目录。
Returns:
tuple: 包含 COCO 格式的 images 和 annotations 列表。
"""
images_info = []
annotations_info = []
image_id_counter = 0
annotation_id_counter = 0
with open(file_list_path, 'r') as f:
image_paths = [line.strip() for line in f.readlines() if line.strip()]
print(f"开始处理 {os.path.basename(file_list_path)} 中的 {len(image_paths)} 张图片...")
for img_path in tqdm(image_paths):
if not os.path.exists(img_path):
print(f"警告: 图片路径不存在,已跳过: {img_path}")
continue
# 复制图片到目标文件夹
img_filename = os.path.basename(img_path)
dest_img_path = os.path.join(output_image_dir, img_filename)
shutil.copy(img_path, dest_img_path)
# 获取图片尺寸
try:
with Image.open(img_path) as img:
width, height = img.size
except IOError:
print(f"警告: 无法打开或读取图片,已跳过: {img_path}")
continue
# 添加图片信息到 COCO images 列表
image_info = {
"id": image_id_counter,
"file_name": img_filename,
"width": width,
"height": height
}
images_info.append(image_info)
# 4. 处理对应的标签文件
label_path = img_path.replace('/images/', '/labels/').replace('.jpg', '.txt').replace('.png', '.txt')
if os.path.exists(label_path):
with open(label_path, 'r') as lf:
for line in lf.readlines():
parts = line.strip().split()
if len(parts) != 5:
continue
class_id, x_center, y_center, bbox_width, bbox_height = map(float, parts)
# YOLO 归一化坐标 -> COCO 绝对坐标 [x_min, y_min, width, height]
abs_bbox_width = bbox_width * width
abs_bbox_height = bbox_height * height
x_min = (x_center * width) - (abs_bbox_width / 2)
y_min = (y_center * height) - (abs_bbox_height / 2)
annotation = {
"id": annotation_id_counter,
"image_id": image_id_counter,
"category_id": int(class_id),
"bbox": [x_min, y_min, abs_bbox_width, abs_bbox_height],
"area": abs_bbox_width * abs_bbox_height,
"iscrowd": 0
}
annotations_info.append(annotation)
annotation_id_counter += 1
image_id_counter += 1
return images_info, annotations_info
def main():
# --------------------------------------------------------------------------------------------------------------- #
# 重要: 请修改 CATEGORIES 列表以匹配数据集类别。
# 顺序必须与 YOLO .txt 文件中的类别 ID 相同。
# 例如, 如果 'person' 是类别 0, 'car' 是类别 1, 那么:
# CATEGORIES = ["person", "car"]
# --------------------------------------------------------------------------------------------------------------- #
CATEGORIES = ["car", "bus", "person"] #根据自己的类别添加
TRAIN_TXT_PATH = '/data/YOLO/train.txt'
VAL_TXT_PATH = '/data/YOLO/val.txt'
OUTPUT_BASE_DIR = '/data/coco'
train_image_dir, val_image_dir, annotations_dir = create_coco_structure(OUTPUT_BASE_DIR)
coco_categories = [{"id": i, "name": name, "supercategory": "object"} for i, name in enumerate(CATEGORIES)]
train_images, train_annotations = yolo_to_coco_converter(TRAIN_TXT_PATH, train_image_dir)
train_coco_format = {
"info": {"description": "Train dataset in COCO format"},
"licenses": [],
"images": train_images,
"annotations": train_annotations,
"categories": coco_categories
}
train_json_path = os.path.join(annotations_dir, 'train.json')
with open(train_json_path, 'w') as f:
json.dump(train_coco_format, f, indent=4)
print(f"成功生成训练集标注文件: {train_json_path}")
# --- 处理验证集 ---
val_images, val_annotations = yolo_to_coco_converter(VAL_TXT_PATH, val_image_dir)
val_coco_format = {
"info": {"description": "Validation dataset in COCO format"},
"licenses": [],
"images": val_images,
"annotations": val_annotations,
"categories": coco_categories
}
val_json_path = os.path.join(annotations_dir, 'val.json')
with open(val_json_path, 'w') as f:
json.dump(val_coco_format, f, indent=4)
print(f"成功生成验证集标注文件: {val_json_path}")
print("\n转换完成!")
if __name__ == '__main__':
main()