MediaPipeのハンドトラッキング(iOS)をXcodeプロジェクトでビルドしてみた

# 概要
1. 環境構築(MediaPipe)
2. ターミナルでビルド
3. 環境構築(Tulsi)
4. Xcodeプロジェクトでビルド

# 成果物

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Hand Tracking on iOS📱<a href="https://twitter.com/hashtag/MediaPipe?src=hash&amp;ref_src=twsrc%5Etfw">#MediaPipe</a> <a href="https://t.co/mgHPfUIHwK">pic.twitter.com/mgHPfUIHwK</a></p>&mdash; MIWA Tetsushi (@WWWPONTE) <a href="https://twitter.com/WWWPONTE/status/1293183995086172171?ref_src=twsrc%5Etfw">August 11, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 開発環境
- MacBook Pro: Catalina 10.15.4
    - Xcode: 11.6
- iPhone SE(第2世代): iOS 13.5.1

# 環境構築(MediaPipe)
### 1. Homebrewのインストール
- [https://brew.sh](https://brew.sh/)に表示されているコマンドをコピー
- ターミナルにペーストして実行
- 終わったら以下のコマンドを打ってバージョンが表示されたら完了

```zsh

$ brew -v
# Homebrew 2.4.7
```

### 2. Command Line Tools のインストール
- [https://developer.apple.com/download/more](https://developer.apple.com/download/more/)より、Xcodeのバージョンに合ったCommand Line Toolsをダウンロード ※Apple Developer Programへのサインインが必要
- ダウンロードした`.dmg`をクリックしてインストール
- 以下のコマンドを打ってライセンスが表示されたら完了

```
$ sudo xcodebuild -license
```

### 3. Pythonのバージョン確認
mac には、デフォルトで Python がプリインストールされている。Python のバージョンによって、ビルドが通らないことがあるので、Python のバージョンを確認しておく必要がある。私は、`Python 3.7.5` でビルドが通ったことを確認しているのでこのバージョンの Pythonでビルドを行うことを推奨する。その際に、`pyenv` という Python のバージョンを切り替えられるバージョンマネージャーがあるので、それを利用した方法を説明する。

- pyenvをクローン

```
$ git clone https://github.com/pyenv/pyenv.git ~/.pyenv
```
- パスを通す

シェルが `zsh` の場合

```zsh
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zsh_profile
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zsh_profile
$ echo 'eval "$(pyenv init -)"' >> ~/.zsh_profile
```

- `Python 3.7.5`をインストール

```
$ pyenv install 3.7.5
```

~/.pyenv/versions/ 配下にインストールした Python が配置される

- `shim`のリフレッシュ

```
$ pyenv rehash
```

- 使用するPythonの指定

グローバルで指定する場合

```
$ pyenv global 3.7.5
```

ローカルで指定する場合

```
$ pyenv local 3.7.5
```

### 4. sixライブラリのインストール
Python 2 と Python 3 の間の違いを吸収するために、”six” ライブラリをインストールする

```
$ pip install –user future six
```

### 5. MediaPipeリポジトリのクローン 

```
$ git clone https://github.com/google/mediapipe.git
```

### 6. Bazelのインストール 

- `Bazel`をインストール

```
$ brew install bazel
```

- 終わったら以下のコマンドを打ってバージョンが表示されたら完了

```zsh

$ bazel --version
# bazel 3.3.0
```

### 7. OpenCVとFFmpegのインストール 

```
$ brew install opencv@3
```

### 8. numpyのインストール 

```
$ pip install numpy
```

### 9. 動作確認

- `Hello World desktop example`を実行

```zsh

$ export GLOG_logtostderr=1
$ bazel run --define MEDIAPIPE_DISABLE_GPU=1 \
    mediapipe/examples/desktop/hello_world:hello_world

# しばらくして以下が表示されたら動作確認完了
# Hello World!
# Hello World!
# Hello World!
# Hello World!
# Hello World!
# Hello World!
# Hello World!
# Hello World!
# Hello World!
# Hello World!
```

# ターミナルでビルド
まず、ターミナルでハンドトラッキング(iOS)をビルドして、ビルドに必要な準備をする

### 1. Provisioning Profileの準備

iOS アプリを実機で実行するために、`Provisioning Profile`と呼ばれるiOSデバイスやアプリを識別するためのファイルが必要である。Apple Developer Program 加入者は、[https://developer.apple.com/jp](https://developer.apple.com/jp/)より作成してダウンロード可能である。ダウンロードしたファイルを`provisioning_profile.mobileprovision`にリネームして、`mediapipe/mediapipe/`に配置する。

### 2. Bundle Identifierの変更

次に、`mediapipe/mediapipe/examples/ios/handtrackinggpu/`の中にある `BUILD`を修正する。`bundle_id`を`Provisioning Profile `で設定した`Bundle Identifier`に変更する。

```zsh:mediapipe/examples/ios/handtrackinggpu/BUILD：36

bundle_id = BUNDLE_ID_PREFIX + ".HandTrackingGpu",
　　　　　　　　　↓
bundle_id = "(Bundle Identifier)",
```

### 3. ビルド

`mediapipe/`ディレクトリに移動してから以下のコードをターミナルに入力することでビルドが始まる

```zsh

$ bazel build -c opt –config=ios_arm64 mediapipe/example/ios/handtrackinggpu:HandTrackingGpuApp
```

下記ディレクトリにipaファイルができる

```zsh

bazel-bin/mediapipe/examples/ios/handtrackinggpu/
```

# 環境構築(Tulsi)
Tulsiを使ってXcodeプロジェクトを生成する

### 1. Tulsiリポジトリのクローン

```
$ git clone https://github.com/bazelbuild/tulsi.git
```

### 2. パッチの適用

```
$ cd tulsi
$ git fetch origin pull/99/head:xcodefix
$ git checkout xcodefix
```

### 3. ビルドスクリプトの実行

```
sh build_and_run.sh
```

実行してみたら、以下のエラーが発生した

```zsh

ERROR: /Users/miwa/tulsi/BUILD:62:18: Linking of rule '//:tulsi.__internal__.apple_binary' failed (Exit 1) wrapped_clang failed: error executing command external/local_config_cc/wrapped_clang -Xlinker -objc_abi_version -Xlinker 2 -fobjc-link-runtime -ObjC -arch x86_64 -filelist ... (remaining 26 argument(s) skipped)
```

[こちら](https://github.com/bazelbuild/tulsi/issues/102)の記事を参考にしたところ、実行することが出来た

```zsh:tulsi/WORKSPACE：6

tag = "0.17.2",
　　　　　　　　　↓
tag = "0.18.0",
```

### 4. Tulsi.appでMediaPipe.tulsiprojを開き、Xcodeプロジェクトを生成
- Tulsi.appを起動して、`mediapipe/mediapipe/`配下にある`Mediapipe.tulsiproj`を開く

<img width="614" alt="Tulsi_Start.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557107/7c9e7bee-19ed-b202-0f9a-b66f0631f557.png">

- ConfigsタブにあるGenerateボタンを押下し、Xcodeプロジェクトの保存場所を指定すると生成が開始される

<img width="661" alt="Tulsi_Generate.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557107/68576854-fd14-9619-795d-76dc6bd1204f.png">


# Xcodeプロジェクトでビルド
さあ、macにiPhoneを繋げよう。そして、生成したXcodeプロジェクトを開き、ビルドを開始する。首を長くして待つと、ビルドが完了し、実機へインストールされる。

<img width="1440" alt="Xcode_handtrackinggpu.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557107/c742e374-ec90-8ede-6db7-1c86c69d6607.png">

デフォルトのカメラがフロントカメラなので、リアカメラを使用するように設定

```zsh:mediapipe/examples/ios/handtrackinggpu/ViewController.mm：107

_cameraSource.cameraPosition = AVCaptureDevicePositionFront;
　　　　　　　　　↓
_cameraSource.cameraPosition = AVCaptureDevicePositionBack;
```

左右が反転してしまったので、Mirroredの値を変更

```zsh:mediapipe/examples/ios/handtrackinggpu/ViewController.mm：111

_cameraSource.videoMirrored = YES;
　　　　　　　　　↓
_cameraSource.videoMirrored = NO;
```

# おわりに

iPhone上でリアルタイムなハンドトラッキングを高精度で実装することが出来た。

今後は、この技術を利用して視覚障害者向けの学習アプリケーションの開発に取り組んでいこうと思う。