WWDC Quick Look 💓 By SwiftGGTeam
Explore the Action & Vision app

Explore the Action & Vision app

元の動画を見る

ハイライト

Apple は、Action & Vision サンプル アプリを使用して、Create ML、Core ML、Vision の物体検出、人間の姿勢、軌道、輪郭検出をデバイス上で組み合わせる方法をデモンストレーションし、iPhone または iPad でビーンバッグ投げを記録し、投げの種類を識別し、速度、角度、スコアに関するリアルタイムのフィードバックを提供できるようにします。

主要内容

多くのスポーツ分析アプリの最初のステップは、ユーザーが自分でビデオを視聴できるようにすることです。それを撮影し、再生し、自分の目に頼ってアクションのどこが間違っていたかを判断してください。Action & Vision は視点を変えます。携帯電話は最初にサイドラインに固定され、カメラを使用して選手とフィールドを観察し、次にローカル マシン上で認識、分析、フィードバックを完了します。

セッションが選んだ例はビーンバッグトスです。アプリは 4 つの質問に答える必要があります。会場はどこか、プレーヤーはどのように移動するか、お手玉はどのように飛ぶか、そして最後にユーザーにどのようなフィードバックを与える必要があるかです。この例は、理解するのに十分なほど単純で、十分に完成しています。サイトの位置決め、人間の姿勢、動作軌跡、動作の分類、速度と角度の計算が同時に必要です。

Apple はプロセスを 3 つの段階に分けています。準備段階では、まず Create ML によってトレーニングされた物体検出モデルを使用してボードを見つけ、次に画像位置合わせを使用してカメラが安定しているかどうかを判断します。セットアップ段階では、輪郭検出を使用してボードの端と穴を測定し、体の姿勢検出を使用してプレーヤーを見つけます。ゲームの段階では、ビーンバッグの放物線が追跡され、投げる前後の体の姿勢ウィンドウが取得され、Core ML モデルを使用して、オーバーハンド、アンダーハンド、またはアンダーザレッグのいずれであるかが判断されます。

このセッションの値は単一の API にはありません。これは、リアルタイム ビジョン アプリのエンジニアリング組織を示しています。カメラ フレームはさまざまな ViewController とキューに入り、Vision リクエストはそれぞれ一種の観察を担当し、最後にビジネス ステート マシンがこれらの結果をユーザーが理解できるフィードバックにマージします。

詳細

このセッションのクエリ データの公式コード スニペットはありません。次のコード ブロックでは、サンプル プロジェクトの実装パスを示すために、トランスクリプトで指定されたクラス、関数、属性、および計算関係のみをリストします。

会場の特定: まずボードを見つけて、次にカメラが安定していることを確認します。

(05:56) スピーカーは最初にアルゴリズム チェーン全体をリストします。ボードは、実行時に渡される Create ML のカスタム オブジェクト検出モデルによって認識されます。VNCoreMLRequest推論を行ってください。ボードを見つけた後、アプリは画像登録を使用してカメラが固定されているかどうかを判断し、輪郭検出を使用してボードの端を測定します。

// SetupViewController 的准备阶段流程,按 transcript 中的代码走查整理
let boardDetectionRequest: VNCoreMLRequest
let sceneStabilityRequest: VNTranslationalImageRegistrationRequest
let boardContourRequest: VNDetectContoursRequest

boardContourRequest.regionOfInterest = boardBoundingBox

キーポイント:

  • VNCoreMLRequestCreate ML によってトレーニングされたボード検出モデルの実行と、ボードの境界ボックスの出力を担当します。
  • VNTranslationalImageRegistrationRequest連続フレーム内の並進変化を比較します。アプリでは、15 フレームの移動平均が 10 ピクセル未満の場合、シーンは安定していると見なされます。
  • VNDetectContoursRequest前のステップで取得したものを使用しますboardBoundingBox設定regionOfInterest、ボード領域内の輪郭のみを検索します。
  • 輪郭の結果はボードのエッジと穴を見つけるために使用され、ボードの実際のサイズは後で実際の速度を計算するときに使用されます。

プレイヤーの識別: ボディジェスチャーを使用して人々を画面から追い出します

(08:54) ボードとフィールドの準備ができたら、アプリはプレーヤーを見つける必要があります。ここで使用しているのはiOS 14で新しく追加されたものですVNDetectHumanBodyPoseRequest。肘、肩、手首、脚などの人体の関節点を返し​​ます。アプリはこれに基づいて関節角度を計算し、連続姿勢を動作分類モデルへの入力として使用することもできます。

// GameViewController 接收相机帧后执行身体姿态请求
let detectPlayerRequest: VNDetectHumanBodyPoseRequest

func handleBodyPoseResults(_ observations: [VNRecognizedPointsObservation]) {
    let playerBox = humanBoundingBox(observations)
    bodyPoseObservations.append(contentsOf: observations)
}

キーポイント:

  • VNDetectHumanBodyPoseRequestこれは、この分野のアクション分析の中核となる入力であり、その後の投球角度とアクション分類はすべてそれに依存します。
  • humanBoundingBoxトランスクリプトで信頼性の低い観測結果をフィルタリングし、フレームに入るプレーヤーの境界ボックスを返すために使用されます。
  • アプリは保存しますbodyPoseObservationsアクションの分類には、一定期間内のジェスチャ シーケンスが必要なためです。
  • このステップでは写真をクラウドにアップロードしません。セッションの冒頭では、すべての分析がデバイス側で完了できることを明確に強調しています。

軌道検出: ビーンバッグ飛行を計算可能な放物線に分割

(18:01) ゲームの開始後、アプリはビーンバッグの飛行経路を見つける必要があります。VNDetectTrajectoriesRequestこれはステートフル リクエスト (ステートフル リクエスト) であり、サンプル バッファにタイムスタンプを継続的に供給する必要があります。最初のフレームでは結論は出ず、複数のフレームから証拠を蓄積し、5フレーム目あたりの軌跡のみを報告します。

let detectTrajectoryRequest: VNDetectTrajectoriesRequest
detectTrajectoryRequest.frameAnalysisSpacing = CMTime.zero
detectTrajectoryRequest.trajectoryLength = trajectoryLength
detectTrajectoryRequest.minimumObjectSize = minimumObjectSize
detectTrajectoryRequest.maximumObjectSize = maximumObjectSize

キーポイント:

  • frameAnalysisSpacing分析フレーム間隔を制御します。すべてのフレームを分析するには 0 に設定し、古いデバイスの負荷を軽減するには値を増やします。
  • trajectoryLength短すぎる断片的な動きを除外するために使用されます。
  • minimumObjectSizeそしてmaximumObjectSizeお手玉のサイズに基づいて、ノイズ、腕の振り、その他の大きなオブジェクトをフィルターします。
  • VNDetectTrajectoriesRequest一連のフレームにわたって状態を構築するときは、同じインスタンスを維持します。
  • セッションでは、軌跡検出はシーンを安定させる必要があること、オブジェクトの動きは放物線として近似する必要があること、サンプル バッファーにはタイムスタンプが必要であることを明確に思い出させます。

(19:29) 軌跡の結果は次のようになります。VNTrajectoryObservation戻る。これには、検出ポイント、投影ポイント、放物線係数、および時間範囲が含まれます。アプリはこの情報を使用して滑らかな軌道を描き、パスを出します。UUIDお手玉の軌道と影の軌道を区別します。

func processTrajectoryObservations(_ observations: [VNTrajectoryObservation]) {
    for observation in observations {
        let detectedPoints = observation.points
        let projectedPoints = observation.projectedPoints
        let coefficients = observation.equationCoefficients
        let timeRange = observation.timeRange
    }
}

キーポイント:

  • pointsは移動オブジェクトの中心点シーケンスです。
  • projectedPoints放物線を描く投影点であり、滑らかな曲線を描くのに適しています。
  • equationCoefficients対応するy = ax^2 + bx + c係数。
  • timeRange投球の実際の開始時刻と終了時刻をアプリに伝えます。これは、対応する人間の姿勢ウィンドウを振り返るために使用されます。

アクション分類: スロー イベントを使用して姿勢ウィンドウをインターセプトする

(25:00) 投げるタイプは継続的に予測されません。アプリはまず軌道検出を使用してスローが発生したことを確認し、次に体の姿勢履歴から 45 フレームを取得して 1 つに結合します。MLMultiArrayラベルと信頼度の予測は Core ML モデルに任せます。

let bodyPoseWindow = bodyPoseObservations // 45 frames around the detected throw
let modelInput: MLMultiArray = prepareInputWithObservations(bodyPoseWindow)
let throwType = playerStats.getLastThrowType()

let confidence = highestProbability

キーポイント:

  • トランスクリプトには、このフィールド モデルが Create ML によってトレーニングされ、Core ML を通じてアプリ内で実行されることが明確に記載されています。
  • 軌道によって検出された投球ポイントの周囲の 45 フレーム ウィンドウ。完全な投球動作をカバーすることを目的としています。
  • モデルの入力元は次のとおりですVNDetectHumanBodyPoseRequest抽出された身体ポーズは、元のビデオ フレームを直接使用しません。
  • モデルには当初、アンダーハンド、オーバーハンド、アンダーザレッグの 3 つのカテゴリしかありませんでした。その後、ビーンバッグを拾ったり歩いたりするなど、投げ以外のアクションをフィルターするために Other/Negative クラスが追加されました。

速度と角度: ピクセル測定値をユーザーのフィードバックに変換します

(27:51) アプリはボードの実際の寸法 (2 フィート x 4 フィート) をすでに認識しています。輪郭検出により、画像内のボードのピクセル サイズがわかります。両者の比率が確立されると、お手玉の軌跡の長さをピクセルから実際の距離に変換できます。弾道の持続時間で割ると、リリース速度が得られます。

let distanceInPixels = trajectoryLengthInPixels
let distanceInFeet = distanceInPixels * boardScaleInFeetPerPixel
let releaseSpeed = distanceInFeet / trajectoryDuration

let releaseAngle = angle(from: wristPoint, to: elbowPoint, relativeTo: horizon)

キーポイント:

  • 真のスケールは通常のボードの固定寸法から得られ、追加の校正オブジェクトは必要ありません。
  • releaseSpeedによる転写ではupdatePathLayer軌跡の長さと継続時間を使用して計算されます。
  • releaseAngle存在するgetReleaseAngle計算では、ビーンバッグを使用して、そのフレームの手首と肘のポイントを解放します。
  • これらの指標は最終的に概要ビューに表示され、プレーヤーがさまざまな投球軌道、平均速度、リリース角度、最終スコアを比較するのに役立ちます。

リアルタイム処理: 最初にカメラ バッファを解放し、次に UI をレンダリングします。

(33:00) リアルタイム アプリで最も一般的な問題はカメラのバッファーです。カメラで使用できるバッファの数は限られています。分析コードがバッファーを長時間占有すると、カメラはフレームを失います。Session の提案は、デキューして並列処理し、できるだけ早くバッファを返し、非同期でメイン キューに戻って結果をレンダリングすることです。

func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer) {
    trajectoryQueue.async {
        performTrajectoryAnalysis(sampleBuffer)
    }

    bodyPoseQueue.async {
        performBodyPoseAnalysis(sampleBuffer)
    }

    DispatchQueue.main.async {
        renderLatestOverlay()
    }
}

キーポイント:

  • 同じ実行パス上のすべての分析がブロックされるのを避けるために、軌道と体の姿勢は別々にキューに入れられます。
  • UI オーバーレイの更新はメイン キューに戻されますが、レンダリングの完了を待たずにカメラ バッファーを解放します。
  • フレームレートを維持できない場合は、キャプチャ出力を使用してくださいdidDropフレーム損失の原因をもう一度確認してください。
  • ローカルビデオを再生する場合、セッションが使用されますAVPlayerItemVideoOutput協力するCADisplayLink、再生遅延を避けるために、分析のために表示時間に応じてピクセル バッファーを取得します。

重要ポイント

  • シュートまたはスロー レビュー ツール: 機能: バスケットボール、フリスビー、テニスのサーブなどの放物線運動を記録します。やる価値がある理由: この分野VNDetectTrajectoriesRequestポイント、放物線、時間枠が表示されます。開始方法: まずカメラの位置を固定し、minimumObjectSizeそしてmaximumObjectSizeターゲットサイズをロックして を押しますtimeRangeアクションの前後の姿勢をインターセプトします。

  • ホーム フィットネス動作のフィードバック: やるべきこと: スクワット、ランジ、ジャンピング ジャックなどの動作の種類と数を特定します。なぜ価値があるか: アクションとビジョンは、体の姿勢が次のような影響を与える可能性があることを証明します。MLMultiArrayそしてアクション分類モデルに引き渡されます。開始方法: まず 10043 を見てアクション分類子をトレーニングし、次にポーズ ウィンドウ キャッシュを独自の Core ML モデルに接続します。

  • 子供向けスポーツ ゲーム スコアラー: 機能: 実際の投げ、ジャンプ、スイングの動きを自動スコアリング ゲームに変換します。実行する価値がある理由: このゲームは、設定、ゲーム、概要の 3 つの状態を接続するために GameManager を使用します。これは、敷居の低いインタラクティブ ゲームに適しています。開始方法: まず安定したサイトを定義し、輪郭検出を使用して実際のスケールを確立し、次に軌道または姿勢の結果をスコアにマッピングします。

  • トレーナーの動作比較レポート: やるべきこと: 複数のスローのスピード、リリース角度、軌道形状をトレーニング レポートにまとめます。実行する価値がある理由: 概要ビューには、軌道、平均速度、リリース角度、スコアがすでに表示されています。開始方法: 毎回保存するVNTrajectoryObservation投影ポイント、リリース速度、リリース角度をグラフで表示し、最良の試行と最悪の試行を示します。

関連セッション

コメント

GitHub Issues · utterances