YOLO Vision 2026:

كيفية تحويل تعليقات 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/",  # 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=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 التوضيحية إلى تنسيق .txt الخاص بـYOLO:

تحويل 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 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

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

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

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

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

model = YOLO("yolo26n.pt")  # load a pretrained model
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) ذات بنية تعليقات توضيحية مختلفة.

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

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

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

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

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

إذا سجّل 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. أعد ربط المعرّفات بقيم متجاورة عند الحاجة.

للاطلاع على تفاصيل API الكاملة وأوصاف المعلمات، راجع مرجع API الخاص بـconvert_coco.

الأسئلة الشائعة#

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

التعليقات