Crea una app web para la detección de objetos personalizados con MediaPipe

1. Antes de comenzar

Las MediaPipe Solutions te permiten aplicar soluciones de aprendizaje automático (AA) en tus apps. Proporcionan un framework para que configures canalizaciones de procesamiento compiladas previamente que arrojan resultados inmediatos, pertinentes y útiles para los usuarios. Incluso puedes personalizar estas soluciones con Model Maker para actualizar los modelos predeterminados.

La detección de objetos es una de las muchas tareas de vision de AA que ofrecen las MediaPipe Solutions. MediaPipe Tasks está disponible para Android, Python y la Web.

En este codelab, agregarás la detección de objetos a una app web para detectar perros en imágenes y un video de cámara web en vivo.

Qué aprenderás

  • Cómo incorporar una tarea de detección de objetos en una app web con MediaPipe Tasks.

Qué compilarás

  • Una app web que detecte la presencia de perros. También puedes personalizar un modelo para detectar una clase de objetos de tu elección con MediaPipe Model Maker.

Requisitos

  • Tener una cuenta de CodePen
  • Tener un dispositivo con un navegador web
  • Tener conocimientos básicos de JavaScript, CSS y HTML

2. Prepárate

En este codelab, se ejecuta tu código en CodePen,​ un entorno de desarrollo social que te permite escribir código en el navegador y verificar los resultados a medida que realizas las compilaciones.

Sigue estos pasos para configurarlo:

  1. En tu cuenta de CodePen, navega a este CodePen. Utiliza este código como base para crear tu propio detector de objetos.
  2. En la parte inferior del CodePen en el menú de navegación, haz clic en Fork para crear una copia del código de partida.

El menú de navegación en CodePen en el que se encuentra el botón Fork

  1. En la pestaña JS, haz clic en la flecha de expansión f079bd83ad4547c9.png y, luego, selecciona Maximize JavaScript editor. Solo debes editar el trabajo en la pestaña JS para este codelab, por lo que no necesitas visualizar las pestañas HTML ni CSS.

Revisa la app de partida

  1. En el panel de vista previa, observa que hay dos imágenes de perros y una opción para ejecutar tu cámara web. El modelo que utilizas en este instructivo se entrenó con los tres perros que aparecen en las dos imágenes.

Una vista previa de la app web a partir del código de partida

  1. En la pestaña JS, observa que hay varios comentarios a lo largo del código. Por ejemplo, en la línea 15 encontrarás el siguiente comentario:
// Import the required package.

Estos comentarios indican el lugar en el que debes insertar los fragmentos de código.

3. Importa los paquetes de tareas de vision de MediaPipe y agrega las variables necesarias

  1. En la pestaña JS, importa el paquete tasks-vision de MediaPipe:
// Import the required package.
​​import { ObjectDetector, FilesetResolver, Detection } from "https://cdn.skypack.dev/@mediapipe/tasks-vision@latest";

Este código utiliza la red de distribución de contenidos (CDN) Skypack para importar el paquete. Para obtener más información sobre cómo usar Skypack con CodePen, consulta Skypack + CodePen.

En tus proyectos puedes usar Node.js con npm, o el administrador de paquetes o CDN que prefieras. Para obtener más información sobre los paquetes obligatorios que debes instalar, consulta paquetes de JavaScript.

  1. Declara las variables para el detector de objetos y el modo de ejecución:
// Create required variables.
let objectDetector: ObjectDetector;
let runningMode = "IMAGE";

La variable runningMode es una cadena que se configura en un valor "IMAGE" cuando detectas objetos en imágenes o en un valor "VIDEO" cuando lo haces en videos.

4. Inicializa el detector de objetos

  • Para inicializar el detector de objetos, agrega el siguiente código después del comentario relevante en la pestaña 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();

El método FilesetResolver.forVisionTasks() especifica la ubicación del objeto binario WebAssembly (Wasm) para la tarea.

El método ObjectDetector.createFromOptions() crea una instancia del detector de objetos. Debes proporcionar una ruta para el modelo que se usa en la detección. En este caso, el modelo para detectar perros se aloja en Cloud Storage.

La propiedad scoreThreshold está configurada con un valor 0.3. Esto significa que el modelo muestra resultados para cada objeto detectado con un nivel de confianza del 30% o superior. Puedes ajustar este umbral para satisfacer las necesidades de tus apps.

La propiedad runningMode se establece cuando se inicializa el objeto ObjectDetector. Puedes cambiar esta y otras opciones más adelante según lo necesites.

5. Ejecuta predicciones en imágenes

  • Para ejecutar predicciones en imágenes, navega a la función handleClick() y, luego, agrega el siguiente código al cuerpo de la función:
// 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 });
  }

Este código determina si el detector de objetos se inicializa, y garantiza que el modo de ejecución se configure para las imágenes.

Detecta objetos

  • Para detectar objetos en imágenes, agrega el siguiente código al cuerpo de la función handleClick():
// Run object detection.
  const detections = objectDetector.detect(event.target);

El siguiente fragmento de código incluye un ejemplo de los datos de resultado de esta tarea:

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

Procesa y muestra predicciones

  1. Al final del cuerpo de la función handleClick(), llama a la función displayImageDetections():
// Call the displayImageDetections() function.
displayImageDetections(detections, event.target);
  1. En el cuerpo de la función displayImageDetections(), agrega el siguiente código para mostrar los resultados de la detección de objetos:
// 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);
  }

Esta función muestra los cuadros delimitadores sobre los objetos detectados en las imágenes. Quita los elementos destacados anteriormente y, luego, crea y muestra etiquetas <p> para destacar cada objeto detectado.

Prueba la app

Cuando modificas tu código en CodePen, el panel de vista previa se actualiza automáticamente luego de guardar los cambios. Si está habilitada la función de guardado automático, es probable que tu aplicación ya se haya actualizado, aunque es buena idea volver a actualizarla.

Sigue estos pasos para probar la app:

  1. En el panel de vista previa, haz clic en cada imagen para ver las predicciones. En los cuadros delimitadores, se muestra el nombre de cada perro con el nivel de confianza del modelo.
  2. Si no hay cuadros delimitadores, abre las Herramientas para desarrolladores de Chrome y, luego, verifica el panel de la consola para buscar errores o revisar los pasos anteriores en caso de que no hayas realizado alguno.

Una vista previa de la app web con cuadros delimitadores sobre los perros que se detectaron en las imágenes

6. Ejecuta predicciones en un video de cámara web en vivo

Detecta objetos

  • Para detectar objetos en un video de cámara web en vivo, navega a la función predictWebcam() y, luego, agrega el siguiente código al cuerpo de la función:
// 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 detección de objetos en videos utiliza los mismos métodos sin importar si ejecutas inferencias en datos de transmisión o un video completo. El método detectForVideo() es similar al método detect() que se usa para las fotos, pero incluye un parámetro adicional para la marca de tiempo asociada con el fotograma actual. Esta función realiza detecciones en vivo, por lo que debes pasar el momento actual como la marca de tiempo

Procesa y muestra predicciones

  • Para procesar y mostrar los resultados de la detección, navega a la función displayVideoDetections() y, luego, agrega el siguiente código al cuerpo de la función:
//  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);
  }

Este código quita los elementos destacados anteriormente y, luego, crea y muestra etiquetas <p> para destacar cada objeto detectado.

Prueba la app

Para probar la detección de objetos en vivo, es útil tener la imagen de uno de los perros con los que se entrenó el modelo.

Sigue estos pasos para probar la app:

  1. Descarga una de las fotos con los perros en tu teléfono.
  2. En el panel de vista previa, haz clic en Enable webcam.
  3. Permite el acceso a la cámara web si el navegador lo solicita.
  4. Mantén la foto del perro en tu teléfono frente a tu cámara web. En un cuadro delimitador, se muestra el nombre del perro y el nivel de confianza del modelo.
  5. Si no hay cuadros delimitadores, abre las Herramientas para desarrolladores de Chrome y, luego, verifica el panel de la consola para buscar errores o revisar los pasos anteriores en caso de que no hayas realizado alguno.

Un cuadro delimitador sobre la imagen de un perro frente a una cámara web en directo

7. Felicitaciones

¡Felicitaciones! Creaste una app web que detecta objetos en imágenes. Para obtener más información, consulta una versión completa de la app en CodePen.

Más información