Ultralytics YOLO27:
Get Started

كيفية تحويل تعليقات 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 JSONYOLO TXT
البنيةملف JSON واحد لجميع الصورملف .txt واحد لكل صورة
تنسيق BBox[x_min, y_min, width, height] بالبكسلتطبيع class x_center y_center width height (0-1)
معرّفات الفئاتcategory_id (يمكن أن يبدأ من أي رقم)يبدأ الفهرس من الصفر (يبدأ من 0)
التجزئةمصفوفات المضلعات في الحقل segmentationإحداثيات المضلعات بعد معرّف الفئة
النقاط المفتاحية[x, y, visibility, ...] بالبكسلتطبيع [x, y, visibility, ...]

البدء السريع#

أسرع طريقة لتحويل تعليقات COCO التوضيحية وبدء التدريب:

from ultralytics.data.converter import convert_coco

convert_coco(
    labels_dir="my_dataset/annotations/",  # ⁨الدليل الذي يحتوي على ملفات JSON الخاصة بك⁩
    save_dir="my_dataset/converted/",  # ⁨مكان حفظ التسميات المحوّلة⁩
    cls91to80=False,  # ⁨اضبطها على False لمجموعات البيانات المخصصة (راجع التحذير أدناه)⁩
)

بعد التحويل، نظّم بنية الدليل، وأنشئ ملف dataset.yaml، ثم ابدأ التدريب. راجع الدليل التفصيلي خطوة بخطوة أدناه.

مجموعات البيانات المخصصة: استخدم دائمًا `cls91to80=False`

الإعداد الافتراضي cls91to80=True مصمم فقط لمجموعة بيانات COCO القياسية ذات 80 فئة للكائنات، إذ يعيّن 91 معرّف فئة غير متتابع إلى 80 معرّف فئة متتابعًا. لأي مجموعة بيانات مخصصة، يجب ضبط cls91to80=False؛ وإلا فستُعيّن معرّفات الفئات لديك على نحو خاطئ دون تنبيه، وسيتعلم نموذجك فئات غير صحيحة.

دليل التحويل خطوة بخطوة#

1. جهّز مجموعة بيانات 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" }
    ]
}

2. حوّل التعليقات التوضيحية#

استخدم الدالة convert_coco() لتحويل تعليقات COCO التوضيحية بصيغة JSON إلى تنسيق YOLO .txt:

تحويل COCO إلى تنسيق YOLO
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/
├── images/      # created but left empty
└── 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) قبل إعادة التشغيل، وإلا فستقرأ الخطوات التالية تسميات قديمة.

3. نظّم بنية الدليل#

بعد التحويل، يجب وضع ملفات التسميات بجوار الصور. يتوقع YOLO دليل labels/ يعكس بنية دليل images/:

import shutil
from pathlib import Path

converted_dir = Path("my_dataset/converted/labels")
dataset_dir = Path("my_dataset")

# ⁨تسمّي convert_coco كل دليل فرعي باسم ملف JSON الخاص به (بعد حذف البادئة "instances_"),⁩
# ⁨لذا كرّر على الأدلة الفرعية الفعلية بدلًا من افتراض وجود "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

4. أنشئ dataset.yaml#

أنشئ ملف إعدادات dataset.yaml يعيّن فئات COCO إلى أسماء فئات YOLO. يحدد هذا الملف لـ YOLO موقع بياناتك والفئات المطلوب اكتشافها:

import json
from pathlib import Path

import yaml

# ⁨اقرأ الفئات من ملف JSON الخاص بـ COCO⁩
with open("my_dataset/annotations/instances_train.json") as f:
    coco = json.load(f)

# ⁨أنشئ أسماء فئات تطابق مخرجات convert_coco (category_id - 1)⁩
categories = sorted(coco["categories"], key=lambda x: x["id"])
names = {cat["id"] - 1: cat["name"] for cat in categories}
# ⁨ملاحظة: يعيّن convert_coco معرّفات الفئات كالتالي: category_id - 1، لذا يجب أن تكون قيمة category_id⁩
# ⁨بدءًا من 1. إذا كانت فئاتك تبدأ من 0، فأضف 1 إلى كل معرّف أولًا.⁩

# ⁨أنشئ 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 لمجموعة البيانات، راجع دليل إعداد مجموعة البيانات.

5. درّب نموذج YOLO#

بعد تجهيز مجموعة البيانات المحوّلة، درّب نموذج YOLO:

التدريب على بيانات COCO المحوّلة
from ultralytics import YOLO

model = YOLO("yolo26n.pt")  # ⁨حمّل نموذجًا مدرّبًا مسبقًا⁩
results = model.train(data="my_dataset/dataset.yaml", epochs=100, imgsz=640)

للحصول على نصائح التدريب وأفضل الممارسات، راجع دليل تدريب النماذج.

6. تحقّق من التحويل#

قبل التدريب، افحص عيّنة من ملفات التسميات للتأكد من صحة معرّفات الفئات والإحداثيات:

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 القياسية. أما category_id الذي لا يقابله شيء ضمن COCO-80، فلا يُعيّن إلى أي شيء، ويؤدي إلى ظهور TypeError: must be real number, not NoneType أثناء التحويل بدلًا من إنشاء تسميات خاطئة.

الحل: استخدم دائمًا cls91to80=False لمجموعات البيانات المخصصة.

لم يُعثر على تسميات أثناء التدريب#

إذا أفاد فحص التسميات بوجود 0 images, N backgrounds ثم توقف التدريب مع ValueError: train: No labels found in .../labels/train.cache، فهذا يعني أن ملفات التسميات ليست في الدليل المتوقع. يحفظ convert_coco() التسميات في دليل إخراج منفصل (مثل save_dir/labels/train/)، لكن YOLO يتوقع وجود labels/ موازيًا لـ images/ داخل دليل مجموعة البيانات.

الحل: انقل ملفات التسميات لتتوافق مع بنية الدليل المتوقعة. تأكد من أن labels/train/ يقع بجوار images/train/.

خطأ KeyError أثناء التحويل#

إذا ظهر لك KeyError: 'bbox' أو أخطاء مشابهة عند تشغيل convert_coco()، فمن المرجح أن labels_dir يحتوي على ملفات JSON ليست خاصة بالنسخ (مثل captions_train2017.json) ولها بنية تعليقات توضيحية مختلفة.

الحل: لا تضع في labels_dir إلا ملفات JSON الخاصة بتعليقات النسخ التوضيحية (مثل instances_train2017.json).

ملفات تسميات فارغة بعد التحويل#

إذا اكتمل التحويل لكن ملفات .txt فارغة أو مفقودة، فقد تحتوي جميع التعليقات التوضيحية على iscrowd: 1 (وهو أمر شائع مع الأقنعة التي ينشئها SAM)، أو قد يكون عرض مربعات الإحاطة أو ارتفاعها صفرًا. يؤدي التشغيل باستخدام use_keypoints=True على تصدير مخصص للاكتشاف فقط إلى النتيجة نفسها، لأن التعليقات التوضيحية التي لا تحتوي على الحقل keypoints تُتخطى بالكامل.

الحل: افحص قيم iscrowd في التعليقات التوضيحية بصيغة JSON. إذا كنت تستخدم أقنعة SAM، فعالج ملف JSON مسبقًا لتعيين iscrowd: 0. إذا مرّرت use_keypoints=True، فتأكد من أن تعليقاتك التوضيحية تتضمن فعلًا keypoints.

مضلعات على شكل مربعات ناتجة عن تعليقات الأقنعة التوضيحية#

إذا سجّل use_segments=True الرسالة annotations without a usable polygon، فهذا يعني أن بعض التعليقات التوضيحية لا تحتوي على قيمة segmentation، أو أن قيمتها ليست قائمة تضم ثلاثة أزواج إحداثيات على الأقل. تشمل الأسباب الشائعة عمليات التصدير المخصصة للاكتشاف فقط، التي تترك الحقل مفقودًا أو فارغًا، وترميز الأطوال المتتالية (RLE) في COCO ({"counts": ..., "size": ...})، الذي تكتبه أدوات تصدير الأقنعة الثنائية مثل SAM؛ وتُعامل بالطريقة نفسها قائمة الإحداثيات المسطحة التي لا تحتوي على قائمة مضلعات، والحدود المؤلفة من نقطة أو نقطتين، والقيم الأخرى ذات التنسيق غير الصحيح. يحتفظ التعليق التوضيحي بالمضلعات الصالحة المتبقية، ويعود إلى صف مقطع على هيئة مربع الإحاطة عند عدم وجود أي مضلع صالح، لذا تظل التسميات صالحة، لكن تلك الصفوف لا تتضمن تفاصيل القناع.

الحل: أعد تصدير التعليقات التوضيحية مع مقاطع مضلعية، أو فك ترميز أقنعة RLE إلى مضلعات قبل تشغيل convert_coco()، أو صحّح أي قيم segmentation ذات تنسيق غير صحيح.

فجوات في معرّفات الفئات ضمن التسميات المحوّلة#

إذا كانت معرّفات الفئات في ملفات التسميات غير متتابعة (مثلًا: 0 و4 و9 بدلًا من 0 و1 و2)، فإن أداة التعليقات التوضيحية تستخدم قيم category_id غير المتتابعة.

الحل: تحقّق من أن معرّفات الفئات في ملفات .txt تطابق القاموس names في dataset.yaml. أعد تعيين المعرّفات إلى قيم متتابعة عند الحاجة.

للاطلاع على تفاصيل API الكاملة وأوصاف المعلمات، راجع مرجع API الخاص بـ 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 في كيفية تعيين قيم COCO category_id إلى معرّفات فئات YOLO. عند ضبط True (الإعداد الافتراضي)، يُطبّق جدول البحث coco91_to_coco80_class() المصمم لمجموعة بيانات COCO القياسية، التي تضم 80 فئة ذات معرّفات غير متتابعة (1-90). بالنسبة إلى مجموعات البيانات المخصصة، اضبط دائمًا cls91to80=False — إذ يطرح ذلك 1 ببساطة من كل قيمة category_id لإنشاء معرّفات فئات تبدأ من الصفر.

  • ليس من دون كتابة تعليمات برمجية مخصصة. يتوقع مسار التدريب الافتراضي تسميات YOLO .txt، بملف واحد لكل صورة؛ لذا شغّل convert_coco() واتبع هذا الدليل التفصيلي خطوة بخطوة، أو أنشئ فئة فرعية من مجموعة البيانات لتحليل COCO JSON أثناء التشغيل — راجع تدريب YOLO على 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، فلن تُكتب في ملفات التسميات إلا النقاط المفتاحية — ويُتجاهل المقاطع بصمت.

التعليقات