יצירת אפליקציית אינטרנט מותאמת אישית לזיהוי אובייקטים באמצעות MediaPipe

1. לפני שמתחילים

בעזרת MediaPipe Solutions אתם יכולים להחיל פתרונות של למידת מכונה (ML) על האפליקציות שלכם. היא מספקת מסגרת שמאפשרת להגדיר צינורות עיבוד נתונים מובנים מראש שמספקים למשתמשים פלט מיידי, מרתק ושימושי. אפשר אפילו להתאים אישית את הפתרונות האלה באמצעות Model Maker כדי לעדכן את המודלים שמוגדרים כברירת מחדל.

זיהוי אובייקטים היא אחת מכמה משימות של ראיית למידת מכונה שמוצעת ב-MediaPipe Solutions. אפליקציית MediaPipe Tasks זמינה ל-Android, ל-Python ולאינטרנט.

ב-Codelab הזה מוסיפים זיהוי אובייקטים לאפליקציית אינטרנט כדי לזהות כלבים בתמונות ובסרטונים בשידור חי ממצלמת אינטרנט.

מה תלמדו

  • איך משלבים משימה של זיהוי אובייקטים באפליקציית אינטרנט באמצעות משימות MediaPipe

מה תפַתחו

  • אפליקציית אינטרנט שמזהה נוכחות של כלבים. תוכלו גם להתאים אישית את המודל כדי לזהות סיווג של אובייקטים לבחירתכם באמצעות MediaPipe Model Maker.

למה תזדקק?

  • חשבון CodePen
  • מכשיר עם דפדפן אינטרנט
  • ידע בסיסי ב-JavaScript, CSS ו-HTML

2. להגדרה

ה-Codelab הזה מריץ את הקוד ב-CodePen,סביבת פיתוח חברתית שמאפשרת לכתוב קוד בדפדפן ולבדוק את התוצאות במהלך הפיתוח.

כדי להשלים את ההגדרה, צריך לבצע את השלבים הבאים:

  1. בחשבון CodePen, עוברים אל ה-CodePen הזה. הקוד הזה משמש כבסיס ליצירת מזהה אובייקטים משלכם.
  2. בתחתית ה-CodePen בתפריט הניווט, לוחצים על Fork כדי ליצור עותק של הקוד לתחילת הפעולה.

תפריט הניווט ב-CodePen שבו נמצא הלחצן Fork

  1. בכרטיסייה JS, לוחצים על חץ ההרחבה b15acb07e6357dce.png ואז בוחרים באפשרות Max JavaScript Editor. צריך לערוך את העבודה בכרטיסייה JS רק עבור ה-Codelab הזה, כך שלא צריך לראות את הכרטיסיות HTML או CSS.

בדיקת האפליקציה לתחילת הפעולה

  1. בחלונית התצוגה המקדימה, תוכלו לראות שמופיעות שתי תמונות של כלבים ואפשרות להפעיל את מצלמת האינטרנט. המודל שבו השתמשתם במדריך הזה עבר אימון על שלושת הכלבים שמוצגים בשתי התמונות.

תצוגה מקדימה של אפליקציית האינטרנט מקוד הסימן לתחילת פעולה

  1. בכרטיסייה JS, תוכלו לראות שיש מספר תגובות לאורך הקוד. לדוגמה, תוכלו למצוא את התגובה הבאה בשורה 15:
// Import the required package.

התגובות האלה מציינות איפה צריך להוסיף קטעי קוד.

3. מייבאים את חבילת החזון של MediaPipe ומוסיפים את המשתנים הנדרשים

  1. בכרטיסייה 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.

  1. יש להצהיר על משתנים בשביל מזהה האובייקטים ובמצב הריצה:
// 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) של המשימה.

ה-method 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

עיבוד והצגת חיזויים

  1. בסוף הגוף של הפונקציה handleClick(), קוראים לפונקציה displayImageDetections():
// Call the displayImageDetections() function.
displayImageDetections(detections, event.target);
  1. בגוף הפונקציה 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, חלונית התצוגה המקדימה תתרענן באופן אוטומטי לאחר השמירה. אם השמירה האוטומטית מופעלת, סביר להניח שכבר מתבצע רענון של האפליקציה, אבל כדאי לרענן שוב.

כדי לבדוק את האפליקציה, פועלים לפי השלבים הבאים:

  1. בחלונית התצוגה המקדימה, לוחצים על כל תמונה כדי לראות את החיזויים. תיבה תוחמת מציגה את שם הכלב עם רמת הסמך של המודל.
  2. אם אין תיבה תוחמת, פותחים את כלי הפיתוח ל-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> כדי להדגיש כל אובייקט שזוהה.

בדיקת האפליקציה

כדי לבדוק את הזיהוי של חפצים פעילים, כדאי לצלם תמונה של אחד מהכלבים שעליהם אומן המודל.

כדי לבדוק את האפליקציה, פועלים לפי השלבים הבאים:

  1. מורידים לטלפון את אחת מהתמונות של הכלב.
  2. בחלונית התצוגה המקדימה, לוחצים על הפעלת מצלמת אינטרנט.
  3. אם בדפדפן מוצגת תיבת דו-שיח שבה תתבקשו להעניק גישה למצלמת האינטרנט, עליכם להעניק הרשאה לכך.
  4. מחזיקים את התמונה של הכלב בטלפון מול מצלמת האינטרנט. תיבה תוחמת מציגה את שם הכלב ואת רמת הסמך של המודל.
  5. אם אין תיבה תוחמת, פותחים את כלי הפיתוח ל-Chrome ובודקים אם יש שגיאות בחלונית המסוף, או בודקים את השלבים הקודמים כדי לוודא שלא פספסתם כלום.

תיבה תוחמת מעל תמונה של כלב שמוצמד למצלמת אינטרנט בזמן אמת

7. מזל טוב

מעולה! יצרתם אפליקציית אינטרנט שמזהה אובייקטים בתמונות. למידע נוסף, ראו גרסה מלאה של האפליקציה ב-CodePen.

מידע נוסף