Créer une application Web de détection d'objets personnalisée avec MediaPipe

1. Avant de commencer

MediaPipe Solutions vous permet d'appliquer des solutions de machine learning (ML) à vos applications. Vous accédez à un framework avec lequel vous pouvez configurer des pipelines de traitement prédéfinis qui fournissent aux utilisateurs une sortie immédiate, attrayante et utile. Vous pouvez même personnaliser ces solutions avec Model Maker afin de modifier les modèles par défaut.

La détection d'objets est l'une des nombreuses tâches de vision ML proposées par MediaPipe Solutions. MediaPipe Tasks est disponible pour Android, Python et le Web.

Dans cet atelier de programmation, vous allez ajouter la détection d'objets à une application Web afin de détecter la présence de chiens dans des images et dans une vidéo de webcam en direct.

Points abordés

  • Intégrer une tâche de détection d'objets dans une application Web avec MediaPipe Tasks

Objectifs de l'atelier

  • Concevoir une application web qui détecte la présence de chiens. Vous pouvez également personnaliser un modèle pour détecter une classe d'objets de votre choix avec MediaPipe Model Maker.

Ce dont vous avez besoin

  • Un compte CodePen
  • Un appareil avec un navigateur Web
  • Connaissances de base sur JavaScript, CSS et HTML

2. Configuration

Dans cet atelier de programmation, vous exécutez le code dans CodePen, un environnement de développement social qui vous permet d'écrire votre code dans un navigateur et de vérifier les résultats au moment du build.

Pour commencer, procédez comme suit :

  1. Dans votre compte CodePen, accédez à ce code CodePen. Vous pouvez vous en servir comme base pour créer votre propre détecteur d'objets.
  2. Au bas de CodePen, dans le menu de navigation, cliquez sur Fork (Dupliquer) pour créer une copie du code de démarrage.

Menu de navigation de CodePen, où se situe le bouton de duplication

  1. Dans l'onglet JS, cliquez sur la flèche de développement f079bd83ad4547c9.png, puis sélectionnez Maximize JavaScript editor (Agrandir l'éditeur JavaScript). Pour cet atelier de programmation, vous ne devez modifier que le code de l'onglet JS. Il n'est donc pas nécessaire d'afficher les onglets HTML ou CSS.

Examiner l'application de démarrage

  1. Dans le volet d'aperçu, vous remarquerez deux images de chiens et une option permettant de lancer votre webcam. Le modèle que vous utilisez dans ce tutoriel a été entraîné sur les trois chiens représentés dans les deux images.

Aperçu de l'application Web à partir du code de démarrage

  1. Dans l'onglet JS, vous remarquerez la présence de commentaires tout au long du code. Voici par exemple le commentaire de la ligne 15 :
// Import the required package.

Ces commentaires indiquent où vous devez insérer des extraits de code.

3. Importer le package MediaPipe "tasks-vision" et ajouter les variables requises

  1. Dans l'onglet JS, importez le package MediaPipe tasks-vision :
// Import the required package.
​​import { ObjectDetector, FilesetResolver, Detection } from "https://cdn.skypack.dev/@mediapipe/tasks-vision@latest";

Ce code utilise le réseau de diffusion de contenu (CDN) Skypack pour importer le package. Pour en savoir plus sur l'utilisation de Skypack avec CodePen, consultez Skypack + CodePen.

Dans vos projets, vous pouvez utiliser Node.js avec npm, ou le gestionnaire de packages ou CDN de votre choix. Pour en savoir plus sur le package que vous devez installer, consultez packages JavaScript.

  1. Déclarez des variables du détecteur d'objets ainsi que le mode d'exécution :
// Create required variables.
let objectDetector: ObjectDetector;
let runningMode = "IMAGE";

La variable runningMode est une chaîne définie sur la valeur "IMAGE" lorsque vous détectez des objets dans des images ou sur la valeur "VIDEO" lorsque vous détectez des objets dans des vidéos.

4. Initialiser le détecteur d'objets

  • Pour initialiser le détecteur d'objets, ajoutez le code suivant après le commentaire correspondant dans l'onglet 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();

La méthode FilesetResolver.forVisionTasks() spécifie l'emplacement du binaire WebAssembly (Wasm) pour la tâche.

La méthode ObjectDetector.createFromOptions() permet d'instancier le détecteur d'objets. Vous devez fournir un chemin d'accès au modèle utilisé pour la détection. Dans ce cas, le modèle de détection de chiens est hébergé sur Cloud Storage.

La propriété scoreThreshold est définie sur la valeur 0.3. Par conséquent, le modèle renvoie des résultats pour tout objet détecté avec un niveau de confiance de 30 % ou plus. Vous pouvez ajuster ce seuil selon les besoins de votre application.

La propriété runningMode est définie à l'initialisation de l'objet ObjectDetector. Vous pouvez modifier cette option et d'autres si nécessaire ultérieurement.

5. Exécuter des prédictions sur les images

  • Pour exécuter des prédictions sur des images, accédez à la fonction handleClick(), puis ajoutez le code suivant au corps de la fonction :
// 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 });
  }

Ce code permet de déterminer si le détecteur d'objets est initialisé et de s'assurer que le mode d'exécution est défini pour les images.

Détecter des objets

  • Pour détecter des objets dans des images, ajoutez le code suivant au corps de la fonction handleClick() :
// Run object detection.
  const detections = objectDetector.detect(event.target);

L'extrait de code suivant inclut un exemple des données de sortie de cette tâche :

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

Traiter et afficher les prédictions

  1. À la fin du corps de la fonction handleClick(), appelez la fonction displayImageDetections() :
// Call the displayImageDetections() function.
displayImageDetections(detections, event.target);
  1. Dans le corps de la fonction displayImageDetections(), ajoutez le code suivant pour afficher les résultats de la détection d'objets :
// Display object detection results.

  const ratio = resultElement.height / resultElement.naturalHeight;

  for (const detection of 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);
  }

Cette fonction permet d'afficher des cadres de délimitation sur les objets détectés dans les images. Elle supprime toute mise en évidence existante, puis crée et affiche des tags <p> pour mettre en évidence chaque objet détecté.

Tester l'application

Lorsque vous apportez des modifications à votre code dans CodePen, le volet d'aperçu s'actualise automatiquement lors de l'enregistrement. Si l'enregistrement automatique est activé, votre application s'est probablement déjà actualisée, mais n'hésitez pas à l'actualiser à nouveau.

Pour tester l'application, suivez ces étapes :

  1. Dans le volet d'aperçu, cliquez sur chaque image pour afficher les prédictions. Un cadre de délimitation affiche le nom du chien et le niveau de confiance du modèle.
  2. Si aucun cadre de délimitation ne s'affiche, ouvrez les outils pour les développeurs Chrome, puis vérifiez si des erreurs sont signalées dans le panneau Console. Vous pouvez aussi consulter les étapes précédentes pour vous assurer de n'avoir rien manqué.

Aperçu de l'application Web avec des cadres de délimitation sur les chiens détectés dans les images

6. Exécuter des prédictions sur une vidéo de webcam en direct

Détecter des objets

  • Pour détecter des objets dans une vidéo de webcam en direct, accédez à la fonction predictWebcam(), puis ajoutez le code suivant au corps de la fonction :
// 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 startTimeMs = performance.now();

  // Detect objects with the detectForVideo() method.
  const detections = await objectDetector.detectForVideo(video, startTimeMs);

  displayVideoDetections(detections);

La détection d'objets dans des vidéos utilise les mêmes méthodes, que vous exécutiez l'inférence sur des flux de données ou sur une vidéo complète. La méthode detectForVideo() est semblable à la méthode detect() utilisée pour les photos, mais elle inclut un paramètre supplémentaire pour le code temporel associé à l'image actuelle. La fonction effectue la détection en direct. Vous transmettez donc l'heure actuelle comme code temporel.

Traiter et afficher les prédictions

  • Pour traiter et afficher les résultats de la détection, accédez à la fonction displayVideoDetections(), puis ajoutez le code suivant au corps de la fonction :
//  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);
  }

Ce code supprime toute mise en évidence existante, puis crée et affiche des tags <p> pour mettre en évidence chaque objet détecté.

Tester l'application

Pour tester la détection d'objets en direct, il est utile de disposer d'une image de l'un des chiens sur lesquels le modèle a été entraîné.

Pour tester l'application, suivez ces étapes :

  1. Téléchargez l'une des photos représentant un chien sur votre téléphone.
  2. Dans le volet d'aperçu, cliquez sur Activer la webcam.
  3. Si votre navigateur affiche une boîte de dialogue vous demandant d'accorder l'accès à la webcam, accordez l'autorisation.
  4. Tenez la photo du chien de votre téléphone devant votre webcam. Un cadre de délimitation affiche le nom du chien et le niveau de confiance du modèle.
  5. Si aucun cadre de délimitation ne s'affiche, ouvrez les outils pour les développeurs Chrome, puis vérifiez si des erreurs sont signalées dans le panneau Console. Vous pouvez aussi consulter les étapes précédentes pour vous assurer de n'avoir rien manqué.

Cadre de délimitation sur une image représentant un chien, tenue devant une webcam

7. Félicitations

Félicitations ! Vous avez créé une application Web qui détecte les objets dans les images. Pour en savoir plus, consultez la version complète de l'application sur CodePen.

En savoir plus