مراقبة التباعد الإجتماعي بإستخدام الذكاء الصنعي

نقدم لكم في هذا المقال نظام ذكاء صنعي يسمح لنا بمراقبة عملية التباعد الاجتماعي بين الناس بشكل آلي من خلال معالجة الإطارات المتدفقة من الكاميرا .

بحسب الاحصائيات الصادرة عن منظمة الصحة العالمية فأن حصيلة فيروس كورونا اكثر من  6 مليون مصاب , وما يقارب 400 ألف حالة وفاة  حيث تأثرت 213 دولة حتى الآن بهذا الفايروس القاتل .

والسبب الأكثر قلقاً ان فايروس كورونا قد ينتقل من شخص الى آخر من خلال المحادثات اذ كان الشخص الغير مصاب قريب جداً من الشخص المصاب . ونظراً لكثافة السكان في بعض المناطق فإن هذا يشكل تحدياً كبيراً في إيقاف انتشار هذا الفايروس .كل هذا فرض علينا نمط معين من الإجراءات لابد من اتباعها بالتالي احد أفضل الوسائل لإيقاف انتشار الفيروس هو التباعد الاجتماعي ” على الأقل حتى يتم ايجاد لقاح لذلك الفايروس “.

ما هي مسافة الأمان – Social distancing  ؟

ما هي مسافة الأمان – Social distancing  ؟
ما هي مسافة الأمان – Social distancing ؟

هي من أحد وأهم الإجراءات الواجب اتباعها في أوقات الأوبئة لمنع انتشار الأمراض المعدية , تعني أن الناس يجيب أن يبتعدوا بأجسادهم عن بعضهم البعض للحد من انتشار الامراض المعدية .

المحتويات :

1)   مبدأ العام لعمل نموذج الـ Social Distancing .

2)    المبدأ الخاص لعمل نموذج الـ Social Distancing .

3)   مراحل تطور الخوارزميات المستخدمة في عملية الـ Object Detection  .

Sliding Window (a.

R-CNN ( b.

Fast R-CNN ( c.

Faster R-CNN ( d.

Yolov3 ( e.

4)   تنصيب الحزم المطلوبة .

5)   الكود البرمجي الخاص بمشروع الـSocial Distancing  .

6)   مقطع يوضح نتيجة تنفيذ النموذج ( حيث تم تصوير هذا المقطع في كلية التربية في جامعة تشرين).

7)   الملخص .

أولاً : مبدأ عمل نموذج الـ Social Distancing  بشكل عام

1)   اكتشاف الأشخاص في كل اطار من اطارات الفيديو باستخدام خوارزمية الـ  YOLO فهي عبارة عن شبكة عصبونية التفافية قادرة على اكتشاف أغراض متعددة في الزمن الحقيقي بمرور واحد فقط وهي اختصار لـ ” You Look Only Once ” , في هذا النموذج سنقوم باستخدام الإصدار الثالث من هذه الخوارزمية بواسطة  مكتبة Keras  .

2)   حساب المسافة بين كل شخص مع باقي الأشخاص الآخرين من خلال حساب المسافة بين مركزي مربعي الإطار Bounding box   الخاصة بالشخصين المطلوب دراسة وضع التباعد الإجتماعي لهم .

3)   تصنيف المسافة المحددة بين كل شخص مع باقي الأشخاص, اذا كانت المسافة قليلة بالتالي هذا الشخص في مرحلة الخطر وقد يتعرض للإصابة بالتالي يتم وضع إطار لونه أحمر حوله, اما اذا كانت المسافة كبيرة بالتالي هذا الشخص في مرحلة أمان ومنه يتم وضع إطار لونه أخضر حوله .

ثانياً : المبدأ الخاص لعمل نموذج ال Social Distancing

 المبدأ الخاص لعمل نموذج ال Social Distancing
المبدأ الخاص لعمل نموذج ال Social Distancing

1)  ليكن لدينا صورة مدخلة اما (ثابتة أو عبارة عن إطار من إطارات الفيديو ) .

2)  تطبيق خوارزمية الـ object detection  لأكتشاف جميع الأشياء الموجودة في الصورة ( انسان – سيارة – اشارة مرور ) , ثم نأخذ فقط الـ objects  الذي يعبر عن المشاة  من خلال رقم الـ class الخاص بالإنسان .

3)  حساب المسافة بين مركزي الـ bounding box  المتعلقة بكل شخصين في الصورة .

4)  اختبار هذه المسافة بين كل شخصين , اذا كانت اقل من قيمة معينة ” يتم تحديدها في الكود ” بالتالي الشخصين لا يحققوا القواعد الصحية للتباعد الإجتماعي , أو اذا كانت المسافة أكبر بالتالي الشخصين يحققوا قواعد الصحية للتباعد الإجتماعي .

5)  إظهار النتائج .

ثالثاً : مراحل تطور الخوارزميات المستخدمة في عملية الـ Object Detection
Sliding Window (a:

يُقصد بها النوافذ المتحركة , تعتبر الطريقة الأبسط لبناء نموذج يعمل على اكتشاف الكائنات , بحيث مبدأ عملها يعتمد على تقسيم الصورة لعدة مناطق متساوية الحجم وبعد ذلك تصنيف الكائن المكتشف في كل منطقة (انسان – فاكهة -سيارة .. ) , من الممكن ان تكون النوافذ متداخلة فيما بينها وذلك يعتمد على الخطوة stride اذا كانت قليلة جداً من المؤكد سيحدث تداخل أما اذا كانت كبيرة بنسبة معينة لا يحدث تداخل.

خطوات مبدأ عمل الـ Sliding Window برمجياً :

ليكن لدينا صورة ما نقوم بتقسم الصورة الى عدة مناطق متساوية ( على سبيل المثال 10*10 ) من أجل كل منطقة نقوم بما يلي :

1)    نطبق شبكة عصبونية التفافية CNN على كل المناطق التي تم تقسيمها لاكتشاف إذا كانت تحوي كائن أم لا .

2)   استخراج السماتFeatures  المميزة للصورة بوسطة شبكة CNN , على سبيل المثال اذا كان لدينا في الدخل صورة تفاحة وصورة برتقالة والمطلوب القيام بعملية التصنيف لهما , ونعلم ان تفاحة تختلف عن البرتقالة بسمة اللون والطول . مع العلم أن السمات المستخرجة لا نعلمها بل شبكة CNN  تقوم بإيجادها .

ملاحظة : خوارزمية Sliding Window  بسيطة وفعالة لكنها مكلفة زمنياً والسبب في ذلك وجود عدد من المناطق المطلوب تصنيفها حيث من الممكن أن يكون عدد المناطق كبير جداً .لهذا السبب تم تحسينها .

R-CNN ( b:

هي تحسين لخوارزمية Sliding Window  بحيث يتم تجاهل المناطق التي من الممكن أن لا تحوي على كائن, حيث نسمى العملية التي يتم فيها اختيار المناطق التي من الممكن أن تحتوي على كائنب” Region Proposals” اي اقتراحات المنطقة.

تم اقتراح العديد من الخوارزميات “اقتراح المنطقة ” لمعرفة المنطقة الهامة في الصورة” Region of Interest “

ROI  ولكن أفضلها هي خوارزمية “Selective Search” .  وهذه الخوارزمية تقترح تقريبا 2000 منطقة من الصورة مع العلم ان المناطق المقترحة من قبل الخوارزمية هي ليست عشوائية , بل تتميز كل منطقة مقترحة انها تملك نسبة احتمالية كبيرة لوجود object  فيها . يمكن القول أن  R-CNN هي عبارة عن شبكة عصبونية قائمة على أساس المنطقة .

الشكل العام لخوارزمية الـ R-CNN   

الشكل العام لخوارزمية الـ R-CNN
الشكل العام لخوارزمية الـ R-CNN


خطوات مبدأ عمل  R-CNNبرمجياً :

1)   ليكن لدينا صورة ما .

2)   نوجد كل المناطق المهمة في الصورة أي”ROI ” باستخدام خوارزمية “Selective Search” .

3)   من أجل كل منطقة نقوم بما يلي :

A) تطبق على كل منطقة من المناطق التي تم استخراجها شبكة  عصبونية التفافية CNN .

B) استخراج السماتFeatures  المميزة للصورة من شبكة CNN .

C) السمات التي تم استخراجها  من شبكة CNN  يتم ادخالها على شبكة Fully connected تحتوي على خرجين , الخرج الأول هو من اجل توقع مربع التحديد الخاص بكل كائن بحيث يتم استخدام خوارزمية Regression  في الخرج , من الممكن ان تكون”Linear Regression ” التوقع الخطي أو” Kalman Filter Regression”بحيث تتوقع المكان القادم بمعلومية المكان الحالي , عملية اختيار خوارزمية التوقع المناسبة تعتمد على “Tracking Detection ” اي تعقب الكائن, أما بالنسبة للخرج الثاني من اجل تصنيف الكائن الموجود في مربع التحديد الذي تم توقعه في الخرج الأول (انسان – قطة – سيارة . . . ) يتم استخدام خوارزمية الـ SVMs   في الخرج ,حيث خوارزمية SVMs هي خوارزمية Machine Learning تصنف من الخوارزميات الخاضعة للإشراف مهمتها القيام بعملية “binary classification ” تم تطويرها الى خوارزمية SVMs لكي تقوم بمهمة “Binary Classification ” بالإضافة لمهمة ” Classification  Multi  ” .

Fast R-CNN ( c:

تعتبر تحسين لخوارزمية الـ R-CNN ,وعملية التحسين تمت على خطوة الـ feature extraction , بدلاً من تمرير كل المناطق المقترحة  من قبل خوارزمية selective search كلاً على حدى  الى شبكة CNN  لإستخراج السمات features الخاصة بكل منطقة . يتم ادخال الصورة بشكل كامل الى شبكة CNN واستخراج السمات features  للصورة ككل , بعد ذلك يتم ايجاد المناطق المقترحة . نلاحظ ان ذلك يتم بعملية واحدة أما في خوارزمية R-CNN كُنا نحتاج الى 2000 عملية .

الشكل العام لخوارزمية ال Fast R-CNN :

الشكل العام لخوارزمية ال Fast R-CNN
الشكل العام لخوارزمية ال Fast R-CNN

خطوات مبدأ عمل  Fast R-CNNبرمجياً :

1) ليكن لدينا صورة ما .

2) ايجاد كل المناطق المهمة في الصورة أي”ROI ” باستخدام خوارزمية “Selective Search” .

3) ادخال الصورة الى  شبكة CNN  .

4)   استخراج ال features map  من كامل الصورة من خلال شبكة الـ     

conv5 بحيث خرج هذه الشبكة هي عبارة عن صورة تحتوي على الخصائص ” السمات” الخاصة بالصورة المدخلة ,وعدد الـ Features map  في الصورة هو من مرتبات 2n, ولكن في الـ conv5 قيمة n=8  اي ال features  المستخرجة من الconv5 هي 256 .

5)   القيام بعملية اسقاط لكل منطقة من المناطق التي تم أيجادها بواسطة خوارزمية الـ “selective search “ على الـ features map  المناظرة ( اي بمعنى اوضح معرفة موقع كل منطقة مهمة على features map ) .

6)   ادخال جميع المناطق الى شبكة  SSPnet  على شكل صور , كل صورة تعبر عن ROI  بعد ذلك  نقوم بعملية pooling   maxلكل منطقة لتخفيض حجم كل منطقة وجعل ابعادها ثابتة  ,نحن نعلم لا يمكن ان يكون دخل شبكة fully conneted  متغير لهذا السبب جعلنا ابعاد كل منطقة ثابتة وذلك باستخدام شبكة SSPnet .

 ملاحظة : دخل شبكة fully connected عبارة عن vector يحوي السمات features  الخاص بكل منطقة بعد حذف السمات features  الغير مهمة والحفاظ على السمات features  المهمة في هذه المنطقة  .

7) شبكة Fully connectedتحتوي على خرجين , الخرج اللأول هو من اجل توقع مربع التحديد الخاص بكل object بحيث يتم استخدام خوارزمية Regression  Linear  في الخرج, والخرج الثاني من اجل تصنيف الكائن object الموجود في مربع التحديد الذي تم توقعه في الخرج الأول , مع العلم يتم تطبيق تابع softmax  على الخرج الثاني .

Faster R-CNN ( d :

هي عبارة عن تحسين لخوارزمية Fast R-CNN  و R-CNN  , تم الإستغناء عن خوارزمية الـ Selective Search  المكلفة زمنياً و المستخدمة في عملية استخراج المناطق المهمة “ROI ” ( حيث عملية استخراج كل منطقة  تأخد زمناً معيناً بالتالي من اجل 2000 منطقة سوف يكون زمناً كبيراً) . تستخدم خوارزمية الـ   RPN اختصار لـ  Region “  Proposal    “ Networkوهي عبارة عن شبكة استخراج المناطق  حيث  تقوم  باستخراج كل منطقة بشكل سريع جداً تعتمد على مفهوم الـ Anchors .

ملاحظة : تحدثنا عن مفهوم الـ Anchors   بشكل مفصل في المقال الذي عنوانه  ”  خوارزمية يولو الإصدار الثالث -YOLO v3 ” على مدونة شمرا .

Yolov3 ( e :

تعد خوارزمية YOLO  من أهم الخوارزميات المستخدمة في مجال الرؤية الحاسوبية Computer vision  .

ملاحظة : تحدثنا ايضاً عن هذه الخوارزمية بشكل مفصل في المقال الذي عنوانه ”  خوارزمية يولو الإصدار الثالث -YOLO v3 ” على مدونة شمرا .


رابعاً : تنصيب الحزم المطلوبة

 نقوم بتنصيب الحزم التي تساعدنا في بناء النموذج

pip install numpy
pip install imutils
pip install opencv-python
pip install scipy
pip install matplolib

خامساً: الكود البرمجي الخاص بمشروع الـSocial Distancing  

#import the necessary packages
import numpy as np
import cv2
import os
import matplotlib.pyplot as plt
from scipy.spatial import distance as dist
import imutils

استيراد المكتبات :

 المكتبة cv2 والمقصود بها مكتبة ال OpenCv   لرسم حدود مربع الأحاطة Bounding Box  على الإطارات .

المكتبة os  التي يتم من خلالها التعامل مع الملفات .

المكتبة matplotlib من أجل إظهار الأطارات .

المكتبة scipy  تحوي على تابع حساب المسافة الإقليدية .

المكتبة imutils  لتغير حجم الأطار .

# base path to YOLO directory
MODEL_PATH = "yolo-coco"

 ModelPath  هو  مسار المجلد yolo-coco الذي يحتوي بداخله الملف coco.names والملف yolov3.weights والملف yolov3.cfg.

ملف coco.names هو ملف نصي يحوي على اسماء 80  صف class حيث هذه الأسماء  تمثل الكائنات  التي تكتشفها خوارزمية YOLO.

# load the COCO class labels our YOLO model was trained on
labelsPath = os.path.sep.join([MODEL_PATH, "coco.names"])
LABELS = open(labelsPath).read().strip().split("\n")

فتح الملف لعملية القراءة مع القيام  بخطوتي معالجة  :

1)   حذف الفراغات في بداية ونهاية  اسماء الصفوف ان وجدت .. فمثلا اذا لدينا

 ”  person  ” نلاحظ ان  اسم الصف هذا يحتوي فراغات في بدايته ونهايته . فبعد تطبيق تابع Strip() يصبح ” person”  .

2)   كل سطر في الملف coco.names يحوي اسم صف class  بالتالي لقراءة اسماء الكائنات نقوم بقراءة كل سطر على حدة باستخدام التابع ( split(“\n”.

ينتج لدينا لائحة LABELS  يكون الشكل العام لها :

“LABEL[0]=”person
“LABEL[1]=”bicycl
.
.
“LABEL[79]=”toothbrush

# derive the paths to the YOLO weights and model configuration
weightsPath = os.path.sep.join([MODEL_PATH, "yolov3.weights"])
configPath = os.path.sep.join([MODEL_PATH, "yolov3.cfg"])


# load our YOLO object detector trained on COCO dataset (80 classes)
print("[INFO] loading YOLO from disk...")
net = cv2.dnn.readNetFromDarknet(configPath, weightsPath)

تابع readNetFromDarknet لتحميل نموذج YOLO v3  الذي تم تدريبه مسبقاً للقيام بعملية اكتشاف الكائنات باستخدام مكتبة ـKeras .

بالنسبة لملف yolov3.weights يحوي على أوزان الشبكة المدربة .

أما ملف yolov3.cfg هو ملف التكوين , يحوي وصف نصي لبنية الشبكة ( تابع التنشيط لشبكة CNN و أبعاد الصورة التي تتعامل معها الشبكة . . .)  .

# determine only the *output* layer names that we need from YOLO
ln = net.getLayerNames()
ln = [ln[i[0] - 1] for i in net.getUnconnectedOutLayers()]

تحتوي YOLO v3 على ثلاث طبقات خرج هما الطبقات 82  و 94 و 106

التابع getLayerNames يرد قائمة list  بأسماء جميع طبقات الموجودة في شبكة  YOLO ,  وشبكة   YOLO v3   تحوي على 254 طبقة. بالشكل

( ……..,“conv_0”,”bn_0” ,”relu_0” )

التابع getUnconnectedOutLayers  يرد قائمة list بدليل طبقات الخرج, وعند تطبيق هذا التابع على الشبكة  YOLO v3 يرد قائمة بثلاث قيم 200 , 227 , 254 ,

هذه القيم تمثل دليل طبقات الخرح .

وبالتالي للحصول طبقات الخرج المقابلة للقيم السابقة نستخدم [ln[ i[0] – 1

وبهذه الطريقة نحصل طبقات الخرج لنموذج YOLO v3.

# initialize minimum probability to filter weak detections along with
# the threshold when applying non-maxima suppression
MIN_CONF = 0.3
NMS_THRESH = 0.3

MIN_CONF: يعبر عن threshold score  والهدف منها حذف الصناديق التي مدى الثقة الخاصة فيها أقل من حد معين .

NMS_THRESH: يعبر عن IOU  التي من خلالها يتم تحديد  هل الصناديق متداخلة مع بعضها البعض او لا .

ملاحظة : تحدثنا عن مبدأ عمل خوارزمية non-max suppression  في المقال الذي عنوانه ”  خوارزمية يولو الإصدار الثالث -YOLO v3 ” على مدونة شمرا .

def detect_people(frame, net, ln, personIdx=0):
  #Block1
  # grab the dimensions of the frame and  initialize the list of
  # results
  (H, W) = frame.shape[:2]
  results = []


  #Block2
  # construct a blob from the input frame and then perform a forward
  # pass of the YOLO object detector, giving us our bounding boxes
  # and associated probabilities
  blob = cv2.dnn.blobFromImage(frame, 1 / 255.0, (416, 416),swapRB=True, crop=False)
  net.setInput(blob)
  layerOutputs = net.forward(ln)


  #Block3
  # initialize our lists of detected bounding boxes, centroids, and
  # confidences, respectively
  boxes = []
  centroids = []
  confidences = []


  #Block4
  # loop over each of the layer outputs
  for output in layerOutputs:
    # loop over each of the detections
    for detection in output:
      # extract the class ID and confidence (i.e., probability)
      # of the current object detection
      scores = detection[5:]
      classID = np.argmax(scores)
      confidence = scores[classID]


      #Block5
      # filter detections by (1) ensuring that the object
      # detected was a person and (2) that the minimum
      # confidence is met
      if classID == personIdx and confidence > MIN_CONF:
        # scale the bounding box coordinates back relative to
        # the size of the image, keeping in mind that YOLO
        # actually returns the center (x, y)-coordinates of
        # the bounding box followed by the boxes' width and
        # height
        box = detection[0:4] * np.array([W, H, W, H])
        (centerX, centerY, width, height) = box.astype("int")


        #Block6
        # use the center (x, y)-coordinates to derive the top
        # and and left corner of the bounding box
        x = int(centerX - (width / 2))
        y = int(centerY - (height / 2))


        # update our list of bounding box coordinates,
        # centroids, and confidences
        boxes.append([x, y, int(width), int(height)])
        centroids.append((centerX, centerY))
        confidences.append(float(confidence))


  #Block7
  # apply non-maxima suppression to suppress weak, overlapping
  # bounding boxes
  idxs = cv2.dnn.NMSBoxes(boxes, confidences, MIN_CONF, NMS_THRESH)


  #Block8
  # ensure at least one detection exists
  if len(idxs) > 0:
    # loop over the indexes we are keeping
    for i in idxs.flatten():
      # extract the bounding box coordinates
      (x, y) = (boxes[i][0], boxes[i][1])
      (w, h) = (boxes[i][2], boxes[i][3])


      # update our results list to consist of the person
      # prediction probability, bounding box coordinates,
      # and the centroid
      r = (confidences[i], (x, y, x + w, y + h), centroids[i])
      results.append(r)


  # return the list of results
  return results

التابع detect_people   لإ كتشاف الأشخاص في كل إطار من إطارات الفيديو على حدى .

يقبل هذا التابع أربع معاملات :

frame : الاطار من ملف الفيديو أو مباشرة من الكاميرا .

net : نموذج الكشف عن الكائنات YOLO  الذي تم تدريبه مسبقاً.

ln : أسماء طبقات طبقات الخرج لنموذج YOLO

personIdx : يمكن لنموذج YOLO اكتشاف أنواع عديدة من الكائنات (مشاة , سيارة , إشارة مرور . . ) ولكن في هذا المشروع سوف نتعامل مع الأشخاص(مشاة) فقط بالتالي من خلال هذا المعامل نمرر دليل صف Class الذي يعبر عن المشاة.

يعيد هذا التابع قائمة results  تتضمن النتائج النهائية لتطبيق YOLO  على الإطار , و القيم المعادة هي ثقة الكائن واحداثيات مربع الاحاطة والمركز من اجل كل كائن ( مشاة ) مكتشف في الاطار.

Block1

نستخرج أبعاد الاطار

تهيئة القائمة results  .

ملاحظة : ثقة الكائن confidence يعبر عن مدى الثقة في كل box  ان يغطي الكائن object  بأفضل شكل ممكن.

Block2

تطبيق خوارزمية YOLO  على الاطار لكن قبل تطبيق هذه الخوارزمية لابد من اجراء معالجة مسبقة للإطار.

التابع  blobFromImage لأجراء عملية معالجة مسبقة على الاطار حيث يقبل هذا التابع المعاملات التالية :

المعامل الأول يمثل الأطار .

المعامل الثاني هو scale factor لتحجيم قيم بكسلات الصورة ضمن نطاق [0,1]  وهذا يفيد في عملية تسريع معالجة الأطار .

المعامل الثالث لتغيير حجم الإطار الى الأبعاد 416×416 ليتوافق مع نموذج YOLOv3

وذلك لان هذا النموذج يقبل صورة دخل بأبعاد 416×416 بيكسل.

المعامل الرابع swapRB=True لتحويل الصورة من الترتيب RGB الى ترتيب BGR وذلك لان مكتبة OpenCV تتعامل مع صور الملونة بالترتيب BGR.

المعامل الخامس crop=False لإشارة الى عدم اقتصاص الصورة بعد تغير حجمها.

التابع setInput لتطبيق تنسيق blob على الإطار المدخل .

التابع forward يقوم بعملية التنبؤ بجميع الكائنات الموجودة بالإطار (وهو يمثل خرج شبكة YOLO v3).

Block3

نقوم بتهيئة ثلاث قوائم القائمة الأولى boxes ستحوي على احداثيات مربعات الإحاطة (الزاوية اليسرى العليا والزاوية اليمن السفلى ) والقائمة الثانية centroids ستحوي على مركز الكائن وأما القائمة الثالثة confidences  ستحوي على مدى الثقة بكل صندوق أنه سيغطي الكائن بأفضل شكل ممكن .

Block4

حلقتي for  ,  الأولى للمرور على طبقات الخرج الثلاثة لشبكة  YOLO v3   , والثانية من أجل المرور على جميع التنبؤات لكل طبقة  .

القائمة  scores تمثل القيم المتنبئ لتصنيف الكائن المكتشف( c1 , c2 , c3 ……… c80)

التابع np.argmax() حيث يرد هذا دليل العنصر الأكبر في القائمة scorce  

المتحول confidence  يمثل ثقة الكائن .

Block5

تعليمة If  من اجل معالجة الكائنات المكتشفة التي هي مشاة فقط وتجاهل الكائنات الأخرى وايضاً من اجل فلترة الاحتماليات (التخلص من الإحتماليات الضعيفة التي  تقل عن  حد    MIN_CONF ).

Box يمثل احداثيات مربع الإحاطة Bounding box( المركز , الطول والعرض )  مطبق عليها Normalization أي مجال قيمها ]0,1[ وبالتالي يجب ضرب هذه الاحداثيات في طول وعرض الإطار للحصول على احداثيات   Bounding box  الصحيحة على الإطار .

التابع astype() لقصر قيم محددة الى نوع معين من البيانات, حيث نحول قيم احداثيات صندوق الاحاطة الى نوع البيانات Integer .

Block6

 نحصل على احداثيات الزاوية العليا اليسرى لصندوق الإحاطة انطلاقا من مركز صندوق الاحاطة وعرضه وطوله بالشكل التالي :

(X = centerX – (width/2

(Y = centerY – (height / 2

حيث (centerX,centerY) تمثل احداثيات مركز مربع الإحاطة .

ملاحظة :خوارزمية YOLO v3 تتنبأ بمركز مربع الإحاطة وطوله وعرضه .

Block7

التابع NMSBoxes() يطبق خوارزمية  Non-max Suppression  على مربعات الإحاطة التي تم التنبؤ بها بوسطة خوارزمية YOLO v3  بالاعتماد على الوسطاء التالية :

Boxes : قائمة تحتوي على جميع مربعات التحديد (bounding boxes  )  للكائنات ( مشاة فقط ) الموجودة في الإطار .

Confidences  :  قائمة تحتوي على مدى الثقة المقابلة لكل مربع تحديد .

Min_Conf : يعبر عن threshold score  والهدف منها حذف الصناديق التي مدى الثقة الخاصة فيها أقل من حد معين .

NMS_THRESH : يعبر IOU  التي من خلالها نحدد هل الصناديق متداخلة مع بعضها البعض او لا .

Block8

تعليمة if  للتأكد من وجود كائن ( مشاة )  مكتشف على الأقل ففي حال وِجد كائن واحد او أكثر تتم اضافة معلومات هذه الكائنات الى القائمة results  .

ملاحظة : المقصود بمعلومات الكائن هنا ( ثقة الكائن – احداثيات مربع الإحاطة – المركز ).

input = "testvideo.mp4"
vs = cv2.VideoCapture(input if input else 0)
writer = None

input  مسار مقطع الفيديو الذي سوف نطبق عليه النموذج .

التابع VideoCapture  لقراءة الفيديو من المسار المحدد .

نهيئ كاتب فيديو الخرج بالقيمة None

output = "outputvideo.avi"
display = 0

output  مسار الملف  الذي سنضع فيه فيديو الخرج الناتج  عن تطبيق النموذج .

display هذا المتحول في حال كانت قيمته أكبر من الصفر يتم إظهار اطارت الفيديو أثناء تطبيق النموذج.

# define the minimum safe distance (in pixels) that two people can be
# from each other
MIN_DISTANCE = 100

Min_Distance : تعبر عن قيمة العتبة التي من خلالها نحدد اذا كانت المسافة بين شخصين تحقق قواعد التباعد الصحي او لا .

# loop over the frames from the video stream
while True:
  #Block1
  # read the next frame from the file
  (grabbed, frame) = vs.read()


  # if the frame was not grabbed, then we have reached the end
  # of the stream
  if not grabbed:
    break


  #Block2
  # resize the frame and then detect people (and only people) in it
  frame = imutils.resize(frame, width=700)
  results = detect_people(frame, net, ln,personIdx=LABELS.index("person"))


  # initialize the set of indexes that violate the minimum social
  # distance
  violate = set()


  #Block3
  # ensure there are *at least* two people detections (required in
  # order to compute our pairwise distance maps)
  if len(results) >= 2:
    # extract all centroids from the results and compute the
    # Euclidean distances between all pairs of the centroids
    centroids = np.array([r[2] for r in results])
    D = dist.cdist(centroids, centroids, metric="euclidean")


    #Block4
    # loop over the upper triangular of the distance matrix
    for i in range(0, D.shape[0]):
      for j in range(i + 1, D.shape[1]):
        # check to see if the distance between any two
        # centroid pairs is less than the configured number
        # of pixels
        if D[i, j] < MIN_DISTANCE:
          # update our violation set with the indexes of
          # the centroid pairs
          violate.add(i)
          violate.add(j)


  #Block5
  # loop over the results
  for (i, (prob, bbox, centroid)) in enumerate(results):
    # extract the bounding box and centroid coordinates, then
    # initialize the color of the annotation
    (startX, startY, endX, endY) = bbox
    (cX, cY) = centroid
    color = (0, 255, 0)


    #Block6
    # if the index pair exists within the violation set, then
    # update the color
    if i in violate:
      color = (0, 0, 255)


    # draw (1) a bounding box around the person and (2) the
    # centroid coordinates of the person,
    cv2.rectangle(frame, (startX, startY), (endX, endY), color, 2)


  #Block7
  # draw the total number of social distancing violations on the
  # output frame
  text = "Social Distancing Violations: {}".format(len(violate))
  cv2.putText(frame, text, (10, frame.shape[0] - 25),cv2.FONT_HERSHEY_SIMPLEX, 0.85, (0, 0, 255), 3)


  #Block8
  # check to see if the output frame should be displayed to our
  # screen
  if display > 0:
    # show the output frame
    plt.imshow( frame)
    key = cv2.waitKey(1) & 0xFF


    # if the `q` key was pressed, break from the loop
    if key == ord("q"):
      break


  # if an output video file path has been supplied and the video
  # writer has not been initialized, do so now
  if output != "" and writer is None:
    # initialize our video writer
    fourcc = cv2.VideoWriter_fourcc(*"MJPG")
    writer = cv2.VideoWriter(output, fourcc, 25,
      (frame.shape[1], frame.shape[0]), True)


  # if the video writer is not None, write the frame to the output
  # video file
  if writer is not None:
    writer.write(frame)

حلقة while  من اجل معالجة إطارات الفيديو .

Block1  

قراءة اطار من الفيديو .

حيث تابع القراءة يعيد قيمتين :

Frame  : يعبر عن الإطار المقروء .

Grabbed : متحول بولياني اذا كانت قيمته True  بالتالي تمت قراءة الأطار بنجاح , اما اذا كانت قيمته False  عندها لايوجد إطار لقرائته بالتالي نكون قد وصلنا إلى نهاية الفيديو .

تعليمة if  في حال وصلنا الى نهاية الفيديو اي لايوجد اطار لقرائته عندها تكون قيمة المتحول grabbed هي False   . فيتم كسرالتنفيذ والخروج من الحلقة .

Block2

التابع resize  يقوم بتغير ابعاد الإطار .

التابع detect_people   يعيد المعلومات حول كل الكائنات المكتشفة ” مشاة ” في الأطار .وتم  توضيح الية عمل هذا التابع في الأعلى .

  تهيئة المجموعة violate  ليتم وضع فيها فيما بعد دليل الكائنات التي انتهكت قواعد التباعد الأجتماعي .

Block3

تعليمة if للتأكد من وجود شخصين على الأقل في الإطار من اجل القيام بحساب المسافة بينهما .

ملاحظة : في حال وجود شخص واحد في الأطار بالتالي هذا الشخص لاداعي لمعالجة حالة التباعد الأجتماعي له ( لأنه ضمنياً يحقق شروط التباعد الصحي فهو الوحيد الموجود في المكان ) .

استخراج جميع النقاط التي تمثل منتصف الكائنات المكتشفة من اجل حساب المسافة الإقليدية بينها.

التابع cdist   لحساب المسافة الإقليدية بين كل  مركز الكائن مع باقي مراكز الكائنات الأخرى   

Block4

حلقتي for   تستخدم من اجل مقارنة كل مربع إحاطة مع باقي المربعات الخرى , من خلال حساب المسافة الإقليدية بين احداثيات نقطتي المركز لكل من المربعين , واذ كانت هذه المسافة اقل من قيمة

Min-Distance   بالتالي نضيف دليلي هذين المربعين الى مجموعة violate .

Block5

حلقة for  للمرور على كل الكائنات ( المشاة ) المكتشفة في الأطار , أي على جميع قيم القائمة result  التي يردها التابع detect_people  .

ثم نهيئ متحول  color  افتراضياً بالقيم التي تمثل اللون الأخضر وفق الترتيب BGR .

Block6

تعليمة if   لتبديل قيم المتحول color  من القيم التي تمثل اللون الأخضر الى القيم التي تمثل اللون الأحمر وفق الترتيب BGR  . وذلك من اجل كل كائن ينتهك قواعد التباعد الإجتماعي.

التابع rectangle  لرسم مربع احاطة حول الكائن ففي حال كان  الكائن لاينتهك قواعد التباعد الأجتماعي يكون لون المربع أخضر والعكس أحمر

ملاحظة : لرسم مستطيل باستخدام مكتبة الـ OpenCV يجب تحديد زاوية المستطيل العليا اليسرى وزاويته السفلى اليمنى

وسطاء التابع rectangle هي :

الوسيط الأول هو  الإطار المراد رسم مستطيل عليه .

الوسيط الثاني والثالث هما إحداثيات زاوية المستطيل العليا اليسرى والسفلى اليمنى.

الوسيط الرابع هو لون خط المستطيل .

الوسيط الخامس هو لسماكة خط المستطيل .

Block7

وضع نص على الإطار  يعبر عن عدد الأشخاص الذين ينتهكون قواعد التباعد الإجتماعي وهو مساوي لطول المجموعة violat .

لأضافه نص للصورة علينا تحديد :

النص الذي نريد إدراجه , موضع النص بالنسبة للصورة (الزاوية السفلى اليسرى ) ,نوع الخط ,عامل مقياس الخط (الذي يتم ضربه في الحجم الأساسي للخط), اللون , السماكة.

Block8

 تعليمة if  لإختبار المتحول display  , اذا كانت قيمته أكبر من الصفر بالتالي  يتم اظهار إطارات الفيديو أثناء معالجة هذه الإطارات .

تعليمة if  الثانية لكسر التنفيذ  والخروج من حلقة while  في حال تم الضغط على الزر “q “.

تعليمة if  الثالثة لإختبار المتحول output  اذا كان مُسند له مسار الخرج  و لم يتم كتابة أي إطار في هذا المسار. فإذا تحقق هذا الشرط نهيئ كاتب الفيديو بمسار ملف الخرج ” الفيديو ” ومعدل اطارات الفيديو المنشأ ( عدد إطارات الفيديو ) .

تعليمة if  الرابعة لإختبار اذا كان كاتب الفيديو مهيئ بالتالي كتابة الأطارات على هذا الملف .


سادساً : مقطع يوضح نتيجة تنفيذ النموذج ( حيث تم تصوير هذا المقطع في كلية التربية في جامعة تشرين)

https://youtube.com/watch?v=zgOx6LXgM70%3Fshowinfo%3D0

الأشخاص الذين حولهم صندوق أحمر هم في مرحلة الخطر أما الأشخاص الذين حولهم صندوق أخضر هم في مرحلة الأمان .

سابعاً : ملخص

في هذا المقال تعلمنا كيف نحقق كاشف التباعد الإجتماعي باستخدام OpenCv  و Deep Learning  و Computer Vision  بالخطوات التالية :

  1. استخدام خوارزمية ال YOLO  لإكتشاف الأشخاص في الإطارات المتدفقة من الفيديو .
  2.  تحديد مركز كل كائن ( شخص ) مكتشف .
  3. حساب المسافة بين كل زوجين من المراكز .
  4. اختبار هذه المسافة اذا كانت تحقق قواعد التباعد الجتماعي أو لا من قيمة معينة يتم تحديدها في الكود .

رابط تحميل المشروع :

https://github.com/Mohammadkardi1/Social-Distancing-Detector/tree/master?fbclid=IwAR27WzN43_G0Jf05iS626Pl8p5JSHyTRzwunbTiSC2QFoXWd7HDf_DRQT8g

ملاحظة : الملف yolov3.weights يبلغ حجمها 237 ميغا بايت لذلك لم نستطع رفعها على موقع github تستطيع تحميله من الموقعهنا

المصدر :

تقديم كلاً من :

محمد  كردي

محمد ذويب