将coco128-seg分割数据集yolo格式转换为coco2017.json格式,方便运行cocoapi接口测试:
保存为一个json文件。
labels.txt 是有80个类别txt信息
注意coco128-seg 中有两张图片和Label错误要挑选出来:
000000000250.jpg
000000000508.jpg
000000000656.txt
000000000659.txt
#!/usr/bin/env python3 """ Convert YOLO format segmentation data to COCO JSON format. Reads images and labels from coco128-seg folder and converts them to a single JSON file. """ import json import os from pathlib import Path from PIL import Image import numpy as np def load_labels_txt(labels_file): """Load category names from labels.txt file.""" with open(labels_file, 'r') as f: categories = [line.strip() for line in f.readlines()] return categories def yolo_to_coco_polygon(yolo_coords, img_width, img_height): """ Convert YOLO normalized polygon coordinates to COCO absolute coordinates. YOLO format: normalized coordinates (0-1) as [x1, y1, x2, y2, ...] COCO format: absolute pixel coordinates as [[x1, y1, x2, y2, ...]] """ coords = np.array(yolo_coords, dtype=np.float32) # Reshape to (N, 2) where N is number of points coords = coords.reshape(-1, 2) # Convert normalized to absolute coords[:, 0] *= img_width coords[:, 1] *= img_height # Flatten back to [x1, y1, x2, y2, ...] polygon = coords.flatten().tolist() return [polygon] def calculate_bbox_from_polygon(polygon): """ Calculate bounding box from polygon coordinates. polygon: [x1, y1, x2, y2, ...] (flattened) Returns: [x, y, width, height] (COCO bbox format) """ coords = np.array(polygon).reshape(-1, 2) x_min = float(np.min(coords[:, 0])) y_min = float(np.min(coords[:, 1])) x_max = float(np.max(coords[:, 0])) y_max = float(np.max(coords[:, 1])) return [x_min, y_min, x_max - x_min, y_max - y_min] def calculate_area_from_polygon(polygon): """ Calculate area from polygon using shoelace formula. polygon: [x1, y1, x2, y2, ...] (flattened) """ coords = np.array(polygon).reshape(-1, 2) x = coords[:, 0] y = coords[:, 1] area = 0.5 * np.abs(np.dot(x, np.roll(y, 1)) - np.dot(y, np.roll(x, 1))) return float(area) def convert_yolo_to_coco(yolo_dir, labels_file, output_json): """ Convert YOLO format segmentation data to COCO JSON format. Args: yolo_dir: Path to coco128-seg directory labels_file: Path to labels.txt file output_json: Path to output JSON file """ # Load category names category_names = load_labels_txt(labels_file) # Create categories list for COCO format # COCO uses 1-based category IDs, YOLO uses 0-based categories = [] for idx, name in enumerate(category_names): category_id = idx + 1 # Convert to 1-based for COCO # Determine supercategory (simplified mapping) if idx == 0: supercategory = "person" elif 1 <= idx <= 8: supercategory = "vehicle" elif 9 <= idx <= 13: supercategory = "outdoor" elif 14 <= idx <= 24: supercategory = "animal" elif 25 <= idx <= 32: supercategory = "accessory" elif 33 <= idx <= 42: supercategory = "sports" elif 43 <= idx <= 50: supercategory = "kitchen" elif 51 <= idx <= 60: supercategory = "food" elif 61 <= idx <= 70: supercategory = "furniture" elif 71 <= idx <= 77: supercategory = "electronic" elif 78 <= idx <= 82: supercategory = "appliance" else: supercategory = "indoor" categories.append({ "id": category_id, "name": name, "supercategory": supercategory }) # Paths images_dir = Path(yolo_dir) / "images" / "train2017" labels_dir = Path(yolo_dir) / "labels" / "train2017" # Collect all image files image_files = sorted(images_dir.glob("*.jpg")) # Check for missing labels images_without_labels = [] labels_without_images = [] valid_pairs = [] for img_path in image_files: label_path = labels_dir / (img_path.stem + ".txt") if label_path.exists(): valid_pairs.append((img_path, label_path)) else: images_without_labels.append(img_path.name) # Check for labels without images label_files = sorted(labels_dir.glob("*.txt")) for label_path in label_files: img_path = images_dir / (label_path.stem + ".jpg") if not img_path.exists(): labels_without_images.append(label_path.name) print(f"统计信息:") print(f" 总图片数: {len(image_files)}") print(f" 总标签数: {len(label_files)}") print(f" 有效配对: {len(valid_pairs)}") if images_without_labels: print(f" 没有标签的图片 ({len(images_without_labels)} 张): {', '.join(images_without_labels)}") if labels_without_images: print(f" 没有图片的标签 ({len(labels_without_images)} 个): {', '.join(labels_without_images)}") print() # Initialize COCO data structure coco_data = { "info": { "description": "COCO 2017 Dataset (converted from YOLO)", "url": "", "version": "1.0", "year": 2017, "contributor": "", "date_created": "2017/09/01" }, "licenses": [], "images": [], "annotations": [], "categories": categories } # Counters image_id = 1 annotation_id = 1 # Process each valid image-label pair for img_path, label_path in valid_pairs: # Get image dimensions try: img = Image.open(img_path) width, height = img.size except Exception as e: print(f"Warning: Could not open image {img_path}: {e}") continue # Add image entry coco_data["images"].append({ "id": image_id, "file_name": img_path.name, "width": width, "height": height, "license": 0, "coco_url": "", "flickr_url": "", "date_captured": "" }) # Read and process labels (label_path is already verified to exist) with open(label_path, 'r') as f: lines = f.readlines() for line in lines: line = line.strip() if not line: continue parts = line.split() if len(parts) < 3: continue try: yolo_class_id = int(parts[0]) # Convert YOLO 0-based class_id to COCO 1-based category_id category_id = yolo_class_id + 1 # Remaining parts are normalized coordinates yolo_coords = [float(x) for x in parts[1:]] if len(yolo_coords) < 6: # Need at least 3 points (x, y pairs) continue # Convert YOLO polygon to COCO format segmentation = yolo_to_coco_polygon(yolo_coords, width, height) # Calculate bounding box bbox = calculate_bbox_from_polygon(segmentation[0]) # Calculate area area = calculate_area_from_polygon(segmentation[0]) # Add annotation coco_data["annotations"].append({ "id": annotation_id, "image_id": image_id, "category_id": category_id, "segmentation": segmentation, "area": area, "bbox": bbox, "iscrowd": 0 }) annotation_id += 1 except (ValueError, IndexError) as e: print(f"Warning: Error processing line in {label_path}: {line[:50]}... Error: {e}") continue image_id += 1 # Write output JSON with open(output_json, 'w') as f: json.dump(coco_data, f, indent=2) print(f"Conversion complete!") print(f"Total images: {len(coco_data['images'])}") print(f"Total annotations: {len(coco_data['annotations'])}") print(f"Total categories: {len(coco_data['categories'])}") print(f"Output saved to: {output_json}") if __name__ == "__main__": # Set paths yolo_dir = "coco128-seg" labels_file = "labels.txt" output_json = "coco128_seg.json" # Convert convert_yolo_to_coco(yolo_dir, labels_file, output_json)