Crea un'app web per il rilevamento di oggetti personalizzata con MediaPipe

1. Prima di iniziare

Soluzioni MediaPipe ti consente di applicare soluzioni di machine learning (ML) alle tue app. Fornisce un framework che consente di configurare pipeline di elaborazione predefinite che forniscono agli utenti output immediati, coinvolgenti e utili. Puoi anche personalizzare queste soluzioni con Model Maker per aggiornare i modelli predefiniti.

Il rilevamento degli oggetti è una delle diverse attività di visione artificiale ML offerte dalle soluzioni MediaPipe. MediaPipe Tasks è disponibile per Android, Python e il web.

In questo codelab, aggiungerai il rilevamento di oggetti a un'app web per rilevare cani nelle immagini e un video in diretta della webcam.

Obiettivi didattici

Cosa creerai

  • Un'app web che rileva la presenza di cani. Puoi anche personalizzare un modello per rilevare una classe di oggetti di tua scelta con MediaPipe Model Maker.

Che cosa ti serve

  • Un account CodePen.
  • Un dispositivo con un browser web.
  • Conoscenza di base di JavaScript, CSS e HTML

2. Configurazione

Questo codelab esegue il tuo codice in CodePen,un ambiente di sviluppo social che ti consente di scrivere codice nel browser e controllare i risultati mentre crei.

Per effettuare la configurazione, segui questi passaggi:

  1. Nel tuo account CodePen, accedi a questo CodePen. che può essere utilizzato come base di partenza per creare un rilevatore di oggetti personalizzato.
  2. Nella parte inferiore di CodePen nel menu di navigazione, fai clic su Fork per creare una copia del codice iniziale.

Il menu di navigazione di CodePen, in cui si trova il pulsante Fork

  1. Nella scheda JS, fai clic sulla freccia di espansione b15acb07e6357dce.png e seleziona Ingrandisci l'editor JavaScript. Puoi modificare il lavoro solo nella scheda JS per questo codelab, quindi non hai bisogno di vedere le schede HTML o CSS.

Controlla l'app iniziale

  1. Nel riquadro di anteprima sono presenti due immagini di cani e un'opzione per attivare la webcam. Il modello che utilizzi in questo tutorial è stato addestrato sui tre cani mostrati nelle due immagini.

Un'anteprima dell'app web dal codice di avvio

  1. Nella scheda JS, nota che ci sono diversi commenti nel codice. Ad esempio, puoi trovare il seguente commento alla riga 15:
// Import the required package.

Questi commenti indicano dove è necessario inserire gli snippet di codice.

3. Importa il pacchetto Tasks-vision di MediaPipe e aggiungi le variabili richieste

  1. Nella scheda JS, importa il pacchetto MediaPipe tasks-vision:
// Import the required package.
​​import { ObjectDetector, FilesetResolver, Detection } from "https://cdn.skypack.dev/@mediapipe/tasks-vision@latest";

Questo codice utilizza la rete CDN (Content Delivery Network) Skypack per importare il pacchetto. Per ulteriori informazioni su come utilizzare Skypack con CodePen, vedi Skypack + CodePen.

Nei tuoi progetti, puoi utilizzare Node.js con npm, il gestore di pacchetti o la CDN di tua scelta. Per ulteriori informazioni sul pacchetto richiesto da installare, consulta la sezione Pacchetti JavaScript.

  1. Dichiara le variabili per il rilevatore di oggetti e la modalità di esecuzione:
// Create required variables.
let objectDetector = null;
let runningMode = "IMAGE";

La variabile runningMode è una stringa impostata su un valore "IMAGE" quando rilevi oggetti nelle immagini o su un valore "VIDEO" quando rilevi oggetti nel video.

4. Inizializzare il rilevatore di oggetti

  • Per inizializzare il rilevatore di oggetti, aggiungi il seguente codice dopo il commento pertinente nella scheda 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();

Il metodo FilesetResolver.forVisionTasks() specifica la posizione del file binario WebAssembly (Wasm) per l'attività.

Il metodo ObjectDetector.createFromOptions() crea un'istanza del rilevatore di oggetti. Devi fornire un percorso al modello utilizzato per il rilevamento. In questo caso, il modello di rilevamento dei cani è ospitato su Cloud Storage.

La proprietà scoreThreshold è impostata su un valore 0.3. Ciò significa che il modello restituisce i risultati per qualsiasi oggetto rilevato con un livello di confidenza pari o superiore al 30%. Puoi regolare questa soglia in base alle esigenze della tua app.

La proprietà runningMode viene impostata al momento dell'inizializzazione dell'oggetto ObjectDetector. Puoi modificare questa e altre opzioni in base alle tue esigenze in un secondo momento.

5. Esegui previsioni sulle immagini

  • Per eseguire previsioni sulle immagini, vai alla funzione handleClick() e aggiungi il codice seguente al corpo della funzione:
// 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 });
  }

Questo codice determina se il rilevatore di oggetti è inizializzato e garantisce che la modalità di esecuzione sia impostata per le immagini.

Rilevamento di oggetti

  • Per rilevare oggetti nelle immagini, aggiungi il codice seguente al corpo della funzione handleClick():
// Run object detection.
  const detections = objectDetector.detect(event.target);

Il seguente snippet di codice include un esempio dei dati di output di questa attività:

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

Elabora e visualizza le previsioni

  1. Alla fine del corpo della funzione handleClick(), chiama la funzione displayImageDetections():
// Call the displayImageDetections() function.
displayImageDetections(detections, event.target);
  1. Nel corpo della funzione displayImageDetections(), aggiungi il seguente codice per visualizzare i risultati del rilevamento degli oggetti:
// 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);
  }

Questa funzione visualizza riquadri di delimitazione sugli oggetti rilevati nelle immagini. Rimuove qualsiasi evidenziazione precedente, quindi crea e mostra tag <p> per evidenziare ogni oggetto rilevato.

Testa l'app

Quando apporti modifiche al codice in CodePen, il riquadro di anteprima si aggiorna automaticamente al momento del salvataggio. Se il salvataggio automatico è attivato, è probabile che l'app sia già stata aggiornata, ma una buona idea aggiornarla di nuovo.

Per testare l'app, segui questi passaggi:

  1. Nel riquadro di anteprima, fai clic su ciascuna immagine per visualizzare le previsioni. Un riquadro di delimitazione mostra il nome del cane con il livello di confidenza del modello.
  2. Se non è presente un riquadro di delimitazione, apri Chrome DevTools, quindi controlla se sono presenti errori nel riquadro Console oppure rivedi i passaggi precedenti per assicurarti di non aver perso nulla.

Un&#39;anteprima dell&#39;app web con riquadri di delimitazione sopra i cani rilevati nelle immagini

6. Esegui previsioni su un video in diretta della webcam

Rilevamento di oggetti

  • Per rilevare oggetti in un video dal vivo della webcam, vai alla funzione predictWebcam() e aggiungi il seguente codice al corpo della funzione:
// 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);

Il rilevamento di oggetti per i video utilizza gli stessi metodi a prescindere dal fatto che tu esegua l'inferenza su dati in streaming o su un video completo. Il metodo detectForVideo() è simile al metodo detect() utilizzato per le foto, ma include un parametro aggiuntivo per il timestamp associato al frame corrente. La funzione esegue il rilevamento in tempo reale, quindi passi l'ora attuale come timestamp.

Elabora e visualizza le previsioni

  • Per elaborare e visualizzare i risultati del rilevamento, vai alla funzione displayVideoDetections() e aggiungi il seguente codice al corpo della funzione:
//  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);
  }
}

Questo codice rimuove qualsiasi evidenziazione precedente, quindi crea e mostra tag <p> per evidenziare ogni oggetto rilevato.

Testa l'app

Per testare il rilevamento di oggetti vivi, può essere utile avere un'immagine di uno dei cani su cui è stato addestrato il modello.

Per testare l'app, segui questi passaggi:

  1. Scarica una delle foto di cani sul telefono.
  2. Nel riquadro di anteprima, fai clic su Attiva webcam.
  3. Se il browser apre una finestra di dialogo che ti chiede di concedere l'accesso alla webcam, concedi l'autorizzazione.
  4. Tieni in mano la foto del cane sullo smartphone davanti alla webcam. Un riquadro di delimitazione mostra il nome del cane e il livello di confidenza del modello.
  5. Se non è presente un riquadro di delimitazione, apri Chrome DevTools, quindi controlla se sono presenti errori nel riquadro Console oppure rivedi i passaggi precedenti per assicurarti di non aver perso nulla.

Un riquadro di delimitazione sull&#39;immagine di un cane tenuto in mano a una webcam in diretta

7. Complimenti

Complimenti! Hai creato un'app web che rileva oggetti nelle immagini. Per ulteriori informazioni, guarda una versione completa dell'app su CodePen.

Scopri di più