1. قبل البدء
تتيح لك حلول MediaPipe تطبيق حلول تعلُّم الآلة (ML) على تطبيقاتك. وهي توفّر إطار عمل يتيح لك ضبط مسارات معالجة مُنشأة مسبقًا تقدّم للمستخدمين نتائج فورية وجذابة ومفيدة. يمكنك حتى تخصيص هذه الحلول باستخدام Model Maker لتعديل النماذج التلقائية.
رصد العناصر هو إحدى مهام رؤية تعلُّم الآلة التي تقدّمها "حلول MediaPipe". تتوفّر MediaPipe Tasks على Android وPython والويب.
في هذا الدرس التطبيقي حول الترميز، ستضيف ميزة رصد الأهداف إلى تطبيق ويب لرصد الكلاب في الصور وفيديو مباشر لكاميرا ويب.
أهداف الدورة التعليمية
- كيفية دمج مهمة رصد العناصر في تطبيق ويب باستخدام MediaPipe Tasks
ما ستنشئه
- تطبيق ويب يرصد وجود الكلاب. يمكنك أيضًا تخصيص نموذج لرصد فئة من العناصر التي تختارها باستخدام MediaPipe Model Maker.
المتطلبات
- حساب على CodePen
- جهاز مزوّد بمتصفّح ويب
- معرفة أساسية بلغات JavaScript وCSS وHTML
2. طريقة الإعداد
يشغّل هذا الدرس التطبيقي حول الترميز الرمز البرمجي في CodePen، وهي بيئة تطوير اجتماعية تتيح لك كتابة الرمز البرمجي في المتصفّح والتحقّق من النتائج أثناء الإنشاء.
لإكمال عملية الإعداد، يُرجى اتّباع الخطوات التالية:
- في حسابك على CodePen، انتقِل إلى CodePen هذا. يمكنك استخدام هذا الرمز كأساس لبدء إنشاء أداة رصد الكائنات الخاصة بك.
- في أسفل CodePen في قائمة التنقّل، انقر على Fork لإنشاء نسخة من الرمز الأولي.

- في علامة التبويب JS، انقر على سهم أداة التوسيع
، ثمّ اختَر تكبير محرّر JavaScript. يمكنك تعديل العمل في علامة التبويب JS فقط في هذا الدرس التطبيقي حول الترميز، لذا لن تحتاج إلى الاطّلاع على علامتَي التبويب HTML أو CSS.
مراجعة التطبيق الأوّلي
- في جزء المعاينة، لاحظ أنّه توجد صورتان لكلبين وخيار لتشغيل كاميرا الويب. تم تدريب النموذج المستخدَم في هذا البرنامج التعليمي على الكلاب الثلاثة المعروضة في الصورتَين.

- في علامة التبويب JS، لاحظ أنّ هناك عدّة تعليقات في جميع أنحاء الرمز. على سبيل المثال، يمكنك العثور على التعليق التالي في السطر 15:
// Import the required package.
تشير هذه التعليقات إلى الأماكن التي يجب إدراج مقتطفات الرمز فيها.
3- استيراد حزمة MediaPipe tasks-vision وإضافة المتغيرات المطلوبة
- في علامة التبويب JS، استورِد حزمة MediaPipe
tasks-vision:
// Import the required package.
import { ObjectDetector, FilesetResolver, Detection } from "https://cdn.skypack.dev/@mediapipe/tasks-vision@latest";
يستخدم هذا الرمز البرمجي شبكة توصيل المحتوى (CDN) Skypack لاستيراد الحزمة. لمزيد من المعلومات حول كيفية استخدام Skypack مع CodePen، يُرجى الاطّلاع على Skypack + CodePen.
في مشاريعك، يمكنك استخدام Node.js مع npm أو مدير الحزم أو شبكة توصيل المحتوى (CDN) التي تختارها. لمزيد من المعلومات عن الحزمة المطلوبة التي عليك تثبيتها، يُرجى الاطّلاع على حِزم JavaScript.
- عليك تعريف متغيرات لأداة رصد العناصر ووضع التشغيل:
// Create required variables.
let objectDetector = null;
let runningMode = "IMAGE";
المتغيّر runningMode هو سلسلة يتم ضبطها على القيمة "IMAGE" عند رصد عناصر في الصور أو القيمة "VIDEO" عند رصد عناصر في الفيديو.
4. إعداد أداة رصد العناصر
- لتهيئة أداة رصد العناصر، أضِف الرمز التالي بعد التعليق ذي الصلة في علامة التبويب JS:
// Initialize the object detector.
async function initializeObjectDetector() {
const visionFilesetResolver = await FilesetResolver.forVisionTasks(
"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm"
);
objectDetector = await ObjectDetector.createFromOptions(visionFilesetResolver, {
baseOptions: {
modelAssetPath: "https://storage.googleapis.com/mediapipe-assets/dogs.tflite"
},
scoreThreshold: 0.3,
runningMode: runningMode
});
}
initializeObjectDetector();
تحدّد الطريقة FilesetResolver.forVisionTasks() موقع الملف الثنائي WebAssembly (Wasm) الخاص بالمهمة.
ينشئ الإجراء ObjectDetector.createFromOptions() مثيلاً لأداة رصد العناصر. يجب تقديم مسار إلى النموذج المستخدَم في عملية الرصد. في هذه الحالة، تتم استضافة نموذج رصد الكلاب على Cloud Storage.
تم ضبط السمة scoreThreshold على القيمة 0.3. وهذا يعني أنّ النموذج يعرض نتائج لأي عنصر يتم رصده بمستوى ثقة يبلغ 30% أو أكثر. يمكنك تعديل هذا الحدّ لتلبية احتياجات تطبيقك.
يتم ضبط السمة runningMode عند إعداد العنصر ObjectDetector. يمكنك تغيير هذا الخيار وخيارات أخرى حسب الحاجة لاحقًا.
5- تشغيل التوقّعات على الصور
- لتشغيل التوقعات على الصور، انتقِل إلى الدالة
handleClick()، ثم أضِف الرمز التالي إلى نص الدالة:
// Verify object detector is initialized and choose the correct running mode.
if (!objectDetector) {
alert("Object Detector still loading. Please try again");
return;
}
if (runningMode === "VIDEO") {
runningMode = "IMAGE";
await objectDetector.setOptions({ runningMode: runningMode });
}
تحدّد هذه التعليمات البرمجية ما إذا كان قد تمّت تهيئة أداة رصد العناصر وتضمن ضبط وضع التشغيل للصور.
رصد الأجسام
- لاكتشاف العناصر في الصور، أضِف الرمز التالي إلى نص الدالة
handleClick():
// Run object detection.
const detections = objectDetector.detect(event.target);
يتضمّن مقتطف الرمز التالي مثالاً على بيانات الإخراج من هذه المهمة:
ObjectDetectionResult:
Detection #0:
Box: (x: 355, y: 133, w: 190, h: 206)
Categories:
index : 17
score : 0.73828
class name : aci
Detection #1:
Box: (x: 103, y: 15, w: 138, h: 369)
Categories:
index : 17
score : 0.73047
class name : tikka
معالجة التوقعات وعرضها
- في نهاية نص الدالة
handleClick()، استدعِ الدالةdisplayImageDetections():
// Call the displayImageDetections() function.
displayImageDetections(detections, event.target);
- في نص الدالة
displayImageDetections()، أضِف الرمز التالي لعرض نتائج رصد العناصر:
// Display object detection results.
const ratio = resultElement.height / resultElement.naturalHeight;
for (const detection of result.detections) {
// Description text
const p = document.createElement("p");
p.setAttribute("class", "info");
p.innerText =
detection.categories[0].categoryName +
" - with " +
Math.round(parseFloat(detection.categories[0].score) * 100) +
"% confidence.";
// Positioned at the top-left of the bounding box.
// Height is that of the text.
// Width subtracts text padding in CSS so that it fits perfectly.
p.style =
"left: " +
detection.boundingBox.originX * ratio +
"px;" +
"top: " +
detection.boundingBox.originY * ratio +
"px; " +
"width: " +
(detection.boundingBox.width * ratio - 10) +
"px;";
const highlighter = document.createElement("div");
highlighter.setAttribute("class", "highlighter");
highlighter.style =
"left: " +
detection.boundingBox.originX * ratio +
"px;" +
"top: " +
detection.boundingBox.originY * ratio +
"px;" +
"width: " +
detection.boundingBox.width * ratio +
"px;" +
"height: " +
detection.boundingBox.height * ratio +
"px;";
resultElement.parentNode.appendChild(highlighter);
resultElement.parentNode.appendChild(p);
}
تعرض هذه الدالة مربّعات حدودية فوق العناصر التي تم رصدها في الصور. تزيل هذه الطريقة أي تمييز سابق، ثم تنشئ علامات <p> وتعرضها لتمييز كل عنصر يتم رصده.
اختبار التطبيق
عند إجراء تغييرات على الرمز في CodePen، يتم تلقائيًا إعادة تحميل جزء المعاينة عند الحفظ. إذا كانت ميزة الحفظ التلقائي مفعَّلة، من المحتمل أن يكون تطبيقك قد أعاد تحميل الصفحة من قبل، ولكن من المستحسن إعادة تحميلها مرة أخرى.
لاختبار التطبيق، اتّبِع الخطوات التالية:
- في لوحة المعاينة، انقر على كل صورة للاطّلاع على التوقعات. يعرض مربّع حدود اسم الكلب مع مستوى ثقة النموذج.
- إذا لم يكن هناك مربّع حدود، افتح "أدوات مطوّري البرامج في Chrome"، ثم تحقّق من لوحة وحدة التحكّم بحثًا عن أخطاء أو راجِع الخطوات السابقة للتأكّد من أنّك لم تفوّت أي شيء.

6. عرض التوقعات على فيديو مباشر من كاميرا الويب
رصد الأجسام
- لرصد العناصر في فيديو مباشر من كاميرا الويب، انتقِل إلى الدالة
predictWebcam()ثم أضِف الرمز التالي إلى نص الدالة:
// Run video object detection.
// If image mode is initialized, create a classifier with video runningMode.
if (runningMode === "IMAGE") {
runningMode = "VIDEO";
await objectDetector.setOptions({ runningMode: runningMode });
}
let nowInMs = performance.now();
// Detect objects with the detectForVideo() method.
const result = await objectDetector.detectForVideo(video, nowInMs);
displayVideoDetections(result.detections);
تستخدم ميزة "رصد العناصر في الفيديو" الطرق نفسها بغض النظر عمّا إذا كنت تجري الاستدلال على بيانات البث أو على فيديو كامل. تشبه الطريقة detectForVideo() الطريقة detect() المستخدَمة للصور، ولكنّها تتضمّن مَعلمة إضافية للطابع الزمني المرتبط بالإطار الحالي. تنفّذ الدالة عملية الاكتشاف بشكل مباشر، لذا عليك إدخال الوقت الحالي كطابع زمني.
معالجة التوقعات وعرضها
- لمعالجة نتائج الاكتشاف وعرضها، انتقِل إلى الدالة
displayVideoDetections()، ثم أضِف الرمز التالي إلى نص الدالة:
// Display video object detection results.
for (let child of children) {
liveView.removeChild(child);
}
children.splice(0);
// Iterate through predictions and draw them to the live view.
for (const detection of result.detections) {
const p = document.createElement("p");
p.innerText =
detection.categories[0].categoryName +
" - with " +
Math.round(parseFloat(detection.categories[0].score) * 100) +
"% confidence.";
p.style =
"left: " +
(video.offsetWidth -
detection.boundingBox.width -
detection.boundingBox.originX) +
"px;" +
"top: " +
detection.boundingBox.originY +
"px; " +
"width: " +
(detection.boundingBox.width - 10) +
"px;";
const highlighter = document.createElement("div");
highlighter.setAttribute("class", "highlighter");
highlighter.style =
"left: " +
(video.offsetWidth -
detection.boundingBox.width -
detection.boundingBox.originX) +
"px;" +
"top: " +
detection.boundingBox.originY +
"px;" +
"width: " +
(detection.boundingBox.width - 10) +
"px;" +
"height: " +
detection.boundingBox.height +
"px;";
liveView.appendChild(highlighter);
liveView.appendChild(p);
// Store drawn objects in memory so that they're queued to delete at next call.
children.push(highlighter);
children.push(p);
}
}
يزيل هذا الرمز أي تمييز سابق، ثم ينشئ علامات <p> ويعرضها لتمييز كل عنصر تم رصده.
اختبار التطبيق
لاختبار ميزة "التعرّف المباشر على الأجسام"، من المفيد أن تكون لديك صورة لأحد الكلاب التي تم تدريب النموذج عليها.
لاختبار التطبيق، اتّبِع الخطوات التالية:
- نزِّل إحدى صور الكلاب على هاتفك.
- في جزء المعاينة، انقر على تفعيل كاميرا الويب.
- إذا عرض المتصفّح مربّع حوار يطلب منك منح إذن الوصول إلى كاميرا الويب، امنح الإذن.
- ثبِّت صورة الكلب على هاتفك أمام كاميرا الويب. يعرض مربّع حدود اسم الكلب ومستوى ثقة النموذج.
- إذا لم يكن هناك مربّع حدود، افتح "أدوات مطوّري البرامج في Chrome"، ثم تحقّق من لوحة وحدة التحكّم بحثًا عن أخطاء أو راجِع الخطوات السابقة للتأكّد من أنّك لم تفوّت أي شيء.

7. تهانينا
تهانينا! لقد أنشأت تطبيق ويب يرصد العناصر في الصور. لمزيد من المعلومات، يمكنك الاطّلاع على نسخة مكتملة من التطبيق على CodePen.