Ultralytics YOLO27: انضم إلى قائمة الانتظار.
الدرسمتوسط

وسم نماذج الوضعية وتدريبها

اكتب تسميات النقاط المفتاحية مع قيم الرؤية، واضبط kpt_shape وflip_idx بشكل صحيح، ودرّب على COCO8-pose، وحوّل النقاط المفتاحية إلى زوايا مفاصل مشروطة بالثقة.

تحوّل تقديرات الوضعية كل شخص إلى 17 نقطة مرقّمة، ومنها تُستخرج القيم التي تسوّقها المنتجات: زوايا المرفقين لعلم بيئة العمل، وزوايا الركبتين لإعادة التأهيل، وارتفاع الورك لاكتشاف السقوط. يحدد مفتاحان في مجموعة البيانات ما إذا كان من الممكن الوثوق بهذه النقاط، والخطأ في أي منهما لا ينتج عنه خطأ ظاهر — بل نموذج يخلط بين اليمين واليسار، أو يتدرّب بصمت من دون أبسط أساليب زيادة البيانات.

النتيجة

درّب yolo26n-pose.pt على coco8-pose.yaml واحسب زاويتي المرفق الأيسر والأيمن لكل شخص باستخدام result.keypoints، مع تجاهل المفاصل التي لا يثق النموذج بها.

المسار السريع
إذا كنت تعرف الأساسيات بالفعل، فإليك النسخة المختصرة.
  1. صفّ التسمية: الفئة، ثم الصندوق (4 قيم)، ثم x y v لكل نقطة مفتاحية، وجميع القيم مطبّعة؛ تكون قيمة v إما 0 (غير موسومة) أو 1 (محجوبة) أو 2 (مرئية).

  2. اضبط kpt_shape: [K, 3] وflip_idx بحيث يبدّل كل شريك أيسر وأيمن.

  3. yolo pose train data=coco8-pose.yaml model=yolo26n-pose.pt epochs=1 imgsz=320.

  4. اقرأ result.keypoints.xy و.conf؛ وتجاوز أي حساب تقل فيه ثقة المفاصل عن الحد الأدنى.

عملي

صفّ تسمية النقاط المفتاحية#

تقدير الوضعية باستخدام Ultralytics YOLO لثلاثة عدّائين، لكل منهم صندوق للشخص وهيكل جسم مكوّن من 17 نقطة مفتاحية

يتكوّن صف تسمية الوضعية من صف كشف أُضيفت إليه نقاط مفتاحية. تُطبّع كل الإحداثيات إلى المجال 0–1، وتظهر النقاط المفتاحية بالترتيب الثابت نفسه في كل صف. وفيما يلي صف حقيقي من COCO8-pose، مقتطع بعد أربع نقاط مفتاحية:

0 0.671279 0.617945 0.645759 0.726859 0.519751 0.381250 2.000000 0.550936 0.348438 2.000000 0.488565 0.367188 2.000000 0.642412 0.354687 2.000000 ...
القيمالمعنى
0فهرس الفئة (شخص)
0.671279 0.617945 0.645759 0.726859مركز الصندوق x، ومركزه y، وعرضه، وارتفاعه
0.519751 0.381250 2النقطة المفتاحية 0 (الأنف): x وy وقيمة الرؤية
…16 نقطة مفتاحية أخرى بالنمط نفسه: 5 + 17 × 3 = 56 قيمة لكل صف

تتبع علامة الرؤية اصطلاح COCO: 2 مرئية، و1 موسومة لكنها محجوبة، و0 غير موسومة. يستبعد Ultralytics النقاط المفتاحية ذات القيمة v = 0 من الخسارة، لذا لا يؤدي غياب المعصم إلى تعليم النموذج التنبؤ بالمعاصم عند (0، 0).

محرر التعليقات التوضيحية في منصة Ultralytics على صورة من COCO8-pose، مع هياكل من 17 نقطة مفتاحية مرسومة على الأشخاص الذين يقطّعون كعكة

ضع تسميات للمفاصل المحجوبة التي يمكنك تحديد موضعها

استخدم 1 لمفصل محجوب يمكنك تحديد موضعه بثقة — مثل ورك خلف طاولة أو معصم خلف الظهر؛ إذ يظل مفيدًا للتدريب. خصص 0 للمفاصل التي يتعذر تحديد موضعها على أي شخص. إن وضع التسمية 0 لكل مفصل مخفي يهدر الحالات الصعبة التي يحتاج إليها النموذج تحديدًا.

يتناول دليل مجموعة بيانات الوضعية أيضًا الصيغة ذات القيمتين (x y فقط، kpt_shape: [K, 2]) لمجموعات البيانات التي لا تتضمن معلومات الرؤية.

kpt_shape وflip_idx#

يضيف YAML مجموعة البيانات مفتاحين إلى المفاتيح المعتادة path وtrain وval وnames:

kpt_shape: [17, 3] # 17 keypoints, each x, y, visibility
flip_idx: [0, 2, 1, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 16, 15]

ترتيب نقاط COCO المفتاحية الـ17 على شخص واقف، مرقّمة من 0 للأنف إلى 16 للكاحل الأيمن

يحدد flip_idx النقطة المفتاحية التي تتحول إليها كل نقطة عند تطبيق زيادة البيانات بالقلب الأفقي. عند عكس صورة شخص، ينتهي المعصم الأيسر (9) في موضع المعصم الأيمن (10)، لذا تحتوي الخانة 9 من flip_idx على 10، وتحتوي الخانة 10 على 9؛ أما الأنف (0) فيتحول إلى نفسه. تنقل كل زيادة هيكل النقاط مع البكسلات، والقلب وحده يحتاج أيضًا إلى خريطة الفهارس:

تعزيزات الوضعية لعدّاء واحد: الأصل، والانعكاس الأفقي، والدوران، وتغيير المقياس، وألوان HSV، والفسيفساء، مع هيكل النقاط الرئيسية بعد كل تحويل

ما الذي يحدث عندما تكون flip_idx خاطئة، وفقًا لما تم التحقق منه في المصدر المثبّت:

  • مفقودة: يصدر التدريب تحذيرًا ويضبط fliplr وflipud على 0، فتفقد أرخص تعزيز لديك.
  • طول غير صحيح: يتوقف التدريب مع ValueError يوضح عدم التطابق — وهذا هو الإخفاق الوحيد الذي يصدر تنبيهًا واضحًا.
  • الطول صحيح، لكن الأزواج خاطئة: لا يصدر أي تحذير. تعلّم نصف العينات المعكوسة النموذج أن اليسار هو اليمين، وتُظهر صور التحقق تبديلًا بين اليسار واليمين في الوضعيات المتناظرة.

التدريب على COCO8-pose#

فسيفساء التدريب على COCO8-pose: أشخاص على دراجة نارية، وتحت مظلة وردية، وفي حديقة تزلج، وعلى ظهور الخيل، مع صندوق شخص وهيكل نقاط رئيسية ملوّن لكل منهم

from ultralytics import YOLO

model = YOLO("yolo26n-pose.pt")
model.train(data="coco8-pose.yaml", epochs=1, imgsz=320, device="cpu")
metrics = model.val()
print(f"box  mAP50-95: {metrics.box.map:.3f}")
print(f"pose mAP50-95: {metrics.pose.map:.3f}")
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95)     Pose(P          R      mAP50  mAP50-95)
                   all          4         14          1      0.783      0.893      0.643      0.966      0.571      0.575      0.326
box  mAP50-95: 0.643
pose mAP50-95: 0.326

كما هو الحال مع التجزئة، ينقسم الجدول إلى قسمين. يقيّم الصندوق صناديق الأشخاص؛ وتقيّم الوضعية مواضع النقاط الرئيسية باستخدام تشابه النقاط الرئيسية للكائن (OKS) ضمن آلية mAP نفسها. تمثل Pose mAP50-95 معيار القبول لإصدار منتج الوضعيات — ويوضح الدرس التالي كيف تحدد OKS ما إذا كانت النقطة الرئيسية صحيحة.

من النقاط الرئيسية إلى زوايا المفاصل#

يحتوي result.keypoints على xy (N × K × 2، بالبكسل)، وxyn (مطبّعة)، وconf (N × K)، وفق ترتيب COCO الموضح أعلاه. زاوية المفصل هي الزاوية بين متجهي الطرفين اللذين يلتقيان عنده — ويمكن حسابها بالضرب النقطي:

import numpy as np

from ultralytics import YOLO

model = YOLO("yolo26n-pose.pt")
result = model("https://ultralytics.com/images/bus.jpg")[0]
kpts = result.keypoints.cpu().numpy()  # people x 17 x (x, y, conf)

SHOULDER, ELBOW, WRIST = 5, 7, 9  # left arm, COCO keypoint order
for person, (xy, conf) in enumerate(zip(kpts.xy, kpts.conf)):
    if conf[[SHOULDER, ELBOW, WRIST]].min() < 0.5:
        print(f"person {person}: left arm not visible enough")
        continue
    a, b, c = xy[SHOULDER], xy[ELBOW], xy[WRIST]
    cos = np.dot(a - b, c - b) / (np.linalg.norm(a - b) * np.linalg.norm(c - b))
    print(f"person {person}: left elbow angle {np.degrees(np.arccos(cos)):.0f} deg")
person 0: left elbow angle 71 deg
person 1: left elbow angle 96 deg
person 2: left elbow angle 59 deg
person 3: left arm not visible enough
person 4: left arm not visible enough

سطرًا بسطر: kpts.xy[p] هي النقاط الـ17 للشخص p بالبكسل؛ ويمثل a - b وc - b العضد والساعد على هيئة متجهين ينطلقان من المرفق؛ والضرب النقطي المطبّع لهما هو جيب تمام الزاوية بينهما. تكون قراءة الذراع المستقيمة قريبة من 180°، والمنثنية بالكامل قريبة من 30°. لدى الشخصين 3 و4 مفصل واحد على الأقل في الذراع اليسرى بثقة أقل من 0.5، لذا يمتنع البرنامج النصي عن قياسهما.

اشترط حدًا أدنى للثقة لكل مفصل

العَرَض: زوايا تبدو موثوقة لأشخاص أذرعهم خارج الإطار. السبب: يعيد النموذج إحداثية لكل نقطة مفتاحية، سواء أكانت محجوبة أم لا. الحل: تجاوز أي حساب تقل فيه ثقة المفاصل عن حد أدنى (0.5 هنا)، وسجّل عدد مرات التجاوز — فارتفاع معدل التجاوز إشارة مبكرة إلى تغير في الكاميرا أو الإضاءة.

جرّبه

درّب دورة واحدة على coco8-pose.yaml وسجّل mAP50-95 للصندوق والوضعية. ثم وسّع pose.py ليعرض زاوية المرفق الأيمن أيضًا (النقاط الرئيسية 6 و8 و10)، وحدد الأشخاص في صورة الحافلة الذين يمكن قياس كلا ذراعيهم.

متى يُعدّ مكتملًا
تكون قد أتممت الدرس عند تحقق جميع الشروط التالية.
  • اكتمل التدريب، وسجّلت mAP50-95 للصندوق والوضعية.

  • يطبع برنامجك النصي زاويتي المرفق لكل شخص، متجاوزًا أي ذراع تقل ثقته عن الحد الأدنى.

  • يمكنك شرح ما يحدث عندما تكون flip_idx مفقودة أو ذات طول غير صحيح أو ذات أزواج غير صحيحة.

عرض الحل
import numpy as np

from ultralytics import YOLO

ARMS = {"left": (5, 7, 9), "right": (6, 8, 10)}  # shoulder, elbow, wrist
kpts = YOLO("yolo26n-pose.pt")("https://ultralytics.com/images/bus.jpg")[0].keypoints.cpu().numpy()

for person, (xy, conf) in enumerate(zip(kpts.xy, kpts.conf)):
    for side, (s, e, w) in ARMS.items():
        if conf[[s, e, w]].min() < 0.5:
            continue
        a, b, c = xy[s], xy[e], xy[w]
        cos = np.dot(a - b, c - b) / (np.linalg.norm(a - b) * np.linalg.norm(c - b))
        print(f"person {person}: {side} elbow {np.degrees(np.arccos(cos)):.0f} deg")
person 0: left elbow 71 deg
person 0: right elbow 94 deg
person 1: left elbow 96 deg
person 2: left elbow 59 deg
person 2: right elbow 135 deg

يمكن قياس كلا ذراعي الشخصين 0 و2. أما الذراع اليمنى للشخص 1 والذراعان للشخصين 3 و4، فتقل ثقتها عن الحد الأدنى البالغ 0.5، لذا يتجاوزها البرنامج النصي بدلًا من التخمين.

يؤدي غياب flip_idx إلى تعطيل تعزيز الانعكاس مع إصدار تحذير؛ ويؤدي الطول غير الصحيح إلى إيقاف التدريب مع ValueError؛ أما flip_idx التي تبدو سليمة لكن أزواجها غير صحيحة، فتؤدي إلى تدريب صامت على تسميات معكوسة، وتظهر المشكلة على شكل تبديلات بين اليسار واليمين أثناء التحقق.

ما الخطوة التالية

بعد ذلك، نصمم نقاطًا رئيسية لكائنات ليست أشخاصًا، ونتعلم كيف تحدد OKS ما إذا كانت النقطة الرئيسية صحيحة.

سجّل الدخول لحفظ التقدم