A tarefa "Mão de referência do MediaPipe" permite detectar os pontos de referência dos ponteiros em uma imagem. Estas instruções mostram como usar o Hand Landmarker com apps para iOS. O exemplo de código descrito nestas instruções está disponível no GitHub.
Para mais informações sobre os recursos, modelos e opções de configuração dessa tarefa, consulte a Visão geral.
Exemplo de código
O código de exemplo do MediaPipe Tasks é uma implementação básica de um app de Hand Landmarker para iOS. O exemplo usa a câmera em um dispositivo iOS físico para detectar pontos de referência da mão em um fluxo de vídeo contínuo. O app também pode detectar pontos de referência da mão em imagens e vídeos da galeria do dispositivo.
Você pode usar o app como ponto de partida para seu próprio app iOS ou se referir a ele ao modificar um app existente. O código de exemplo do Hand Landmarker está hospedado no GitHub.
Fazer o download do código
As instruções a seguir mostram como criar uma cópia local do código de exemplo usando a ferramenta de linha de comando git.
Para fazer o download do código de exemplo:
Clone o repositório do Git usando o seguinte comando:
git clone https://github.com/google-ai-edge/mediapipe-samples
Opcionalmente, configure sua instância do Git para usar o checkout esparso, para que você tenha apenas os arquivos do app de exemplo Hand Landmarker:
cd mediapipe git sparse-checkout init --cone git sparse-checkout set examples/hand_landmarker/ios/
Depois de criar uma versão local do código de exemplo, é possível instalar a biblioteca de tarefas do MediaPipe, abrir o projeto usando o Xcode e executar o app. Para instruções, consulte o Guia de configuração para iOS.
Principais componentes
Os arquivos abaixo contêm o código crucial para o exemplo de aplicativo Hand Landmarker:
- HandLandmarkerService.swift: inicializa o Hand Landmarker, processa a seleção de modelos e executa a inferência nos dados de entrada.
- CameraViewController.swift: implementa a interface do modo de entrada de feed de câmera ao vivo e visualiza os resultados.
- MediaLibraryViewController.swift: implementa a interface para o modo de entrada de imagem estática e arquivo de vídeo e visualiza os resultados.
Configuração
Esta seção descreve as principais etapas para configurar seu ambiente de desenvolvimento e projetos de código para usar o Hand Landmarker. Para informações gerais sobre como configurar seu ambiente de desenvolvimento para usar tarefas do MediaPipe, incluindo os requisitos de versão da plataforma, consulte o Guia de configuração para iOS.
Dependências
O ponteiro usa a biblioteca MediaPipeTasksVision
, que precisa ser instalada
com o CocoaPods. A biblioteca é compatível com apps Swift e Objective-C
e não requer nenhuma configuração específica da linguagem.
Para instruções sobre como instalar o CocoaPods no macOS, consulte o guia de instalação do CocoaPods.
Para instruções sobre como criar um Podfile
com os pods necessários para seu
app, consulte Como usar
CocoaPods.
Adicione o pod MediaPipeTasksVision no Podfile
usando o seguinte código:
target 'MyHandLandmarkerApp' do
use_frameworks!
pod 'MediaPipeTasksVision'
end
Se o app incluir destinos de teste de unidade, consulte o guia de configuração para
iOS para mais informações sobre como configurar
o Podfile
.
Modelo
A tarefa de detecção de pontos de referência da mão do MediaPipe exige um modelo treinado compatível com essa tarefa. Para mais informações sobre os modelos treinados disponíveis para o Ponto de referência de mão, consulte a visão geral da tarefa Seção de Modelos.
Selecione e faça o download de um modelo e adicione-o ao diretório do projeto usando o Xcode. Para instruções sobre como adicionar arquivos ao projeto Xcode, consulte Como gerenciar arquivos e pastas no projeto do Xcode.
Use a propriedade BaseOptions.modelAssetPath
para especificar o caminho para o modelo
no app bundle. Para conferir um exemplo de código, consulte a próxima seção.
Criar a tarefa
É possível criar a tarefa "Mão de referência" chamando um de seus inicializadores. O
inicializador HandLandmarker(options:)
aceita valores para as opções de
configuração.
Se você não precisa de um ponto de referência de mão inicializado com opções de configuração
personalizadas, use o inicializador HandLandmarker(modelPath:)
para criar um
marcador de mão com as opções padrão. Para mais informações sobre as opções de configuração, consulte Visão geral da configuração.
A tarefa "Ponto de referência manual" é compatível com três tipos de dados de entrada: imagens estáticas, arquivos de vídeo
e streams de vídeo ao vivo. Por padrão, HandLandmarker(modelPath:)
inicializa uma
tarefa para imagens estáticas. Se você quiser que sua tarefa seja inicializada para processar arquivos
de vídeo ou streams de vídeo ao vivo, use HandLandmarker(options:)
para especificar o vídeo
ou o modo de execução da transmissão ao vivo. O modo de transmissão ao vivo também exige a opção de configuração
adicional handLandmarkerLiveStreamDelegate
, que permite que o
Hand Landmarker transmita resultados para o delegado de forma assíncrona.
Escolha a guia correspondente ao modo de execução para saber como criar a tarefa e executar a inferência.
Swift
Imagem
import MediaPipeTasksVision let modelPath = Bundle.main.path(forResource: "hand_landmarker", ofType: "task") let options = HandLandmarkerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .image options.minHandDetectionConfidence = minHandDetectionConfidence options.minHandPresenceConfidence = minHandPresenceConfidence options.minTrackingConfidence = minHandTrackingConfidence options.numHands = numHands let handLandmarker = try HandLandmarker(options: options)
Vídeo
import MediaPipeTasksVision let modelPath = Bundle.main.path(forResource: "hand_landmarker", ofType: "task") let options = HandLandmarkerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .video options.minHandDetectionConfidence = minHandDetectionConfidence options.minHandPresenceConfidence = minHandPresenceConfidence options.minTrackingConfidence = minHandTrackingConfidence options.numHands = numHands let handLandmarker = try HandLandmarker(options: options)
Transmissão ao vivo
import MediaPipeTasksVision // Class that conforms to the `HandLandmarkerLiveStreamDelegate` protocol and // implements the method that the hand landmarker calls once it finishes // performing landmarks detection in each input frame. class HandLandmarkerResultProcessor: NSObject, HandLandmarkerLiveStreamDelegate { func handLandmarker( _ handLandmarker: HandLandmarker, didFinishDetection result: HandLandmarkerResult?, timestampInMilliseconds: Int, error: Error?) { // Process the hand landmarker result or errors here. } } let modelPath = Bundle.main.path( forResource: "hand_landmarker", ofType: "task") let options = HandLandmarkerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .liveStream options.minHandDetectionConfidence = minHandDetectionConfidence options.minHandPresenceConfidence = minHandPresenceConfidence options.minTrackingConfidence = minHandTrackingConfidence options.numHands = numHands // Assign an object of the class to the `handLandmarkerLiveStreamDelegate` // property. let processor = HandLandmarkerResultProcessor() options.handLandmarkerLiveStreamDelegate = processor let handLandmarker = try HandLandmarker(options: options)
Objective-C
Imagem
@import MediaPipeTasksVision; NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"hand_landmarker" ofType:@"task"]; MPPHandLandmarkerOptions *options = [[MPPHandLandmarkerOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeImage; options.minHandDetectionConfidence = minHandDetectionConfidence; options.minHandPresenceConfidence = minHandPresenceConfidence; options.minTrackingConfidence = minHandTrackingConfidence; options.numHands = numHands; MPPHandLandmarker *handLandmarker = [[MPPHandLandmarker alloc] initWithOptions:options error:nil];
Vídeo
@import MediaPipeTasksVision; NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"hand_landmarker" ofType:@"task"]; MPPHandLandmarkerOptions *options = [[MPPHandLandmarkerOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeVideo; options.minHandDetectionConfidence = minHandDetectionConfidence; options.minHandPresenceConfidence = minHandPresenceConfidence; options.minTrackingConfidence = minHandTrackingConfidence; options.numHands = numHands; MPPHandLandmarker *handLandmarker = [[MPPHandLandmarker alloc] initWithOptions:options error:nil];
Transmissão ao vivo
@import MediaPipeTasksVision; // Class that conforms to the `MPPHandLandmarkerLiveStreamDelegate` protocol // and implements the method that the hand landmarker calls once it finishes // performing landmarks detection in each input frame. @interface APPHandLandmarkerResultProcessor : NSObject@end @implementation APPHandLandmarkerResultProcessor - (void)handLandmarker:(MPPHandLandmarker *)handLandmarker didFinishDetectionWithResult:(MPPHandLandmarkerResult *)handLandmarkerResult timestampInMilliseconds:(NSInteger)timestampInMilliseconds error:(NSError *)error { // Process the hand landmarker result or errors here. } @end NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"hand_landmarker" ofType:@"task"]; MPPHandLandmarkerOptions *options = [[MPPHandLandmarkerOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeLiveStream; options.minHandDetectionConfidence = minHandDetectionConfidence; options.minHandPresenceConfidence = minHandPresenceConfidence; options.minTrackingConfidence = minHandTrackingConfidence; options.numHands = numHands; // Assign an object of the class to the `handLandmarkerLiveStreamDelegate` // property. APPHandLandmarkerResultProcessor *processor = [APPHandLandmarkerResultProcessor new]; options.handLandmarkerLiveStreamDelegate = processor; MPPHandLandmarker *handLandmarker = [[MPPHandLandmarker alloc] initWithOptions:options error:nil];
Opções de configuração
Esta tarefa tem as seguintes opções de configuração para apps iOS:
Nome da opção | Descrição | Intervalo de valor | Valor padrão |
---|---|---|---|
running_mode |
Define o modo de execução da tarefa. Há três
modos: IMAGE: o modo para entradas de imagem única. VÍDEO: o modo para quadros decodificados de um vídeo. LIVE_STREAM: o modo de uma transmissão ao vivo de dados de entrada, como de uma câmera. Nesse modo, o resultListener precisa ser chamado para configurar um listener para receber resultados de forma assíncrona. Nesse modo, handLandmarkerLiveStreamDelegate precisa ser definido como uma instância de uma classe que implemente o HandLandmarkerLiveStreamDelegate para receber os resultados da detecção de pontos de referência da mão de forma assíncrona.
|
{RunningMode.image, RunningMode.video, RunningMode.liveStream } |
RunningMode.image |
numHands |
O número máximo de mãos detectadas pelo detector de pontos de referência da mão. | Any integer > 0 |
1 |
minHandDetectionConfidence |
A pontuação de confiança mínima para que a detecção de mão seja considerada bem-sucedida no modelo de detecção de palma. | 0.0 - 1.0 |
0.5 |
minHandPresenceConfidence |
A pontuação de confiança mínima para a pontuação de presença da mão no modelo de detecção de pontos de referência da mão. No modo de vídeo e de transmissão ao vivo, se a pontuação de confiança de presença de mão do modelo de ponto de referência da mão estiver abaixo desse limite, o Hand Landmarker aciona o modelo de detecção de palma. Caso contrário, um algoritmo de rastreamento de mão leve determina a localização da mão para detecções de marco subsequentes. | 0.0 - 1.0 |
0.5 |
minTrackingConfidence |
A pontuação de confiança mínima para que o rastreamento de mãos seja considerado bem-sucedido. Esse é o limite de IoU da caixa delimitadora entre as mãos no frame atual e no último. No modo de vídeo e no modo de transmissão do Hand Landmarker, se o rastreamento falhar, o Hand Landmarker aciona a detecção da mão. Caso contrário, a detecção de mãos é ignorada. | 0.0 - 1.0 |
0.5 |
result_listener |
Define o listener de resultado para receber os resultados de detecção
de forma assíncrona quando o marcador de mão está no modo de transmissão ao vivo.
Aplicável apenas quando o modo de execução está definido como LIVE_STREAM |
N/A | N/A |
Quando o modo de execução está definido como transmissão ao vivo, o Hand Landmarker exige a
opção de configuração handLandmarkerLiveStreamDelegate
adicional, que
permite que o Hand Landmarker forneça resultados de detecção de pontos de referência da mão
de forma assíncrona. O delegado precisa implementar o
método handLandmarker(_:didFinishDetection:timestampInMilliseconds:error:)
,
que o marcador de ponto de referência chama depois de processar os resultados da detecção de pontos de referência
da mão para cada frame.
Nome da opção | Descrição | Intervalo de valor | Valor padrão |
---|---|---|---|
handLandmarkerLiveStreamDelegate |
Permite que o Hand Landmarker receba os resultados
da detecção de ponto de referência de forma assíncrona no modo de transmissão ao vivo. A classe
que tem a instância definida para essa propriedade precisa implementar o
método
handLandmarker(_:didFinishDetection:timestampInMilliseconds:error:) . |
Não relevante | Não definido |
Preparar dados
É necessário converter a imagem de entrada ou o frame em um objeto MPImage
antes de
transmiti-lo ao Hand Landmarker. MPImage
oferece suporte a diferentes tipos de formatos de imagem
do iOS e pode usá-los em qualquer modo em execução para inferência. Para mais
informações sobre MPImage
, consulte a
API MPImage.
Escolha um formato de imagem do iOS com base no seu caso de uso e no modo de execução
exigido pelo aplicativo.MPImage
aceita os formatos de imagem UIImage
, CVPixelBuffer
e
CMSampleBuffer
do iOS.
UIImage
O formato UIImage
é adequado para os seguintes modos de execução:
Imagens: as imagens de um pacote de apps, galeria de usuários ou sistema de arquivos formatadas como
UIImage
podem ser convertidas em um objetoMPImage
.Vídeos: use AVAssetImageGenerator para extrair frames de vídeo no formato CGImage e converta-os em imagens
UIImage
.
Swift
// Load an image on the user's device as an iOS `UIImage` object. // Convert the `UIImage` object to a MediaPipe's Image object having the default // orientation `UIImage.Orientation.up`. let image = try MPImage(uiImage: image)
Objective-C
// Load an image on the user's device as an iOS `UIImage` object. // Convert the `UIImage` object to a MediaPipe's Image object having the default // orientation `UIImageOrientationUp`. MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
O exemplo inicializa um MPImage
com a orientação
padrão UIImage.Orientation.Up. É possível inicializar uma MPImage
com qualquer um dos valores
UIImage.Orientation
compatíveis. O Hand Landmarker não oferece suporte a orientações espelhadas, como .upMirrored
, .downMirrored
, .leftMirrored
e .rightMirrored
.
Para mais informações sobre UIImage
, consulte a documentação para desenvolvedores da Apple
de UIImage (em inglês).
CVPixelBuffer
O formato CVPixelBuffer
é adequado para aplicativos que geram frames
e usam o framework CoreImage
do iOS para processamento.
O formato CVPixelBuffer
é adequado para os seguintes modos de execução:
Imagens: apps que geram imagens
CVPixelBuffer
após algum processamento usando o frameworkCoreImage
do iOS podem ser enviados para o Hand Landmarker no modo de execução de imagem.Vídeos: os frames de vídeo podem ser convertidos para o formato
CVPixelBuffer
para processamento e, em seguida, enviados para o Hand Landmarker no modo de vídeo.Transmissão ao vivo: os apps que usam uma câmera do iOS para gerar frames podem ser convertidos no formato
CVPixelBuffer
para processamento antes de serem enviados para o Hand Landmarker no modo de transmissão ao vivo.
Swift
// Obtain a CVPixelBuffer. // Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the default // orientation `UIImage.Orientation.up`. let image = try MPImage(pixelBuffer: pixelBuffer)
Objective-C
// Obtain a CVPixelBuffer. // Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the // default orientation `UIImageOrientationUp`. MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
Para mais informações sobre CVPixelBuffer
, consulte a Documentação do desenvolvedor
da Apple CVPixelBuffer (em inglês).
CMSampleBuffer
O formato CMSampleBuffer
armazena amostras de mídia de um tipo uniforme e é
adequado para o modo de execução de transmissões ao vivo. Os frames ao vivo das câmeras do iOS são
enviados de forma assíncrona no formato CMSampleBuffer
pelo
AVCaptureVideoDataOutput do iOS.
Swift
// Obtain a CMSampleBuffer. // Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the default // orientation `UIImage.Orientation.up`. let image = try MPImage(sampleBuffer: sampleBuffer)
Objective-C
// Obtain a `CMSampleBuffer`. // Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the // default orientation `UIImageOrientationUp`. MPImage *image = [[MPPImage alloc] initWithSampleBuffer:sampleBuffer error:nil];
Para mais informações sobre CMSampleBuffer
, consulte a documentação
para desenvolvedores da Apple
CMSampleBuffer (em inglês).
Executar a tarefa
Para executar o ponto de referência da mão, use o método detect()
específico para o modo de
execução atribuído:
- Imagem estática:
detect(image:)
- Vídeo:
detect(videoFrame:timestampInMilliseconds:)
- Transmissão ao vivo:
detectAsync(image:timestampInMilliseconds:)
Swift
Imagem
let result = try handLandmarker.detect(image: image)
Vídeo
let result = try handLandmarker.detect( videoFrame: image, timestampInMilliseconds: timestamp)
Transmissão ao vivo
try handLandmarker.detectAsync( image: image, timestampInMilliseconds: timestamp)
Objective-C
Imagem
MPPHandLandmarkerResult *result = [handLandmarker detectInImage:image error:nil];
Vídeo
MPPHandLandmarkerResult *result = [handLandmarker detectInVideoFrame:image timestampInMilliseconds:timestamp error:nil];
Transmissão ao vivo
BOOL success = [handLandmarker detectAsyncInImage:image timestampInMilliseconds:timestamp error:nil];
O exemplo de código do Hand Landmarker mostra as implementações de cada um desses modos com mais detalhes. O exemplo de código permite que o usuário alterne entre modos de processamento, o que pode não ser necessário para seu caso de uso.
Observe o seguinte:
Ao executar no modo de vídeo ou de transmissão ao vivo, você também precisa fornecer o carimbo de data/hora do frame de entrada para a tarefa de detecção de pontos de referência da mão.
Quando executada no modo de imagem ou vídeo, a tarefa de detecção de pontos de referência da mão bloqueia a linha de execução atual até que ela termine de processar a imagem ou o frame de entrada. Para evitar o bloqueio da linha de execução atual, execute o processamento em uma linha de execução em segundo plano usando os frameworks Dispatch ou NSOperation do iOS.
Quando executada no modo de transmissão ao vivo, a tarefa de marcador de mão retorna imediatamente e não bloqueia a linha de execução atual. Ele invoca o método
handLandmarker(_:didFinishDetection:timestampInMilliseconds:error:)
com o resultado do ponto de referência da mão após o processamento de cada frame de entrada. O Hand Scoreer invoca esse método de forma assíncrona em uma fila de envio em série dedicada. Para mostrar os resultados na interface do usuário, envie os resultados para a fila principal depois de processá-los. Se a funçãodetectAsync
for chamada quando a tarefa de detecção de pontos de referência da mão estiver ocupada processando outro frame, a detecção de pontos de referência da mão vai ignorar o novo frame de entrada.
Processar e mostrar resultados
Ao executar a inferência, a tarefa "Ponto de referência da mão" retorna um HandLandmarkerResult
que contém pontos de referência de mão em coordenadas de imagem, pontos de referência de mão em coordenadas
mundiais e mão esquerda(esquerda/direita) das mãos detectadas.
Confira a seguir um exemplo dos dados de saída desta tarefa:
A saída HandLandmarkerResult
contém três componentes. Cada componente é uma matriz, em que cada elemento contém os seguintes resultados para uma única mão detectada:
Mão dominante
A dominância da mão representa se as mãos detectadas são esquerda ou direita.
Pontos de referência
Há 21 pontos de referência da mão, cada um composto por coordenadas
x
,y
ez
. As coordenadasx
ey
são normalizadas para [0,0, 1,0] pela largura e altura da imagem, respectivamente. A coordenadaz
representa a profundidade do ponto de referência, com a profundidade no pulso sendo a origem. Quanto menor o valor, mais próximo o ponto de referência está da câmera. A magnitude dez
usa aproximadamente a mesma escala quex
.Pontos turísticos do mundo
Os 21 pontos de referência da mão também são apresentados em coordenadas mundiais. Cada ponto de referência é composto por
x
,y
ez
, representando coordenadas 3D reais em metros com a origem no centro geométrico da mão.
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)
A imagem a seguir mostra uma visualização da saída da tarefa: