WWDC Quick Look 💓 By SwiftGGTeam
Classify hand poses and actions with Create ML

Classify hand poses and actions with Create ML

元の動画を見る

ハイライト

[ML の作成] では、手のポーズの分類と手の動作の分類という 2 つの新しいテンプレートが追加されます。開発者は、カスタム ジェスチャ分類器をトレーニングし、Vision の手のキー ポイント検出に基づいてジェスチャ コントロール アプリを実装できます。

主な内容

2 つのジェスチャー表現形式

Vision フレームワークは、iOS 14 で手のキーポイント検出を導入しました。これにより、写真内の手と 21 の関節ポイントの位置を識別できます。しかし、手がどこにあるかを知ることと、手が何をしているかを知ることは別の問題です。

WWDC2021 では、2 種類のジェスチャー表現が区別されました (01:36):

  • ポーズ: 静的なポーズ。1 枚の写真で完全な意味を表現できます。たとえば、「親指を立てる」、「バイエー」、「ストップ」のジェスチャーなどです。
  • アクション: 意味を表現するには継続的な動きが必要です。「手を振る」「こっちにおいで」「あっちへ行って」など。意図は 1 つのフレームだけを見て判断することはできず、ビデオ シーケンスが必要です。

これら 2 つのフォームに対して、Create ML はそれぞれ手のポーズ分類テンプレートと手の動作分類テンプレートを提供します。

手のポーズ分類トレーニング プロセス

トレーニング データはカテゴリごとにフォルダーに保存する必要があります (04:08)。各フォルダ名はカテゴリ名です。これには、2 種類の画像を含む Background クラスが含まれている必要があります。1 つは、さまざまな無関係なジェスチャのランダムな写真 (さまざまな肌の色、年齢、照明をカバーするため)、もう 1 つは、ターゲット ジェスチャの遷移姿勢 (手を下ろしてから「停止」ジェスチャに至るまでの位置など) です。

Background クラスの目的は、モデルに「いつトリガーすべきでないのか」を学習させることです。これがないと、モデルはすべての手の位置を特定のターゲット ジェスチャとして分類し、誤ったトリガーが発生します。

今年、Create ML アプリにライブ プレビュー機能が追加されました (06:07)。 FaceTime カメラを使用すると、最初にアプリに統合しなくても、モデルの効果をリアルタイムでテストできます。

手の動作の分類に関する特別な要件

アクションの分類にはトレーニング データとしてビデオが必要です (17:23)。各ビデオはアクションを表し、カテゴリごとにフォルダーに保存されます。Background クラスは、ターゲットのアクションと関係のないビデオを配置するためにも必要です。

トレーニング中にアクションの継続時間を指定する必要があります。Create ML は、この期間から連続するフレームをランダムにサンプリングします。ビデオ フレーム レートは、トレーニング中に指定されたフレーム レートと一致する必要があります。デモでは 30fps、1.5 秒のビデオを使用するため、モデルは入力として 45 フレーム (45 の手のポーズ) を想定しています。

ビジョンのキラリティー: 左手と右手の区別

今年与えるビジョンVNHumanHandPoseObservation追加したchirality属性 (14:44) により、検出された手が左右どちらであるかを判断できます。左手と右手の判定は独立しており、一方の手の結果がもう一方の手の判定に影響を与えることはありません。

この機能により、「左手で移動、右手で攻撃」といったゲーム上のインタラクションが可能になります。

##詳細

ビジョンを使用して手のキーポイントを検出する

09:31

func session(_ session: ARSession, didUpdate frame: ARFrame) {
    let pixelBuffer = frame.capturedImage

    let handPoseRequest = VNDetectHumanHandPoseRequest()
    handPoseRequest.maximumHandCount = 1
    handPoseRequest.revision = VNDetectHumanHandPoseRequestRevision1

    let handler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, options: [:])
    do {
        try handler.perform([handPoseRequest])
    } catch {
        assertionFailure("Hand Pose Request failed: \(error)")
    }

    guard let handPoses = handPoseRequest.results, !handPoses.isEmpty else {
        // 没有检测到手,清除特效
        return
    }
    let handObservation = handPoses.first
}

キーポイント:

  • maximumHandCount検出する手の最大数を制御します。デフォルトは 2 です。画像内にさらに多くの手が存在する場合、アルゴリズムは最も目立つ中央にある手を選択します。
  • 明示的に設定することを推奨しますrevision、SDK アップデート後の動作の変更を避けるため
  • ここではARKitを使用してフレームを取得していますが、これを使用することもできますAVCaptureOutput代替案として

ジェスチャ分類予測

11:03

if frameCounter % handPosePredictionInterval == 0 {
    guard let keypointsMultiArray = try? handObservation.keypointsMultiArray()
    else { fatalError() }

    let handPosePrediction = try model.prediction(poses: keypointsMultiArray)
    let confidence = handPosePrediction.labelProbabilities[handPosePrediction.label]!

    if confidence > 0.9 {
        renderHandPoseEffect(name: handPosePrediction.label)
    }
}

func renderHandPoseEffect(name: String) {
    switch name {
    case "One":
        if effectNode == nil {
            effectNode = addParticleNode(for: .one)
        }
    default:
        removeAllParticleNode()
    }
}

キーポイント:

  • すべてのフレームを予測する必要はなく、間隔予測により特殊効果のジッターを回避できます。
  • keypointsMultiArray()21 個の関節点を MLMultiArray に変換し、Core ML モデルに直接入力します
  • 信頼度のしきい値を高く (0.9) に設定すると、誤ったトリガーを減らすことができ、Background クラスの存在により高いしきい値が可能になります。
  • labelProbabilitiesすべてのカテゴリの確率分布を取得できます

人差し指先端の位置を特殊効果のアンカーポイントとして取得します。

12:25

let landmarkConfidenceThreshold: Float = 0.2
let indexFingerName = VNHumanHandPoseObservation.JointName.indexTip

let width = viewportSize.width
let height = viewportSize.height

if let indexFingerPoint = try? observation.recognizedPoint(indexFingerName),
   indexFingerPoint.confidence > landmarkConfidenceThreshold {

    let normalizedLocation = indexFingerPoint.location
    indexFingerTipLocation = CGPoint(
        x: normalizedLocation.x * width,
        y: normalizedLocation.y * height
    )
} else {
    indexFingerTipLocation = nil
}

キーポイント:

  • recognizedPoint(_:)指定された関節点の正規化された座標を取得します (0 ~ 1 の範囲)
  • 要チェックconfidence、信頼性の低いキーポイントの位置は信頼できません。
  • Vision の座標原点は左下隅にあり、UIKit の左上隅の原点とは異なります。変換するときは注意してください
  • ビューポートの幅と高さを乗算して、正規化された座標を画面座標に変換します。

左手と右手を区別する

15:47

let handPoseRequest = VNDetectHumanHandPoseRequest()
try handler.perform([handPoseRequest])
let detectedHandPoses = handPoseRequest.results!

for hand in detectedHandPoses where hand.chirality == .right {
    // 只对右手采取行动,或过滤结果
}

キーポイント:

  • chiralityはいVNHumanHandPoseObservation.Chirality列挙すると、.left.right.unknown3つの価値観
  • .unknown古いバージョンの Observation を逆シリアル化する場合にのみ表示されます
  • 各手のキラリティーは独立して判断され、他の手の影響を受けません。

手のアクションの分類: 累積ジェスチャ キュー

22:16

var queue = [MLMultiArray]()

frameCounter += 1
if frameCounter % 2 == 0 {
    let hands: [(MLMultiArray, VNHumanHandPoseObservation.Chirality)] = getHands()

    for (pose, chirality) in hands where chirality == .right {
        queue.append(pose)
        queue = Array(queue.suffix(queueSize))
        queueSamplingCounter += 1

        if queue.count == queueSize && queueSamplingCounter % queueSamplingCount == 0 {
            let poses = MLMultiArray(
                concatenating: queue,
                axis: 0,
                dataType: .float32
            )
            let prediction = try? handActionModel?.prediction(poses: poses)

            guard let label = prediction?.label,
                  let confidence = prediction?.labelProbabilities[label]
            else { continue }

            if confidence > handActionConfidenceThreshold {
                DispatchQueue.main.async {
                    self.renderer?.renderHandActionEffect(name: label)
                }
            }
        }
    }
}

キーポイント:

  • アクション分類では、一定期間の姿勢データを蓄積し、FIFO キューを使用して最新の姿勢データを保存する必要があります。queueSizeジェスチャー
  • デモでは、ARKit は 60fps を出力しますが、モデルのトレーニングでは 30fps を使用するため、2 フレームごとに 1 フレームが取得されます (frameCounter % 2 == 0
  • キューがいっぱいの場合は、 を押します。queueSamplingCount応答速度と計算量を両立したインターバル読み取り
  • MLMultiArray(concatenating:axis:dataType:)キュー内のポーズをモデルが予期する入力シェイプ (45x3x21) に結合します。

重要ポイント

1.ジェスチャーコントロール AR ゲーム

  • やるべきこと: さまざまなジェスチャーを使用して、さまざまな AR 特殊効果やスキルをトリガーします。たとえば、「拳を作る」と火の玉を発射し、「手のひらを開く」とシールドを生成します。
  • 実行する価値がある理由: 手のポーズ分類では、使用可能な精度を達成するために数十のトレーニング画像のみが必要であり、Create ML アプリのライブ プレビューによりデバッグが非常に便利になります
  • 開始方法: 各ジェスチャ (Background クラスを含む) の写真を 500 枚収集し、Create ML アプリでトレーニングし、Vision を統合しますVNDetectHumanHandPoseRequestキーポイント入力モデルの取得

2.両手コラボレーションのためのクリエイティブ ツール

  • やるべきこと: 左手でブラシの色を制御し (さまざまなジェスチャーで色を切り替える)、右手でブラシの太さを制御します (指の開き具合)
  • 実行する価値がある理由:chirality属性により両手を独立して制御できるようになり、一方の手の状態がもう一方の手の認識に影響を与えることはありません。
  • 開始方法: 2 つの手のポーズ分類子をそれぞれトレーニングします。1 つは左手のジェスチャーを認識し、もう 1 つは右手のジェスチャーを認識します。使用chiralityそれぞれの入力をフィルタリングする

3.ジェスチャーパスワード/認証

  • 何をすべきか: ユーザーは、専用のジェスチャ シーケンスのセットをアプリのロック解除パスワードとして定義します。
  • 実行する価値がある理由: 手の動作の分類により、連続的な動作シーケンスを識別できるため、静的なジェスチャより安全です (秘密の写真にコピーされるのが困難)
  • 開始方法: ハンド アクション分類を使用してユーザーのカスタム アクションをトレーニングし、アクションごとに 1.5 秒のビデオを 100 件録画し、マッチングのためにアプリにジェスチャ キューを蓄積します。

4.サイレントコマンドシステム

  • 対処方法: 図書館や会議室など、沈黙が必要なシーンでは、ジェスチャーを使用して音楽再生やスライド ページめくりを制御します。
  • 価値がある理由: Vision の手検出は、通常の屋内照明の下で安定して動作し、追加のハードウェアは必要ありません。
  • 開始方法: 一連の簡単なジェスチャー (次の曲、一時停止、音量の増減) を定義し、ハンド ポーズ分類器をトレーニングし、組み合わせます。VNDetectHumanHandPoseRequestリアルタイム検出

関連セッション

コメント

GitHub Issues · utterances