Guida al rilevamento dei punti di riferimento della mano per Android

L'attività MediaPipe Hand Landmarker consente di rilevare i punti di riferimento delle mani in un'immagine. Queste istruzioni mostrano come utilizzare il rilevamento di punti di riferimento della mano con le app per Android. L'esempio di codice descritto in queste istruzioni è disponibile su GitHub.

Per ulteriori informazioni sulle funzionalità, sui modelli e sulle opzioni di configurazione di questa attività, consulta la Panoramica.

Esempio di codice

Il codice di esempio di MediaPipe Tasks è una semplice implementazione di un'app di rilevamento di punti di riferimento della mano per Android. L'esempio utilizza la fotocamera di un dispositivo Android fisico per rilevare continuamente i punti di riferimento della mano e può anche utilizzare immagini e video dalla galleria del dispositivo per rilevare in modo statico i punti di riferimento della mano.

Puoi utilizzare l'app come punto di partenza per la tua app per Android o farvi riferimento quando modifichi un'app esistente. Il codice di esempio di Hand Landmarker è ospitato su GitHub.

Scarica il codice

Le istruzioni riportate di seguito mostrano come creare una copia locale del codice di esempio utilizzando lo strumento a riga di comando git.

Per scaricare il codice di esempio:

  1. Clona il repository git utilizzando il seguente comando:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. Se vuoi, configura l'istanza Git in modo da utilizzare il controllo sparse, in modo da avere solo i file per l'app di esempio Hand Landmarker:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/hand_landmarker/android
    

Dopo aver creato una versione locale del codice di esempio, puoi importare il progetto in Android Studio ed eseguire l'app. Per istruzioni, consulta la Guida alla configurazione per Android.

Componenti chiave

I seguenti file contengono il codice fondamentale per questa applicazione di esempio di rilevamento di landmark della mano:

  • HandLandmarkerHelper.kt: inizializza il rilevatore di landmark della mano e gestisce la selezione del modello e del delegato.
  • MainActivity.kt: implementa l'applicazione, inclusa la chiamata a HandLandmarkerHelper.

Configurazione

Questa sezione descrive i passaggi chiave per configurare l'ambiente di sviluppo e i progetti di codice specificamente per utilizzare Hand Landmarker. Per informazioni generali sulla configurazione dell'ambiente di sviluppo per l'utilizzo delle attività MediaPipe, inclusi i requisiti della versione della piattaforma, consulta la guida alla configurazione per Android.

Dipendenze

L'attività di rilevamento di punti di riferimento della mano utilizza la libreria com.google.mediapipe:tasks-vision. Aggiungi questa dipendenza al file build.gradle della tua app per Android:

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

Modello

L'attività MediaPipe Hand Landmarker richiede un bundle di modelli addestrati compatibile con questa attività. Per ulteriori informazioni sui modelli addestrati disponibili per il rilevamento di punti di riferimento della mano, consulta la sezione Modelli della panoramica dell'attività.

Seleziona e scarica il modello e memorizzalo nella directory del progetto:

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

Specifica il percorso del modello all'interno del parametro ModelAssetPath. Nel codice di esempio, il modello è definito nel file HandLandmarkerHelper.kt:

baseOptionBuilder.setModelAssetPath(MP_HAND_LANDMARKER_TASK)

Crea l'attività

L'attività MediaPipe Hand Landmarker utilizza la funzione createFromOptions() per configurare l'attività. La funzione createFromOptions() accetta valori per le opzioni di configurazione. Per ulteriori informazioni sulle opzioni di configurazione, consulta Opzioni di configurazione.

La funzionalità di rilevamento di elementi distintivi della mano supporta tre tipi di dati di input: immagini, file video e streaming dal vivo. Quando crei l'attività, devi specificare la modalità di esecuzione corrispondente al tipo di dati di input. Scegli la scheda corrispondente al tipo di dati di input per scoprire come creare l'attività ed eseguire l'inferenza.

Immagine

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)
    

Live streaming

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)
    

L'implementazione del codice di esempio di Hand Landmarker consente all'utente di passare da una modalità di elaborazione all'altra. L'approccio rende il codice di creazione delle attività più complicato e potrebbe non essere appropriato per il tuo caso d'uso. Puoi vedere questo codice nella funzione setupHandLandmarker() del file HandLandmarkerHelper.kt.

Opzioni di configurazione

Questa attività offre le seguenti opzioni di configurazione per le app per Android:

Nome opzione Descrizione Intervallo di valori Valore predefinito
runningMode Imposta la modalità di esecuzione dell'attività. Esistono tre modalità:

IMMAGINE: la modalità per l'inserimento di singole immagini.

VIDEO: la modalità per i fotogrammi decodificati di un video.

LIVE_STREAM: la modalità per un live streaming di dati di input, ad esempio da una videocamera. In questa modalità, resultListener deve essere chiamato per configurare un ascoltatore per ricevere i risultati in modo asincrono.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
numHands Il numero massimo di mani rilevate dal Rilevamento di punti di riferimento della mano. Any integer > 0 1
minHandDetectionConfidence Il punteggio di attendibilità minimo per il rilevamento della mano deve essere considerato positivo nel modello di rilevamento del palmo. 0.0 - 1.0 0.5
minHandPresenceConfidence Il punteggio di attendibilità minimo per il punteggio di presenza della mano nel modello di rilevamento dei punti di riferimento della mano. In modalità Video e Live streaming, se il punteggio di confidenza della presenza della mano del modello di landmark della mano è inferiore a questa soglia, il rilevamento dei landmark della mano attiva il modello di rilevamento del palmo. In caso contrario, un algoritmo di monitoraggio delle mani leggero determina la posizione delle mani per i rilevamenti successivi dei punti di riferimento. 0.0 - 1.0 0.5
minTrackingConfidence Il punteggio di attendibilità minimo per il rilevamento delle mani deve essere considerato positivo. Questa è la soglia IoU del riquadro di delimitazione tra le mani nel frame corrente e nell'ultimo frame. In modalità Video e Stream di Hand Landmarker, se il monitoraggio non va a buon fine, Hand Landmarker attiva il rilevamento della mano. In caso contrario, salta il rilevamento della mano. 0.0 - 1.0 0.5
resultListener Imposta l'ascoltatore dei risultati in modo da ricevere i risultati del rilevamento in modo asincrono quando il rilevamento di punti di riferimento della mano è in modalità live streaming. Applicabile solo quando la modalità di esecuzione è impostata su LIVE_STREAM N/D N/D
errorListener Imposta un listener di errore facoltativo. N/D N/D

Preparazione dei dati

La funzionalità di rilevamento di elementi distintivi della mano funziona con immagini, file video e video in live streaming. L'attività gestisce la preelaborazione dei dati di input, tra cui ridimensionamento, rotazione e normalizzazione dei valori.

Il seguente codice mostra come trasferire i dati per l'elaborazione. Questi esempi includono dettagli su come gestire i dati di immagini, file video e streaming di video live.

Immagine

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()
    

Live streaming

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()
    

Nel codice di esempio di Landmarker per le mani, la preparazione dei dati viene gestita nel file HandLandmarkerHelper.kt.

Esegui l'attività

A seconda del tipo di dati con cui stai lavorando, utilizza il metodo HandLandmarker.detect...() specifico per quel tipo di dati. Utilizza detect() per le singole immagini, detectForVideo() per i fotogrammi nei file video e detectAsync() per gli stream video. Quando esegui i rilevamenti su un spostamento video, assicurati di eseguirli in un thread separato per evitare di bloccare il thread dell'interfaccia utente.

I seguenti esempi di codice mostrano esempi semplici di come eseguire Hand Landmarker in queste diverse modalità di dati:

Immagine

val result = handLandmarker?.detect(mpImage)
    

Video

val timestampMs = i * inferenceIntervalMs

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

Live streaming

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

handLandmarker?.detectAsync(mpImage, frameTime)
    

Tieni presente quanto segue:

  • Quando esegui l'attività in modalità video o live streaming, devi anche fornire il timestamp del frame di input all'attività di rilevamento di punti di riferimento della mano.
  • Quando viene eseguita in modalità immagine o video, l'attività di rilevamento di landmark della mano blocca il thread corrente fino al termine dell'elaborazione dell'immagine o del frame di input. Per evitare di bloccare l'interfaccia utente, esegui l'elaborazione in un THREAD in background.
  • Quando viene eseguita in modalità live streaming, l'attività di rilevamento di punti di riferimento della mano non blocca il thread corrente, ma restituisce immediatamente. Evocherà il suo ascoltatore dei risultati con il risultato del rilevamento ogni volta che ha terminato l'elaborazione di un frame di input. Se la funzione di rilevamento viene chiamata quando l'attività di rilevamento dei punti di riferimento della mano è impegnata a elaborare un altro frame, l'attività ignorerà il nuovo frame di input.

Nel codice di esempio di identificazione di punti di riferimento della mano, le funzioni detect, detectForVideo e detectAsync sono definite nel file HandLandmarkerHelper.kt.

Gestire e visualizzare i risultati

Il rilevamento dei punti di riferimento della mano genera un oggetto di risultato del rilevamento dei punti di riferimento della mano per ogni esecuzione del rilevamento. L'oggetto risultato contiene i landmark delle mani nelle coordinate dell'immagine, i landmark delle mani nelle coordinate del mondo e l'uso della mano(sinistra/destra) delle mani rilevate.

Di seguito è riportato un esempio dei dati di output di questa attività:

L'output HandLandmarkerResult contiene tre componenti. Ogni componente è un array, in cui ogni elemento contiene i seguenti risultati per una singola mano rilevata:

  • Mano dominante

    La dominanza indica se le mani rilevate sono la mano sinistra o la mano destra.

  • Punti di riferimento

    Esistono 21 punti di riferimento della mano, ciascuno composto da coordinate x, y e z. Le coordinate x e y sono normalizzate in [0,0, 1,0] in base alla larghezza e all'altezza dell'immagine, rispettivamente. La coordinata z rappresenta la profondità del punto di riferimento, con la profondità al polso come origine. Più piccolo è il valore, più il punto di riferimento è vicino alla fotocamera. L'intensità di z utilizza approssimativamente la stessa scala di x.

  • Monumenti del mondo

    I 21 punti di riferimento della mano sono presentati anche in coordinate mondiali. Ogni punto di riferimento è composto da x, y e z, che rappresentano coordinate 3D reali in metri con l'origine nel centro geometrico della mano.

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)

L'immagine seguente mostra una visualizzazione dell'output dell'attività:

Una mano con il pollice in su con la struttura scheletrica della mano mappata

Il codice di esempio di Hand Landmarker mostra come visualizzare i risultati restituiti dall'attività. Per ulteriori dettagli, consulta la classe OverlayView.