Tworzenie niestandardowej aplikacji internetowej do wykrywania obiektów za pomocą MediaPipe

1. Zanim zaczniesz

MediaPipe Solutions umożliwia stosowanie w aplikacjach rozwiązań wykorzystujących systemy uczące się. Udostępnia ona ramy, które umożliwiają konfigurowanie gotowych przepływów przetwarzania, które dostarczają użytkownikom natychmiastowych, atrakcyjnych i przydatnych wyników. Możesz nawet dostosować te rozwiązania za pomocą Model Makera, aby zaktualizować modele domyślne.

Wykrywanie obiektów to jedno z kilku zadań dotyczących widzenia AI, które oferuje MediaPipe Solutions. MediaPipe Tasks jest dostępny w wersji na Androida, w Pythonie i w internecie.

W tym laboratorium kodu dodasz do aplikacji internetowej wykrywanie obiektów, aby wykrywać psy na zdjęciach i w filmach z kamery internetowej.

Czego się nauczysz

  • Jak uwzględnić zadanie wykrywania obiektów w aplikacji internetowej za pomocą MediaPipe Tasks.

Co utworzysz

  • Aplikacja internetowa, która wykrywa obecność psów. Możesz też dostosować model do wykrywania wybranej klasy obiektów za pomocą MediaPipe Model Maker.

Czego potrzebujesz

  • Konto CodePen
  • Urządzenie z przeglądarką
  • podstawy JavaScriptu, CSS i HTML;

2. Konfiguracja

Ten warsztat programistyczny uruchamia kod w CodePen, czyli środowisku programistycznym, które umożliwia pisanie kodu w przeglądarce i sprawdzanie wyników w miarę tworzenia.

Aby przeprowadzić konfigurację, wykonaj te czynności:

  1. Na koncie CodePen otwórz CodePen. Użyj tego kodu jako podstawy do utworzenia własnego wykrywacza obiektów.
  2. W dolnej części CodePen w menu nawigacyjnym kliknij Fork (Fork), aby utworzyć kopię kodu startowego.

Menu nawigacyjne w CodePen, w którym znajduje się przycisk Fork

  1. Na karcie JS kliknij strzałkę b15acb07e6357dce.png i wybierz Maksymalizacja edytora JavaScript. W tym ćwiczeniu możesz edytować tylko kod na karcie JS, więc nie musisz wyświetlać kart HTML ani CSS.

Sprawdzanie aplikacji inicjującej

  1. W panelu podglądu zobaczysz 2 zdjęcia psów i opcję włączenia kamery internetowej. Model, którego używasz w tym samouczku, został wytrenowany na 3 psach widocznych na 2 obrazach.

Podgląd aplikacji internetowej utworzonej na podstawie kodu startowego

  1. Na karcie JS widać, że w kodzie znajduje się kilka komentarzy. Na przykład w wierszu 15 możesz znaleźć taki komentarz:
// Import the required package.

Te komentarze wskazują, gdzie należy wstawić fragmenty kodu.

3. Zaimportuj pakiet MediaPipe tasks-vision i dodaj wymagane zmienne

  1. Na karcie JS zaimportuj pakiet MediaPipe tasks-vision:
// Import the required package.
​​import { ObjectDetector, FilesetResolver, Detection } from "https://cdn.skypack.dev/@mediapipe/tasks-vision@latest";

Ten kod używa sieci dostarczania treści (CDN) Skypack do importowania pakietu. Więcej informacji o korzystaniu z Skypack w połączeniu z CodePen znajdziesz w artykule Skypack + CodePen.

W swoich projektach możesz używać Node.js z npm lub wybranego menedżera pakietów albo CDN. Więcej informacji o wymaganym pakiecie, który należy zainstalować, znajdziesz w artykule Pakiety JavaScript.

  1. Zadeklaruj zmienne dla detektora obiektów i trybu działania:
// Create required variables.
let objectDetector = null;
let runningMode = "IMAGE";

Zmienna runningMode to ciąg znaków, który ma wartość "IMAGE", gdy wykryjesz obiekty na zdjęciach, lub wartość "VIDEO", gdy wykryjesz obiekty w filmie.

4. Inicjalizacja detektora obiektów

  • Aby zainicjować detektor obiektów, dodaj ten kod po odpowiednim komentarzu na karcie 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();

Metoda FilesetResolver.forVisionTasks() określa lokalizację binarnego pliku WebAssembly (Wasm) dla zadania.

Metoda ObjectDetector.createFromOptions() tworzy instancję detektora obiektów. Musisz podać ścieżkę do modelu używanego do wykrywania. W tym przypadku model wykrywania psów jest hostowany w Cloud Storage.

Właściwość scoreThreshold ma wartość 0.3. Oznacza to, że model zwraca wyniki dla każdego wykrytego obiektu z poziomem ufności co najmniej 30%. Możesz dostosować ten próg do potrzeb swojej aplikacji.

Właściwość runningMode jest ustawiana podczas inicjowania obiektu ObjectDetector. W razie potrzeby możesz później zmienić tę i inne opcje.

5. Przeprowadzanie prognoz na obrazach

  • Aby przeprowadzić przewidywania na podstawie obrazów, otwórz funkcję handleClick() i dodaj do jej treści ten kod:
// 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 });
  }

Ten kod określa, czy detektor obiektów jest zainicjowany, i zapewnia, że tryb działania jest ustawiony dla obrazów.

Wykrywanie obiektów

  • Aby wykrywać obiekty na obrazach, dodaj do funkcji handleClick() ten kod:
// Run object detection.
  const detections = objectDetector.detect(event.target);

Ten fragment kodu zawiera przykład danych wyjściowych z tego zadania:

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

Przetwarzanie i wyświetlanie prognoz

  1. Na końcu ciała funkcji handleClick() wywołaj funkcję displayImageDetections():
// Call the displayImageDetections() function.
displayImageDetections(detections, event.target);
  1. Aby wyświetlić wyniki wykrywania obiektów, dodaj do treści funkcji displayImageDetections() ten kod:
// 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);
  }

Ta funkcja wyświetla ramki wokół obiektów wykrytych na obrazach. Usuwa wcześniejsze wyróżnienia, a następnie tworzy i wyświetla tagi <p>, aby wyróżnić każdy wykryty obiekt.

Testowanie aplikacji

Gdy wprowadzisz zmiany w kodzie w CodePen, po zapisaniu panel podglądu zostanie automatycznie odświeżony. Jeśli automatyczne zapisywanie jest włączone, aplikacja prawdopodobnie została już odświeżona, ale warto ją odświeżyć jeszcze raz.

Aby przetestować aplikację:

  1. W okienku podglądu kliknij po kolei wszystkie obrazy, aby wyświetlić prognozy. Pole ograniczające zawiera nazwę psa i poziom ufności modelu.
  2. Jeśli nie ma ramki, otwórz Narzędzia deweloperskie w Chrome, a potem sprawdź panel Konsola pod kątem błędów. Możesz też sprawdzić poprzednie kroki, aby upewnić się, że niczego nie pominięto.

Podgląd aplikacji internetowej z ramkami wokół psów wykrytych na zdjęciach

6. Wykonywanie prognoz na podstawie obrazu z kamery internetowej

Wykrywanie obiektów

  • Aby wykrywać obiekty na bieżąco w filmie z kamery internetowej, otwórz funkcję predictWebcam() i dodaj do niej ten kod:
// 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);

Wykrywanie obiektów w filmie wykorzystuje te same metody niezależnie od tego, czy wykonujesz wnioskowanie na danych strumieniowych, czy na całym filmie. Metoda detectForVideo() jest podobna do metody detect() używanej w przypadku zdjęć, ale zawiera dodatkowy parametr dla sygnatury czasowej powiązanej z bieżącą ramką. Funkcja wykonuje wykrywanie na żywo, więc jako sygnatury czasowej używasz bieżącego czasu.

Przetwarzanie i wyświetlanie prognoz

  • Aby przetworzyć i wyświetlić wyniki wykrywania, otwórz funkcję displayVideoDetections() i dodaj do niej ten kod:
//  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);
  }
}

Ten kod usuwa wcześniejsze wyróżnienia, a następnie tworzy i wyświetla tagi <p>, aby wyróżnić każdy wykryty obiekt.

Testowanie aplikacji

Aby przetestować wykrywanie obiektów na żywo, warto mieć obraz jednego z psów, na których model został wytrenowany.

Aby przetestować aplikację:

  1. Pobierz na telefon jedno ze zdjęć psa.
  2. W okienku podglądu kliknij Włącz kamerę.
  3. Jeśli przeglądarka wyświetli okno z prośbą o dostęp do kamery internetowej, przyznaj go.
  4. Trzymaj zdjęcie psa na telefonie przed kamerą internetową. Boks ograniczający zawiera nazwę psa i poziom ufności modelu.
  5. Jeśli nie ma ramki, otwórz Narzędzia deweloperskie w Chrome, a potem sprawdź panel Konsola pod kątem błędów. Możesz też sprawdzić poprzednie kroki, aby upewnić się, że niczego nie pominięto.

Ramka ograniczająca na obrazie przedstawiającym psa trzymanego przed kamerą internetową

7. Gratulacje

Gratulacje! Utworzyłeś(-aś) aplikację internetową, która wykrywa obiekty na obrazach. Więcej informacji znajdziesz w gotowej wersji aplikacji na CodePen.

Więcej informacji