Tạo ứng dụng web phát hiện đối tượng tuỳ chỉnh bằng MediaPipe

1. Trước khi bắt đầu

Giải pháp MediaPipe cho phép bạn áp dụng các giải pháp học máy (ML) cho ứng dụng. Giải pháp này cung cấp một khung cho phép bạn định cấu hình các quy trình xử lý dựng sẵn để cung cấp kết quả đầu ra tức thì, hấp dẫn và hữu ích cho người dùng. Bạn thậm chí có thể tuỳ chỉnh các giải pháp này bằng Model Maker để cập nhật các mô hình mặc định.

Phát hiện vật thể là một trong số các tác vụ thị giác học máy mà Giải pháp MediaPipe cung cấp. Bạn có thể sử dụng MediaPipe Tasks cho Android, Python và web.

Trong lớp học lập trình này, bạn sẽ thêm tính năng phát hiện vật thể vào một ứng dụng web để phát hiện chó trong hình ảnh và video trực tiếp từ webcam.

Kiến thức bạn sẽ học được

  • Cách kết hợp tác vụ phát hiện vật thể trong một ứng dụng web bằng MediaPipe Tasks.

Sản phẩm bạn sẽ tạo ra

  • Một ứng dụng web phát hiện sự hiện diện của chó. Bạn cũng có thể tuỳ chỉnh một mô hình để phát hiện một loại đối tượng mà bạn chọn bằng MediaPipe Model Maker.

Bạn cần có

  • Một tài khoản CodePen
  • Một thiết bị có trình duyệt web
  • Kiến thức cơ bản về JavaScript, CSS và HTML

2. Bắt đầu thiết lập

Lớp học lập trình này chạy mã của bạn trong CodePen – một môi trường phát triển xã hội cho phép bạn viết mã trong trình duyệt và kiểm tra kết quả khi bạn xây dựng.

Để thiết lập, hãy làm theo các bước sau:

  1. Trong tài khoản CodePen, hãy chuyển đến CodePen này. Bạn sử dụng mã này làm cơ sở ban đầu để tạo trình phát hiện vật thể của riêng mình.
  2. Ở cuối CodePen trong trình đơn điều hướng, hãy nhấp vào Fork (Phân nhánh) để tạo bản sao của mã khởi đầu.

Trình đơn điều hướng trong CodePen, nơi có nút Fork

  1. Trong thẻ JS, hãy nhấp vào mũi tên mở rộng b15acb07e6357dce.png rồi chọn Maximize JavaScript editor (Tối đa hoá trình chỉnh sửa JavaScript). Bạn chỉ chỉnh sửa công việc trong thẻ JS cho lớp học lập trình này, vì vậy, bạn không cần xem các thẻ HTML hoặc CSS.

Xem lại ứng dụng khởi đầu

  1. Trong ngăn xem trước, hãy lưu ý rằng có 2 hình ảnh về chó và một lựa chọn để chạy webcam. Mô hình mà bạn sử dụng trong hướng dẫn này được huấn luyện trên 3 chú chó hiển thị trong 2 hình ảnh.

Bản xem trước của ứng dụng web từ mã khởi đầu

  1. Trong thẻ JS, hãy lưu ý rằng có một số nhận xét trong suốt mã. Ví dụ: bạn có thể tìm thấy nhận xét sau trên dòng 15:
// Import the required package.

Các nhận xét này cho biết vị trí bạn cần chèn đoạn mã.

3. Nhập gói tasks-vision MediaPipe và thêm các biến bắt buộc

  1. Trong thẻ JS, hãy nhập gói tasks-vision MediaPipe:
// Import the required package.
​​import { ObjectDetector, FilesetResolver, Detection } from "https://cdn.skypack.dev/@mediapipe/tasks-vision@latest";

Mã này sử dụng mạng phân phối nội dung (CDN) Skypack để nhập gói. Để biết thêm thông tin về cách sử dụng Skypack với CodePen, hãy xem Skypack + CodePen.

Trong các dự án, bạn có thể sử dụng Node.js với npm hoặc trình quản lý gói hoặc CDN mà bạn chọn. Để biết thêm thông tin về gói bắt buộc mà bạn cần cài đặt, hãy xem Gói JavaScript.

  1. Khai báo các biến cho trình phát hiện vật thể và chế độ chạy:
// Create required variables.
let objectDetector = null;
let runningMode = "IMAGE";

Biến runningMode là một chuỗi được đặt thành giá trị "IMAGE" khi bạn phát hiện các vật thể trong hình ảnh hoặc giá trị "VIDEO" khi bạn phát hiện các vật thể trong video.

4. Khởi chạy trình phát hiện vật thể

  • Để khởi động trình phát hiện vật thể, hãy thêm mã sau vào sau nhận xét có liên quan trong thẻ 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();

Phương thức FilesetResolver.forVisionTasks() chỉ định vị trí của tệp nhị phân WebAssembly (Wasm) cho tác vụ.

Phương thức ObjectDetector.createFromOptions() tạo thực thể cho trình phát hiện vật thể. Bạn phải cung cấp một đường dẫn đến mô hình dùng để phát hiện. Trong trường hợp này, mô hình phát hiện chó được lưu trữ trên Cloud Storage.

Thuộc tính scoreThreshold được đặt thành giá trị 0.3. Điều này có nghĩa là mô hình trả về kết quả cho mọi vật thể được phát hiện với mức độ tin cậy từ 30% trở lên. Bạn có thể điều chỉnh ngưỡng này cho phù hợp với nhu cầu của ứng dụng.

Thuộc tính runningMode được thiết lập khi khởi chạy đối tượng ObjectDetector. Bạn có thể thay đổi thuộc tính này và các lựa chọn khác khi cần sau này.

5. Chạy dự đoán trên hình ảnh

  • Để chạy dự đoán trên hình ảnh, hãy chuyển đến hàm handleClick() rồi thêm mã sau vào nội dung của hàm:
// 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 });
  }

Mã này xác định xem trình phát hiện vật thể đã được khởi chạy hay chưa và đảm bảo rằng chế độ chạy được đặt cho hình ảnh.

Phát hiện vật thể

  • Để phát hiện các vật thể trong hình ảnh, hãy thêm mã sau vào nội dung của hàm handleClick():
// Run object detection.
  const detections = objectDetector.detect(event.target);

Đoạn mã sau đây chứa một ví dụ về dữ liệu đầu ra từ tác vụ này:

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

Xử lý và hiển thị dự đoán

  1. Ở cuối nội dung của hàm handleClick(), hãy gọi hàm displayImageDetections():
// Call the displayImageDetections() function.
displayImageDetections(detections, event.target);
  1. Trong nội dung của hàm displayImageDetections(), hãy thêm mã sau để hiển thị kết quả phát hiện vật thể:
// 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);
  }

Hàm này hiển thị các hộp giới hạn trên các vật thể được phát hiện trong hình ảnh. Hàm này sẽ xoá mọi điểm nổi bật trước đó, sau đó tạo và hiển thị các thẻ <p> để làm nổi bật từng vật thể được phát hiện.

Kiểm thử ứng dụng

Khi bạn thay đổi mã trong CodePen, ngăn xem trước sẽ tự động làm mới khi bạn lưu. Nếu tính năng tự động lưu được bật, thì ứng dụng của bạn có thể đã làm mới, nhưng bạn nên làm mới lại.

Để kiểm thử ứng dụng, hãy làm theo các bước sau:

  1. Trong ngăn xem trước, hãy nhấp vào từng hình ảnh để xem các dự đoán. Một hộp giới hạn cho biết tên của chú chó cùng với mức độ tin cậy của mô hình.
  2. Nếu không có hộp giới hạn, hãy mở Chrome DevTools rồi kiểm tra bảng điều khiển Console (Bảng điều khiển) để tìm lỗi hoặc xem lại các bước trước đó để đảm bảo bạn không bỏ sót điều gì.

Bản xem trước của ứng dụng web có các hộp giới hạn trên những chú chó được phát hiện trong hình ảnh

6. Chạy dự đoán trên video trực tiếp từ webcam

Phát hiện vật thể

  • Để phát hiện các vật thể trong video trực tiếp từ webcam, hãy chuyển đến hàm predictWebcam() rồi thêm mã sau vào nội dung của hàm:
// 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);

Tính năng phát hiện vật thể cho video sử dụng cùng một phương thức, bất kể bạn chạy suy luận trên dữ liệu truyền trực tuyến hay video hoàn chỉnh. Phương thức detectForVideo() tương tự như phương thức detect() dùng cho ảnh, nhưng phương thức này có thêm một tham số cho dấu thời gian được liên kết với khung hình hiện tại. Hàm này thực hiện phát hiện trực tiếp, vì vậy, bạn sẽ truyền thời gian hiện tại làm dấu thời gian.

Xử lý và hiển thị dự đoán

  • Để xử lý và hiển thị kết quả phát hiện, hãy chuyển đến hàm displayVideoDetections() rồi thêm mã sau vào nội dung của hàm:
//  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);
  }
}

Mã này sẽ xoá mọi điểm nổi bật trước đó, sau đó tạo và hiển thị các thẻ <p> để làm nổi bật từng đối tượng được phát hiện.

Kiểm thử ứng dụng

Để kiểm thử tính năng phát hiện vật thể trực tiếp, bạn nên có hình ảnh của một trong những chú chó mà mô hình được huấn luyện.

Để kiểm thử ứng dụng, hãy làm theo các bước sau:

  1. Tải một trong những bức ảnh chó xuống điện thoại.
  2. Trong ngăn xem trước, hãy nhấp vào Enable webcam (Bật webcam).
  3. Nếu trình duyệt của bạn hiển thị một hộp thoại yêu cầu bạn cấp quyền truy cập vào webcam, hãy cấp quyền.
  4. Giữ bức ảnh chú chó trên điện thoại trước webcam. Một hộp giới hạn cho biết tên của chú chó và mức độ tin cậy của mô hình.
  5. Nếu không có hộp giới hạn, hãy mở Chrome DevTools rồi kiểm tra bảng điều khiển Console (Bảng điều khiển) để tìm lỗi hoặc xem lại các bước trước đó để đảm bảo bạn không bỏ sót điều gì.

Một khung hình chữ nhật trên hình ảnh một chú chó được đưa lên trước webcam trực tiếp

7. Xin chúc mừng

Xin chúc mừng! Bạn đã tạo một ứng dụng web phát hiện các vật thể trong hình ảnh. Để tìm hiểu thêm, hãy xem phiên bản hoàn chỉnh của ứng dụng trên CodePen.

Tìm hiểu thêm