(Swift)Visionフレームワークを利用して手の形を認識する
はじめに
サンプルアプリを作成したので、まずは試してみてください。
このアプリはカメラの映像を500 msごとに取得し、手の形を識別します。手の形がグーの場合はマラカスの音、手の形がパーの場合は拍手の音が鳴ります。
実装の考慮事項
Visionフレームワークの使い方はApple Developerのサイトにて詳しく説明されていますので、そちらを参照してください。ここからはドキュメントでは触れられていない、アプリを実装する際の考慮事項についてまとめます。
(その1)Visionフレームワークにグーやパーなど手の形を分類する機能はない
Visionフレームワークで手を認識した際に得られる情報は座標と信頼度から構成されるジョイントとよばれる値のみです。グーやパーなど手の形を分類する機能は提供されていません。
指については先端、第一関節、第二関節、つけ根の4個のジョイントが取得できます。手全体で、5本の指プラス手首の合計21個のジョイントが取得できます。このデータをもとに何らかの特徴量を見つけ出し、手の形を分類する必要があります。
今回のサンプルアプリは素朴な方法で実装しました。具体的には手首から中指の先端までの距離をもとにグーとパーを分類しています。中指を選んだのは手を閉じたり開いたりした際に最も大きく距離が変化するためです。
ただし、この実装方法は指先と手首までの距離を判定しているだけですから、例えばパーとチョキの区別がつきません。また、手首をひねって指先までの距離が短く見えるような形にしたり、手首がカメラのファインダーからはみ出したりすると、うまく認識されません。
もし事前に大量の画像データを用意できるなら、VisionフレームワークではなくCreate MLフレームワークのMLHandPoseClassifierでモデルを訓練した方が、よい結果が得られるはずです。あるいはVisionフレームワークと組み合わせて、信頼度の低い画像を事前に弾いた後に訓練させるなどハイブリッドな方法も考えられます。
(その2)カメラの前で手を動かしているだけで消費電力が増える
iOS標準のカメラアプリを開いて動画モードにします。撮影ボタンは押さないでください。その後、カメラの前で手を閉じたり開いたり、適当に動かし続けてみてください。iPhone本体が発熱するはずです。
比較として動きのないもの、例えば無地の壁や床にカメラを向けてみてください。そのまま放置してもほぼ発熱しないはずです。あくまで想像ですが、おそらくプレビューしている最中も綺麗な映像でプレビューできるように、高頻度で物体認識をしているものと思われます。
Visionフレームワークに限った話ではありませんが、カメラから取得した画像をもとに動きのあるものを認識しようとすると必ず消費電力が増えます。うまい対策が思いつかないので、各自で工夫するしかなさそうです。
(その3)VNDetectedPointのconfidenceについて
VNDetectedPointのconfidenceプロパティ(信頼度を表す値)は0.0から1.0に正規化された値です。1.0で最も信頼できることを意味します。
この値ですが、アプリの動作検証を進める中で0.5未満でもそれなりに信頼できることがわかりました。体感的には0.3までは信頼して問題なさそうです。ただし、閾値を下げすぎると過敏に反応することになります。
なお、動作検証した環境は屋内かつ物が少ない場所です。今回作成したサンプルアプリでは定数0.75をハードコードしていますが、動作検証を繰り返す中でこれくらいで良いだろうと適当に決めた値です。利便性を追求するなら、ユーザーごとに閾値を調整できるようにしたり、フィードバックをもとに動的に変化させるようにすると良さそうです。
参考までに、Appleが提供しているVisionフレームワークのサンプルプロジェクトでも、謎の定数0.3がハードコードされています。
- Detecting Hand Poses with Vision - Apple Developer Documentation
- HandPose/CameraViewController.swift:229
// Ignore low confidence points.
guard thumbTipPoint.confidence > 0.3 && indexTipPoint.confidence > 0.3 else {
return
}
(その4(手袋をすると認識の精度はどうなる?
手をパーの形にして5本の指が独立した状態であれば、手袋をしていてもほぼ確実に認識されます。例えば白い軍手をしていても、認識の精度は普段とほぼ変化ありませんでした。
しかし、手袋をした状態で指を少しでも曲げると、急激に認識の精度が低下します。例えば軍手おをした状態であれば、グーの形は全く認識されません。
Visionフレームワークが利用している機械学習のモデルがどのようなものか公表されていないため、我々が詳細を知ることはできません。加えて、iOSのバージョンごとにモデルが徐々に改善されている可能性もあります。手の認識といってもアプリケーションごとに要件は異なるでしょうし、やはり実機でテストする工程は踏んだ方が良さそうです。
(その5)手の認識にかかる時間
以下の実機で手の認識にかかる時間を計測しました。バッテリー残量は100 %かつ他のアプリはすべて閉じた状態での計測です。
- iPhone 15 Pro
- iPhone 13
- iPhone SE 第2世代
結果は次のとおりでした。
- iPhone 15 Pro: 19 ms
- iPhone 13: 27 ms
- iPhone SE 第2世代: 40 ms
どの端末も動作中はやや発熱しますが、極端に暑くなったりバッテリーの残量が急激に低下することはありませんでした。
2020年に発売されたiPhone SE 第2世代が想定外に良い結果を出したことに驚いています。この端末はバッテリー交換をせずに使い続け、著しいバッテリーの劣化(新品値との比較で残量77 %)の警告が表示されている状態です。Visionフレームワークがいかに最適化されているか理解しました。
参考資料
- Detecting Hand Poses with Vision - Apple Developer Documentation
- VNRecognizedPoint - Apple Developer Documentation
- VNHumanHandPoseObservation.JointName - Apple Developer Documentation
- MLHandPoseClassifier - Apple Developer Documentation
- Recognizing Gestures with Machine Learning - Sample Apps Tutorials - Apple Developer Documentation
Discussion