كيفية تحويل تعليقات COCO التوضيحية إلى تنسيق YOLO#
يتطلب تدريب نماذج Ultralytics YOLO توفير التعليقات التوضيحية بتنسيق YOLO، ولكن العديد من أدوات التعليق التوضيحي الشائعة تصدر البيانات بتنسيق COCO JSON بدلاً من ذلك. يوضح لك هذا الدليل كيفية تحويل تعليقات COCO التوضيحية إلى تنسيق YOLO وبدء تدريب نماذج اكتشاف الكائنات، وتجزئة المثيلات، وتقدير الوضعية.
للتدريب مباشرة على COCO JSON دون إنشاء ملفات .txt، راجع تدريب YOLO على COCO JSON بدون تحويل.
لماذا التحويل من COCO إلى YOLO؟#
يخزن تنسيق COCO JSON كافة التعليقات التوضيحية في ملف واحد، بينما يستخدم YOLO ملف نصي واحد لكل صورة بإحداثيات مسواة. يُعد التحويل ضررياً للأسباب التالية:
- تتطلب نماذج YOLO ملفات تسميات
.txtبحيث يحتوي كل ملف على صورة واحدة، وتتضمنclass x_center y_center width heightبإحداثيات مسواة. - يستخدم تنسيق COCO JSON إحداثيات البكسل بتنسيق
[x_min, y_min, width, height]مع ملف JSON واحد لكافة الصور. - تختلف معرفات الفئات — حيث يستخدم COCO قيم
category_idعشوائية، بينما يتطلب YOLO معرفات فئات تبدأ من الصفر.
| الميزة | COCO JSON | YOLO TXT |
|---|---|---|
| الهيكل | ملف JSON واحد لجميع الصور | ملف .txt واحد لكل صورة |
| تنسيق Bbox | [x_min, y_min, width, height] بالبكسل | class x_center y_center width height مسوى (0-1) |
| معرفات الفئات | category_id (يمكن أن يبدأ من أي رقم) | مفهرسة من الصفر (تبدأ من 0) |
| التجزئة (Segmentation) | مصفوفات المضلعات في حقل segmentation | إحداثيات المضلع بعد معرف الفئة |
| النقاط الرئيسية (Keypoints) | [x, y, visibility, ...] بالبكسل | [x, y, visibility, ...] مسوى |
بدء التشغيل السريع#
أسرع طريقة لتحويل تعليقات COCO التوضيحية وبدء التدريب:
from ultralytics.data.converter import convert_coco
convert_coco(
labels_dir="my_dataset/annotations/", # directory containing your JSON files
save_dir="my_dataset/converted/", # where to save converted labels
cls91to80=False, # set False for custom datasets (see warning below)
)بعد التحويل، قم بترتيب هيكل الدليل الخاص بك، وأنشئ ملف dataset.yaml، وابدأ التدريب. راجع الدليل الشامل خطوة بخطوة أدناه.
تم تصميم القيمة الافتراضية لـ cls91to80=True فقط لـ مجموعة بيانات COCO القياسية التي تحتوي على 80 فئة كائنات، والتي تربط 91 معرف فئة غير متجاور بـ 80 معرف فئة متجاور. لأي مجموعة بيانات مخصصة، يجب عليك تعيين cls91to80=False — وإلا سيتم تعيين معرفات الفئات الخاصة بك بصمت بشكل غير صحيح وسيتعلم نموذجك فئات خاطئة.
دليل التحويل خطوة بخطوة#
جهز مجموعة بيانات COCO الخاصة بك#
تحتوي مجموعة البيانات بتنسيق COCO النموذجية المصدرة من أدوات التعليق التوضيحي على الهيكل التالي:
my_dataset/
├── images/
│ ├── train/
│ │ ├── img_001.jpg
│ │ ├── img_002.jpg
│ │ └── ...
│ └── val/
│ ├── img_100.jpg
│ └── ...
└── annotations/
├── instances_train.json
└── instances_val.jsonيتبع كل ملف JSON مواصفات تنسيق بيانات COCO مع ثلاثة حقول مطلوبة — images، وannotations، وcategories:
{
"images": [{ "id": 1, "file_name": "img_001.jpg", "width": 640, "height": 480 }],
"annotations": [
{
"id": 1,
"image_id": 1,
"category_id": 1,
"bbox": [100, 50, 200, 150],
"area": 30000,
"iscrowd": 0
}
],
"categories": [
{ "id": 1, "name": "helmet" },
{ "id": 2, "name": "vest" }
]
}تحويل التعليقات التوضيحية#
استخدم الدالة convert_coco() لتحويل تعليقات COCO JSON التوضيحية إلى تنسيق YOLO .txt:
from ultralytics.data.converter import convert_coco
convert_coco(
labels_dir="my_dataset/annotations/",
save_dir="my_dataset/converted/",
cls91to80=False,
)يكتب convert_coco() ملف .txt واحد لكل صورة معلّقة داخل مجلد فرعي labels/ مُسمى باسم كل ملف JSON، مع إزالة بادئة instances_ (بحيث ينتج عن instances_train.json الملف labels/train/). يتم تخطي الصور التي ليس لها تعليقات توضيحية ولا تحصل على ملف تسميات، لذا قد لا يعكس شجرة labels/ كل صورة بدقة:
my_dataset/converted/
└── labels/
├── train/ # from instances_train.json
│ ├── img_001.txt
│ └── ...
└── val/ # from instances_val.json
└── ...لا يقوم convert_coco() أبداً بالكتابة فوق ملف save_dir موجود: إذا كان my_dataset/converted/ موجوداً بالفعل، فإن إعادة التشغيل تكتب في my_dataset/converted-2/ بدلاً من ذلك. احذف الناتج السابق (أو قم بتغيير save_dir) قبل إعادة التشغيل، وإلا ستستقر الخطوات التالية على قراءة تسميات قديمة.
تنظيم هيكل الدليل#
بعد التحويل، يجب وضع ملفات التسميات بجوار صورك. يتوقع YOLO وجود دليل labels/ يعكس دليل images/:
import shutil
from pathlib import Path
converted_dir = Path("my_dataset/converted/labels")
dataset_dir = Path("my_dataset")
# convert_coco names each subdirectory after its JSON file (minus the "instances_" prefix),
# so iterate the actual subdirectories instead of assuming "train"/"val".
for src in converted_dir.iterdir():
if not src.is_dir():
continue
dst = dataset_dir / "labels" / src.name
dst.mkdir(parents=True, exist_ok=True)
for f in src.glob("*.txt"):
shutil.move(str(f), str(dst / f.name))يجب أن تبدو بنية مجموعة البيانات النهائية كالتالي:
my_dataset/
├── images/
│ ├── train/
│ │ ├── img_001.jpg
│ │ └── ...
│ └── val/
│ └── ...
├── labels/
│ ├── train/
│ │ ├── img_001.txt
│ │ └── ...
│ └── val/
│ └── ...
└── dataset.yamlإنشاء dataset.yaml#
أنشئ ملف تكوين dataset.yaml يربط فئات COCO الخاصة بك بأسماء فئات YOLO. يخبر هذا الملف YOLO بمكان بياناتك والفئات المراد اكتشافها:
import json
from pathlib import Path
import yaml
# Read categories from your COCO JSON
with open("my_dataset/annotations/instances_train.json") as f:
coco = json.load(f)
# Build class names matching convert_coco output (category_id - 1)
categories = sorted(coco["categories"], key=lambda x: x["id"])
names = {cat["id"] - 1: cat["name"] for cat in categories}
# NOTE: convert_coco maps class IDs as category_id - 1, so category_id must
# start from 1. If your categories start from 0, add 1 to each ID first.
# Create dataset.yaml
dataset = {
"path": str(Path("my_dataset").resolve()),
"train": "images/train",
"val": "images/val",
"names": names,
}
with open("my_dataset/dataset.yaml", "w") as f:
yaml.dump(dataset, f, default_flow_style=False)ملف YAML الناتج:
path: /absolute/path/to/my_dataset
train: images/train
val: images/val
names:
0: helmet
1: vestلمزيد من التفاصيل حول تنسيق YAML لمجموعة البيانات، راجع دليل تكوين مجموعة البيانات.
تدريب نموذج YOLO الخاص بك#
مع جاهزية مجموعة بياناتك المحولة، قم بتدريب نموذج YOLO:
from ultralytics import YOLO
model = YOLO("yolo26n.pt") # load a pretrained model
results = model.train(data="my_dataset/dataset.yaml", epochs=100, imgsz=640)للحصول على نصائح التدريب وأفضل الممارسات، راجع دليل تدريب النماذج.
التحقق من التحويل الخاص بك#
قبل التدريب، تحقق عشوائياً من بعض ملفات التسمية للتأكد من صحة معرفات الفئات والإحداثيات:
from pathlib import Path
label_file = Path("my_dataset/labels/train/img_001.txt")
for line in label_file.read_text().strip().splitlines():
parts = line.split()
cls_id = int(parts[0])
coords = [float(v) for v in parts[1:5]]
assert cls_id >= 0, f"Negative class ID {cls_id} — category_id in your JSON may start from 0"
assert all(0 <= v <= 1 for v in coords), f"Coordinates out of [0, 1] range: {coords}"إذا رأيت معرفات فئات سالبة، فمن المحتمل أن يكون ملف COCO JSON الخاص بك يرتكز على category_id يبدأ من 0. أضف 1 إلى جميع قيم category_id في ملف JSON الخاص بك قبل تشغيل convert_coco()، نظراً لأنه يربط معرفات الفئات كـ category_id - 1.
استكشاف الأخطاء وإصلاحها الشائعة#
معرفات فئات خاطئة بعد التحويل#
إذا كان نموذجك يتدرب ولكنه يكتشف فئات كائنات خاطئة، فمن المحتمل أنك تستخدم cls91to80=True (الافتراضي) على مجموعة بيانات مخصصة. يؤدي هذا إلى تعيين قيم category_id الخاصة بك عبر جدول البحث COCO 91 إلى 80، وهو صحيح فقط لـ مجموعة بيانات COCO القياسية.
الحل: استخدم دائماً cls91to80=False لمجموعات البيانات المخصصة.
لم يتم العثور على تسميات أثناء التدريب#
إذا أظهر التدريب WARNING: No labels found أو 0 images, N backgrounds، فإن ملفات التسميات الخاصة بك ليست في الدليل المتوقع. يقوم convert_coco() بحفظ التسميات في دليل إخراج منفصل (على سبيل المثال، save_dir/labels/train/)، لكن YOLO يتوقع وجود labels/ موازياً لـ images/ داخل دليل مجموعة البيانات الخاص بك.
الحل: انقُل ملفات التسميات لتتطابق مع بنية الدليل المتوقعة. تأكد من أن labels/train/ يمثل عنصراً شقيقاً لـ images/train/.
خطأ KeyError أثناء التحويل#
إذا واجهت KeyError: 'bbox' أو أخطاء مشابهة عند تشغيل convert_coco()، فمن المحتمل أن يحتوي labels_dir على ملفات JSON لا تمثل مثيلات (مثل captions_train2017.json) ذات بنية تعليقات توضيحية مختلفة.
الحل: ضع فقط ملفات JSON لتعليقات المثيلات التوضيحية (مثل instances_train2017.json) في labels_dir.
ملفات تسمية فارغة بعد التحويل#
إذا اكتمل التحويل ولكن ملفات .txt كانت فارغة أو مفقودة، فقد تحتوي جميع التعليقات التوضيحية على iscrowd: 1 (وهو أمر شائع مع الأقنعة المُولدة بواسطة SAM)، أو أن مربعات الإحاطة لها عرض أو ارتفاع يساوي صفراً.
الحل: افحص تعليقات JSON التوضيحية بحثاً عن قيم iscrowd. إذا كنت تستخدم أقنعة SAM، فقم بمعالجة ملف JSON مسبقاً لتعيين iscrowd: 0.
مضلعات على شكل صندوق من تعليقات الأقنعة#
إذا سجّل use_segments=True الرسالة annotations without a usable polygon، فهذا يعني أن بعض التعليقات التوضيحية لا تحمل قيمة segmentation، أو أن القيمة ليست قائمة مكونة من ثلاثة أزواج إحداثيات على الأقل. الأسباب الشائعة هي الصادرات الخاصة بالكتشاف فقط، والتي تترك الحقل مفقوداً أو فارغاً، وترميز تشغيل الطول لـ COCO ({"counts": ..., "size": ...})، والذي تكتبه مصدّرات الأقنعة الثنائية مثل SAM؛ يتم التعامل مع قائمة الإحداثيات المسطحة التي لا تحتوي على قائمة مضلعات محيطية، والمخططات ذات النقطة الواحدة والنقطتين، وغيرها من القيم التالفة بنفس الطريقة. يحتفظ التعليق التوضيحي بأي مضلعات تتبقى، ويلجأ إلى صف تجزئة على شكل مربع الإحاطة الخاص به عندما لا تتوفر أي منها، بحيث تظل التسميات صالحة ولكن تلك الصفوف لا تحمل تفاصيل قناع.
الحل: أعد تصدير التعليقات التوضيحية باستخدام تجزئات المضلعات، أو قم بفك تشفير أقنعة RLE إلى مضلعات قبل تشغيل convert_coco()، أو صحح أي قيم segmentation تالفة.
فجوات في معرفات الفئات في التسميات المحولة#
إذا كانت معرفات الفئات في ملفات التسميات غير متجاورة (على سبيل المثال، 0، 4، 9 بدلاً من 0، 1، 2)، فإن أداة التعليق التوضيحي الخاص بك تستخدم قيم category_id غير متجاورة.
الحل: تحقق من أن معرفات الفئات في ملفات .txt تتطابق مع قاموس names في dataset.yaml. قم بإعادة تعيين المعرفات إلى قيم متجاورة إذا لزم الأمر.
للحصول على تفاصيل واجهة برمجة التطبيقات الكاملة ووصف المعلمات، راجع [مرجع واجهة برمجة التطبيقات convert_coco.
الأسئلة الشائعة#
استخدم دالة
convert_coco()من Ultralytics لتحويل تعليقات COCO JSON التوضيحية إلى تنسيق YOLO.txt. قم بتعيينcls91to80=Falseلمجموعات البيانات المخصصة:from ultralytics.data.converter import convert_coco convert_coco(labels_dir="path/to/annotations/", save_dir="output/", cls91to80=False)بعد التحويل، أعد تنظيم ملفات التسميات الخاصة بك بحيث يعكس
labels/دليلimages/، ثم أنشئ ملفdataset.yaml. راجع الدليل خطوة بخطوة لمعرفة سير العمل الكامل.يحدث هذا لأن
convert_coco()يحفظ التسميات في مجلد فرعي داخلsave_dir/labels/(على سبيل المثال،save_dir/labels/train/) بدلاً من حفظها مباشرة فيlabels/train/الخاص بمجموعة البيانات بجوارimages/train/. يتوقع YOLO أن توجد التسميات بشكل موازٍ للصور — على سبيل المثال، يحتاجimages/train/img.jpgإلىlabels/train/img.txt. انقُل التسميات المحولة لتتوافق مع هذا الهيكل. راجع إصلاح بنية الدليل.تتحكم معلمة
cls91to80في كيفية تعيين قيم COCOcategory_idإلى معرفات فئات YOLO. عندما تكونTrue(الافتراضية)، فإنها تطبق جدول البحثcoco91_to_coco80_class()المصمم لـ مجموعة بيانات COCO القياسية، والتي تحتوي على 80 فئة بمعرفات غير متجاورة (1-90). بالنسبة لـ مجموعات البيانات المخصصة، قم دائماً بتعيينcls91to80=False— حيث يؤدي هذا ببساطة إلى طرح 1 من كلcategory_idلإنشاء معرفات فئات تبدأ من الصفر.لا يمكن ذلك باستخدام خط أنابيب تدريب YOLO الحالي — يجب أن تكون التعليقات التوضيحية بتنسيق YOLO
.txtمع ملف واحد لكل صورة. استخدمconvert_coco()لتحويل ملف COCO JSON أولاً، ثم اتبع هذا الدليل للتنظيم والتدريب. لمزيد من المعلومات حول التنسيقات المدعومة، راجع تنسيقات مجموعات البيانات.نعم، استخدم
use_segments=Trueعند استدعاءconvert_coco()تضمين أقنعة تجزئة المضلعات في تسميات YOLO المحولة. ينتج عن هذا ملفات تسميات متوافقة مع نماذج تجزئة YOLO:from ultralytics.data.converter import convert_coco convert_coco(labels_dir="annotations/", save_dir="output/", use_segments=True, cls91to80=False)استخدم
use_keypoints=Trueلتحويل تعليقات نقاط التباين في COCO لتدريب تقدير الوضعية:from ultralytics.data.converter import convert_coco convert_coco(labels_dir="annotations/", save_dir="output/", use_keypoints=True, cls91to80=False)لاحظ أنه إذا تم تعيين كل من
use_segmentsوuse_keypointsإلىTrue، فسيتم كتابة نقاط التباين فقط في ملفات التسميات — بينما يتم تجاهل التجزئات بصمت.