Hướng dẫn phát hiện điểm mốc trên tay cho Android

Nhiệm vụ MediaPipe Hand chunger cho phép bạn phát hiện các điểm mốc của bàn tay trong một hình ảnh. Các hướng dẫn này chỉ cho bạn cách sử dụng Cột mốc cầm tay với các ứng dụng Android. Mã mẫu được mô tả trong những hướng dẫn này hiện có trên GitHub.

Để biết thêm thông tin về các tính năng, mô hình và lựa chọn cấu hình của nhiệm vụ này, hãy xem phần Tổng quan.

Ví dụ về mã

Mã ví dụ về MediaPipe Tasks là một cách triển khai đơn giản của ứng dụng Hand Returner dành cho Android. Ví dụ này sử dụng máy ảnh trên một thiết bị Android thực để liên tục phát hiện các điểm mốc trên bàn tay, đồng thời cũng có thể sử dụng hình ảnh và video từ thư viện thiết bị để phát hiện tĩnh các điểm mốc trên tay.

Bạn có thể dùng ứng dụng này làm điểm xuất phát cho ứng dụng Android của riêng mình hoặc tham chiếu đến ứng dụng này khi sửa đổi một ứng dụng hiện có. Mã ví dụ về Hand RCSer được lưu trữ trên GitHub.

Tải mã xuống

Hướng dẫn sau đây chỉ cho bạn cách tạo bản sao cục bộ của mã ví dụ bằng công cụ dòng lệnh git.

Cách tải mã ví dụ xuống:

  1. Sao chép kho lưu trữ git bằng lệnh sau:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. Bạn có thể định cấu hình thực thể git để sử dụng quy trình thanh toán thưa thớt (không bắt buộc), vì vậy, bạn chỉ có các tệp cho ứng dụng ví dụ về HandMốc:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/hand_landmarker/android
    

Sau khi tạo phiên bản cục bộ của mã ví dụ, bạn có thể nhập dự án vào Android Studio và chạy ứng dụng. Để được hướng dẫn, hãy xem Hướng dẫn thiết lập dành cho Android.

Thành phần chính

Các tệp sau đây chứa mã quan trọng cho ứng dụng mẫu phát hiện điểm mốc kim loại này:

  • HandLandmarkerHelper.kt – Khởi chạy trình phát hiện điểm mốc trên kim đồng hồ, đồng thời xử lý lựa chọn mô hình và uỷ quyền.
  • MainActivity.kt – Triển khai ứng dụng, bao gồm cả việc gọi HandLandmarkerHelper.

Thiết lập

Phần này mô tả các bước chính để thiết lập môi trường phát triển và lập trình cho các dự án dành riêng cho việc sử dụng Handmarker. Để biết thông tin chung về cách thiết lập môi trường phát triển nhằm sử dụng các tác vụ của MediaPipe, bao gồm cả yêu cầu về phiên bản nền tảng, hãy xem Hướng dẫn thiết lập dành cho Android.

Phần phụ thuộc

Nhiệm vụ Vẽ tay bằng dấu ấn sử dụng thư viện com.google.mediapipe:tasks-vision. Thêm phần phụ thuộc này vào tệp build.gradle của ứng dụng Android:

dependencies {
    implementation 'com.google.mediapipe:tasks-vision:latest.release'
}

Mẫu

Tác vụ MediaPipe Hand RCSer cần có một gói mô hình đã qua huấn luyện và tương thích với tác vụ này. Để biết thêm thông tin về các mô hình đã huấn luyện hiện có cho Cột mốc cầm tay, hãy xem nội dung tổng quan về tác vụ phần Mô hình.

Chọn và tải mô hình xuống rồi lưu trữ trong thư mục dự án của bạn:

<dev-project-root>/src/main/assets

Chỉ định đường dẫn của mô hình trong tham số ModelAssetPath. Trong mã ví dụ, mô hình được xác định trong tệp HandLandmarkerHelper.kt:

baseOptionBuilder.setModelAssetPath(MP_HAND_LANDMARKER_TASK)

Tạo việc cần làm

Tác vụ MediaPipe Hand RCSer sử dụng hàm createFromOptions() để thiết lập tác vụ đó. Hàm createFromOptions() chấp nhận các giá trị cho các tuỳ chọn cấu hình. Để biết thêm thông tin về các lựa chọn cấu hình, hãy xem phần Lựa chọn cấu hình.

Tay mốc hỗ trợ 3 loại dữ liệu đầu vào: hình ảnh tĩnh, tệp video và phát trực tiếp. Bạn cần chỉ định chế độ chạy tương ứng với loại dữ liệu đầu vào của mình khi tạo tác vụ. Chọn thẻ tương ứng với loại dữ liệu đầu vào của bạn để xem cách tạo tác vụ và chạy dự đoán.

Bài đăng có hình ảnh

val baseOptionsBuilder = BaseOptions.builder().setModelAssetPath(MP_HAND_LANDMARKER_TASK)
val baseOptions = baseOptionBuilder.build()

val optionsBuilder =
    HandLandmarker.HandLandmarkerOptions.builder()
        .setBaseOptions(baseOptions)
        .setMinHandDetectionConfidence(minHandDetectionConfidence)
        .setMinTrackingConfidence(minHandTrackingConfidence)
        .setMinHandPresenceConfidence(minHandPresenceConfidence)
        .setNumHands(maxNumHands)
        .setRunningMode(RunningMode.IMAGE)

val options = optionsBuilder.build()

handLandmarker =
    HandLandmarker.createFromOptions(context, options)
    

Video

val baseOptionsBuilder = BaseOptions.builder().setModelAssetPath(MP_HAND_LANDMARKER_TASK)
val baseOptions = baseOptionBuilder.build()

val optionsBuilder =
    HandLandmarker.HandLandmarkerOptions.builder()
        .setBaseOptions(baseOptions)
        .setMinHandDetectionConfidence(minHandDetectionConfidence)
        .setMinTrackingConfidence(minHandTrackingConfidence)
        .setMinHandPresenceConfidence(minHandPresenceConfidence)
        .setNumHands(maxNumHands)
        .setRunningMode(RunningMode.VIDEO)

val options = optionsBuilder.build()

handLandmarker =
    HandLandmarker.createFromOptions(context, options)
    

Sự kiện trực tiếp

val baseOptionsBuilder = BaseOptions.builder().setModelAssetPath(MP_HAND_LANDMARKER_TASK)
val baseOptions = baseOptionBuilder.build()

val optionsBuilder =
    HandLandmarker.HandLandmarkerOptions.builder()
        .setBaseOptions(baseOptions)
        .setMinHandDetectionConfidence(minHandDetectionConfidence)
        .setMinTrackingConfidence(minHandTrackingConfidence)
        .setMinHandPresenceConfidence(minHandPresenceConfidence)
        .setNumHands(maxNumHands)
        .setResultListener(this::returnLivestreamResult)
        .setErrorListener(this::returnLivestreamError)
        .setRunningMode(RunningMode.VIDEO)

val options = optionsBuilder.build()

handLandmarker =
    HandLandmarker.createFromOptions(context, options)
    

Ví dụ về cách triển khai đoạn mã có vai trò Người đánh dấu tay cho phép người dùng chuyển đổi giữa các chế độ xử lý. Phương pháp này khiến mã tạo tác vụ trở nên phức tạp hơn và có thể không phù hợp với trường hợp sử dụng của bạn. Bạn có thể thấy mã này trong hàm setupHandLandmarker() ở tệp HandLandmarkerHelper.kt.

Các lựa chọn về cấu hình

Tác vụ này có các lựa chọn cấu hình sau đây cho ứng dụng Android:

Tên lựa chọn Nội dung mô tả Khoảng giá trị Giá trị mặc định
runningMode Đặt chế độ chạy cho tác vụ. Có 3 chế độ:

IMAGE: Chế độ nhập một hình ảnh.

VIDEO: Chế độ khung hình đã giải mã của video.

LIVE_STREAM: Chế độ phát trực tiếp dữ liệu đầu vào, chẳng hạn như từ máy quay. Ở chế độ này, bạn phải gọi resultsListener để thiết lập trình nghe nhằm nhận kết quả không đồng bộ.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
numHands Số lượng tay tối đa mà trình phát hiện mốc Tay phát hiện được. Any integer > 0 1
minHandDetectionConfidence Điểm số tin cậy tối thiểu để tính năng phát hiện tay được coi là thành công trong mô hình phát hiện lòng bàn tay. 0.0 - 1.0 0.5
minHandPresenceConfidence Điểm số tin cậy tối thiểu cho điểm số về sự hiện diện của tay trong mô hình phát hiện điểm mốc kim loại. Ở chế độ Video và chế độ Phát trực tiếp, nếu điểm số tin cậy của sự hiện diện kim đồng hồ từ mô hình điểm mốc kim loại thấp hơn ngưỡng này, thì Tay mốc sẽ kích hoạt mô hình phát hiện lòng bàn tay. Nếu không, thuật toán theo dõi kim nhẹ sẽ xác định vị trí của(các) kim để phát hiện điểm mốc tiếp theo. 0.0 - 1.0 0.5
minTrackingConfidence Điểm số tin cậy tối thiểu để theo dõi tay được coi là thành công. Đây là ngưỡng IoU hộp giới hạn giữa các kim trong khung hiện tại và khung cuối cùng. Ở chế độ Video và chế độ Phát trực tiếp của Cổng đánh dấu tay, nếu theo dõi không thành công, Tay Cột mốc sẽ kích hoạt tính năng phát hiện tay. Nếu không, tính năng này sẽ bỏ qua tính năng phát hiện tay. 0.0 - 1.0 0.5
resultListener Thiết lập trình nghe kết quả để nhận kết quả phát hiện một cách không đồng bộ khi điểm mốc kim đồng hồ đang ở chế độ phát trực tiếp. Chỉ áp dụng khi chế độ chạy được đặt thành LIVE_STREAM Không áp dụng Không áp dụng
errorListener Thiết lập một trình nghe lỗi (không bắt buộc). Không áp dụng Không áp dụng

Chuẩn bị dữ liệu

Tay Cột khuôn mặt hoạt động với hình ảnh, tệp video và video phát trực tiếp. Tác vụ này sẽ xử lý trước bước xử lý dữ liệu đầu vào, bao gồm cả việc đổi kích thước, xoay và chuẩn hoá giá trị.

Mã sau đây minh hoạ cách chuyển giao dữ liệu cho việc xử lý. Các mẫu này bao gồm thông tin chi tiết về cách xử lý dữ liệu từ hình ảnh, tệp video và luồng video trực tiếp.

Bài đăng có hình ảnh

import com.google.mediapipe.framework.image.BitmapImageBuilder
import com.google.mediapipe.framework.image.MPImage

// Convert the input Bitmap object to an MPImage object to run inference
val mpImage = BitmapImageBuilder(image).build()
    

Video

import com.google.mediapipe.framework.image.BitmapImageBuilder
import com.google.mediapipe.framework.image.MPImage

val argb8888Frame =
    if (frame.config == Bitmap.Config.ARGB_8888) frame
    else frame.copy(Bitmap.Config.ARGB_8888, false)

// Convert the input Bitmap object to an MPImage object to run inference
val mpImage = BitmapImageBuilder(argb8888Frame).build()
    

Sự kiện trực tiếp

import com.google.mediapipe.framework.image.BitmapImageBuilder
import com.google.mediapipe.framework.image.MPImage

// Convert the input Bitmap object to an MPImage object to run inference
val mpImage = BitmapImageBuilder(rotatedBitmap).build()
    

Trong mã ví dụ về Mặt bằng tay, việc chuẩn bị dữ liệu được xử lý trong tệp HandLandmarkerHelper.kt.

Chạy tác vụ

Tuỳ thuộc vào loại dữ liệu bạn đang xử lý, hãy sử dụng phương thức HandLandmarker.detect...() dành riêng cho loại dữ liệu đó. Sử dụng detect() cho từng hình ảnh, detectForVideo() cho khung hình trong tệp video và detectAsync() cho luồng video. Khi bạn đang thực hiện phát hiện trên một luồng video, hãy đảm bảo bạn chạy các quy trình phát hiện trên một luồng riêng để tránh chặn luồng giao diện người dùng.

Các mã mẫu sau đây cho thấy các ví dụ đơn giản về cách chạy Tay Cột mốc ở nhiều chế độ dữ liệu sau đây:

Bài đăng có hình ảnh

val result = handLandmarker?.detect(mpImage)
    

Video

val timestampMs = i * inferenceIntervalMs

handLandmarker?.detectForVideo(mpImage, timestampMs)
    ?.let { detectionResult ->
        resultList.add(detectionResult)
    }
    

Sự kiện trực tiếp

val mpImage = BitmapImageBuilder(rotatedBitmap).build()
val frameTime = SystemClock.uptimeMillis()

handLandmarker?.detectAsync(mpImage, frameTime)
    

Xin lưu ý những điều sau:

  • Khi chạy ở chế độ video hoặc chế độ phát trực tiếp, bạn cũng phải cung cấp dấu thời gian của khung nhập dữ liệu cho tác vụ có Cột mốc trong tay.
  • Khi chạy ở chế độ hình ảnh hoặc video, tác vụ Cột số bằng tay sẽ chặn luồng hiện tại cho đến khi xử lý xong hình ảnh hoặc khung đầu vào. Để tránh chặn giao diện người dùng, hãy thực thi quá trình xử lý trong luồng ở chế độ nền.
  • Khi chạy ở chế độ phát trực tiếp, tác vụ trên Bàn tay mốc không chặn luồng hiện tại mà sẽ trả về ngay lập tức. Hàm này sẽ gọi trình nghe kết quả cùng với kết quả phát hiện mỗi khi xử lý xong một khung đầu vào. Nếu chức năng phát hiện được gọi khi tác vụ Người đánh dấu tay đang bận xử lý một khung khác, thì tác vụ đó sẽ bỏ qua khung đầu vào mới.

Trong mã ví dụ về Bàn tay, các hàm detect, detectForVideodetectAsync được xác định trong tệp HandLandmarkerHelper.kt.

Xử lý và hiển thị kết quả

Tay mốc có thể tạo một đối tượng kết quả của điểm mốc làm thủ công cho mỗi lần chạy phát hiện. Đối tượng kết quả chứa các mốc kim trong toạ độ hình ảnh, điểm mốc kim trên toạ độ thế giới và tỷ lệ thuận tay(tay trái/phải) của tay được phát hiện.

Sau đây là ví dụ về dữ liệu đầu ra của nhiệm vụ này:

Đầu ra HandLandmarkerResult chứa 3 thành phần. Mỗi thành phần là một mảng, trong đó mỗi phần tử chứa các kết quả sau đây cho một kim được phát hiện:

  • Tay thuận

    Tay thuận biểu thị việc tay được phát hiện là tay trái hay tay phải.

  • Địa danh

    Có 21 điểm mốc kim, mỗi mốc bao gồm các toạ độ x, yz. Các toạ độ xy được chuẩn hoá lần lượt thành [0,0, 1,0] theo chiều rộng và chiều cao của hình ảnh. Toạ độ z thể hiện chiều sâu của điểm mốc, với chiều sâu ở cổ tay là gốc. Giá trị càng nhỏ, điểm đánh dấu càng gần với camera. Độ lớn của z sử dụng tỷ lệ gần tương tự như x.

  • Điểm mốc Thế giới

    Các mốc 21 kim cũng được trình bày theo toạ độ trên thế giới. Mỗi điểm mốc bao gồm x, yz, biểu thị các toạ độ 3D thực tế tính bằng mét với gốc toạ độ ở tâm hình học của kim đồng hồ.

HandLandmarkerResult:
  Handedness:
    Categories #0:
      index        : 0
      score        : 0.98396
      categoryName : Left
  Landmarks:
    Landmark #0:
      x            : 0.638852
      y            : 0.671197
      z            : -3.41E-7
    Landmark #1:
      x            : 0.634599
      y            : 0.536441
      z            : -0.06984
    ... (21 landmarks for a hand)
  WorldLandmarks:
    Landmark #0:
      x            : 0.067485
      y            : 0.031084
      z            : 0.055223
    Landmark #1:
      x            : 0.063209
      y            : -0.00382
      z            : 0.020920
    ... (21 world landmarks for a hand)

Hình ảnh sau đây minh hoạ kết quả của tác vụ:

Mã ví dụ về Bàn tay đánh dấu minh hoạ cách hiển thị kết quả được trả về từ tác vụ, xem lớp OverlayView để biết thêm thông tin chi tiết.