使用 MediaPipe 建立自訂物件偵測網頁應用程式

1. 事前準備

MediaPipe Solutions 可讓您將機器學習 (ML) 解決方案套用至應用程式。這項服務提供架構,讓您設定預先建立的處理管道,以便向使用者立即提供實用、引人入勝且實用的輸出內容。您還可以使用 Model Maker 自訂這些解決方案,藉此更新預設模型。

物件偵測是 MediaPipe Solutions 提供的幾個機器學習視覺工作之一。MediaPipe 工作支援 Android、Python 和網頁。

在本程式碼研究室中,您要在網頁應用程式中加入物件偵測功能,以偵測圖片中的狗和即時網路攝影機影片。

課程內容

  • 如何透過 MediaPipe 工作在網頁應用程式中整合物件偵測工作。

建構項目

  • 用於偵測是否出現狗的網頁應用程式。您也可以使用 MediaPipe Model Maker 自訂模型來偵測所選物件類別。

軟硬體需求

  • CodePen 帳戶
  • 搭載網路瀏覽器的裝置
  • 對 JavaScript、CSS 和 HTML 有基本瞭解

2. 做好準備

本程式碼研究室會在 CodePen 中執行程式碼;CodePen 是一個社交開發環境,可讓您在瀏覽器中編寫程式碼,並在建構時查看結果。

如要開始設定,請按照下列步驟操作:

  1. 在 CodePen 帳戶中,前往這個 CodePen。您可以使用這個程式碼做為基礎,建立自己的物件偵測工具。
  2. 在導覽選單中,按一下 CodePen 底部的「Fork」,即可複製範例程式碼。

CodePen 中的導覽選單,「Fork」按鈕的位置

  1. 在「JS」分頁中,按一下 b15acb07e6357dce.png 展開箭頭,然後選取「最大化 JavaScript 編輯器」。您只能在本程式碼研究室的「JS」分頁中編輯工作,因此不需要查看「HTML」或「CSS」分頁。

查看範例應用程式

  1. 請注意,預覽窗格中有兩個犬隻圖片,以及執行網路攝影機的選項。您在本教學課程中使用的模型,是根據兩張圖片中顯示的三隻狗訓練而成。

透過範例程式碼預覽網頁應用程式

  1. 在「JS」分頁中,請注意程式碼中有多個註解。例如,您可以在第 15 行找到以下註解:
// Import the required package.

這些註解會指出需要插入程式碼片段的位置。

3. 匯入 MediaPipe Tasks-vision 套件並新增必要變數

  1. 在「JS」分頁中,匯入 MediaPipe tasks-vision 套件:
// Import the required package.
​​import { ObjectDetector, FilesetResolver, Detection } from "https://cdn.skypack.dev/@mediapipe/tasks-vision@latest";

這個程式碼會使用 Skypack 內容傳遞網路 (CDN) 匯入套件。如要進一步瞭解如何將 Skypack 與 CodePen 搭配使用,請參閱「Skypack + CodePen」。

在專案中,您可以搭配 npm 或選擇的套件管理員或 CDN 使用 Node.js。如要進一步瞭解您需要安裝的必要套件,請參閱 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) 二進位檔位置。

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 開發人員工具,然後查看「Console」面板中是否有錯誤,或查看先前的步驟,確保有沒有遺漏任何資訊。

網頁應用程式預覽,圖中偵測到的犬隻上方有定界框

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 開發人員工具,然後查看「Console」面板中是否有錯誤,或查看先前的步驟,確保有沒有遺漏任何資訊。

相片上面的方框方塊顯示正對著即時網路攝影機的狗

7. 恭喜

恭喜!您建構了一個可偵測圖片中物件的網頁應用程式。詳情請參閱「CodePen 上完整的應用程式版本」。

瞭解詳情