ARKitにおけるカメラの解像度とフレームレート

## ARKitにおける動画キャプチャフォーマットのコンフィギュレーション

ARKit 1.5というと、「ついに垂直平面も認識できるようになった！」という新機能が目立ちがちでしたが、もともとARKitが平面推定に用いている特徴点群へアクセスするAPIはあったので、[ARKit 1.0の頃から垂直平面を推定することは可能](https://qiita.com/rakusan/items/8e3ba031acb31fd7a26c)ではありました。

しかし**サードパーティ開発者がどうやっても乗り越えられなかった壁**が、「解像度・フレームレートの変更」です。1.0時点ではこれらを変えるAPIは用意されておらず、AV Foundationのカメラ入力とARKitとを併用することもできませんでした。とくにキャプチャされるフレーム画像の解像度は**1280 x 720**と低く、iPhone 7（4.7インチ）や7 Plus（5.5インチ）のスクリーンで見ると普通に少しボケてましたし、`ARFrame`から取得したフレームごとの画像データを保存してアレコレしようとしてもコンテンツとしては解像度が物足りないということもありました。

## ARConfiguration.VideoFormat

そこにARKit 1.5/iOS 11.3で追加されたのが`ARConfiguration.VideoFormat`というクラスです。`var framesPerSecond: Int`（フレームレート）と`var imageResolution: CGSize`（画像解像度）という２つのプロパティを持つシンプルなクラスです。

`ARConfiguration`プロトコルに`videoFormat`という`ARConfiguration.VideoFormat`型のプロパティが用意されており、ここに使用したい動画フォーマットをセットすることができます。

```swift
var videoFormat: ARConfiguration.VideoFormat { get set }
```

https://developer.apple.com/documentation/arkit/arconfiguration/videoformat

## supportedVideoFormats

ただし、`ARConfiguration.VideoFormat`のフォーマットを適当につくってセットできるわけではありません。使用可能なフォーマットは以下の条件で変わってきます。

- `ARConfiguration`の種類
- デバイスの種類
- iOSバージョン

> Different devices and iOS versions offer different sets of supported video formats

https://developer.apple.com/documentation/arkit/arconfiguration/2942261-supportedvideoformats


使用可能なフォーマットの一覧は、次のクラスプロパティで取得できます。

```swift
class var supportedVideoFormats: [ARConfiguration.VideoFormat] { get }
```

このプロパティには、`ARConfiguration`という抽象クラスからアクセスすることはできません。`ARConfiguration.supportedVideoFormats`とすると、実行時に次のようなエラーになります。

> *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Supported video formats should be called on individual configuration class.'

`ARWorldTrackingConfiguration`のような、具象クラスからアクセスします。

```swift
print(ARWorldTrackingConfiguration.supportedVideoFormats)
```

ARセッションの動画キャプチャフォーマットを変更するには、`supportedVideoFormats`から得られる配列に入っているフォーマットのうちひとつを選び、ARコンフィギュレーションオブジェクトの`videoFormat`にセットします。

```swift
configuration.videoFormat = selectedVideoFormat
```


## iPhone Xで利用可能なフォーマット一覧

現時点（iOS 12.0）で利用可能な5つのコンフィギュレーションクラスについて、iPhone X/iOS 12.0で出力した`supportedVideoFormats`を表にしてみました。

| Configuration | Resolution | fps |
| :---- | :----: | ----: |
| `ARWorldTrackingConfiguration` | (1920.0, 1440.0) | 60 |
|  | (1920.0, 1080.0) | 60 |
|  | (1280.0, 720.0) | 60 |
| `AROrientationTrackingConfiguration` | (1920.0, 1440.0) | 60 |
|  | (1920.0, 1080.0) | 60 |
|  | (1280.0, 720.0) | 60 |
| `ARImageTrackingConfiguration` | (1920.0, 1440.0) | 60 |
|  | (1920.0, 1080.0) | 60 |
|  | (1280.0, 720.0) | 60 |
| `ARObjectScanningConfiguration` | (1920.0, 1440.0) | 60 |
|  | (1920.0, 1080.0) | 60 |
|  | (1280.0, 720.0) | 60 |
| `ARFaceTrackingConfiguration` | (1280.0, 720.0) | 60 |
|  | (1280.0, 720.0) | 30 |

フロントカメラを使う`ARFaceTrackingConfiguration`以外、つまり**リアカメラを使うコンフィギュレーションはどれも動画フォーマットの選択肢は同じ**、という結果になりました。フレームレートはいずれも60 fpsで、実質変更できないようです。

`ARFaceTrackingConfiguration`については、解像度は1パターン、fpsが2種類、という結果になりました。

## iPhone 7 Plusで利用可能なフォーマット一覧

コンフィギュレーションタイプ以外に、デバイス、iOSバージョンによっても利用可能なフォーマットは変わるとのことで、手元のiPhone 7 Plus/iOS 11.4.1でも試してみました。

| Configuration | Resolution | fps |
| :---- | :----: | ----: |
| `ARWorldTrackingConfiguration` | (1920.0, 1080.0) | 60 |
|  | (1280.0, 720.0) | 60 |
| `AROrientationTrackingConfiguration` | (1920.0, 1080.0) | 60 |
|  | (1280.0, 720.0) | 60 |
| `ARImageTrackingConfiguration` [^2] | - |- |
| `ARObjectScanningConfiguration` [^2] | - | - |
| `ARFaceTrackingConfiguration` [^3] | - | - |

[^2]: iOS 11.xなので利用不可
[^3]: iPhone 7 Plusなので利用不可

実行前の予想は「実は変わらないんじゃないの」と思ってましたが、変わりました。**解像度(1920.0, 1440.0)のフォーマットは利用できない**ようです。デバイスがiPhone Xだと利用できるのか、iOSバージョンが12以上だと利用できるのかは、手元にiPhone X/iOS 11またはiPhone 7/iOS 12がないのでわかりません。。

## iPhone 12 Proで利用可能なフォーマット一覧（2020.12.23追記）

iPhone 12 Pro/iOS 14.3で出力した`supportedVideoFormats`を表にしてみました。

| Configuration | Resolution | fps |
| :---- | :----: | ----: |
| `ARWorldTrackingConfiguration` | (1920.0, 1440.0) | 60 |
|  | (1920.0, 1080.0) | 60 |
|  | (1280.0, 720.0) | 60 |
| `AROrientationTrackingConfiguration` | (1920.0, 1440.0) | 60 |
|  | (1920.0, 1080.0) | 60 |
|  | (1280.0, 720.0) | 60 |
| `ARImageTrackingConfiguration` | (1920.0, 1440.0) | 60 |
|  | (1920.0, 1080.0) | 60 |
|  | (1280.0, 720.0) | 60 |
| `ARObjectScanningConfiguration` | (1920.0, 1440.0) | 60 |
|  | (1920.0, 1080.0) | 60 |
|  | (1280.0, 720.0) | 60 |
| `ARFaceTrackingConfiguration` | (1440.0, 1080.0) | 60 |
|  | (1440.0, 1080.0) | 30 |
|  | (1280.0, 720.0) | 60 |
|  | (1280.0, 720.0) | 30 |

`ARFaceTrackingConfiguration`に解像度が高いフォーマットが追加されています。

## iPhone 15 Proで利用可能なフォーマット一覧（2023.11.4追記）

iPhone 15 Pro/iOS 17.1で出力した`supportedVideoFormats`を表にしてみました。

| Configuration | Resolution | fps | HDR |
| :---- | :----: | ----: | :---: |
| `ARWorldTrackingConfiguration` | (1920.0, 1440.0) | 60 / 30 | ◎ |
|  | (1920.0, 1080.0) | 60 / 30 | ◎ |
|  | (1280.0, 720.0) | 60 / 30 | ◎ |
|  | (3240.0, 2160.0) | 30 | ◯ |
| `AROrientationTrackingConfiguration` | (1920.0, 1440.0) | 60 / 30 | ◎ |
|  | (1920.0, 1080.0) | 60 / 30 | ◎ |
|  | (1280.0, 720.0) | 60 / 30 | ◎ |
|  | (3240.0, 2160.0) | 30 | ◯ |
| `ARImageTrackingConfiguration` | (1920.0, 1440.0) | 60 / 30 | ◎ |
|  | (1920.0, 1080.0) | 60 / 30 | ◎ |
|  | (1280.0, 720.0) | 60 / 30 | ◎ |
|  | (3240.0, 2160.0) | 30 | ◯ |
| `ARBodyTrackingConfiguration` | (1920.0, 1440.0) | 60 / 30 | ◎ |
|  | (1920.0, 1080.0) | 60 / 30 | ◎ |
|  | (1280.0, 720.0) | 60 / 30 | ◎ |
|  | (3240.0, 2160.0) | 30 | ◯ |
| `ARObjectScanningConfiguration` | (1920.0, 1440.0) | 60 / 30 | ◎ |
|  | (1920.0, 1080.0) | 60 / 30 | ◎ |
|  | (1280.0, 720.0) | 60 / 30 | ◎ |
| `ARFaceTrackingConfiguration` | (1440.0, 1080.0) | 60 / 30 | ◯ |
|  | (1280.0, 720.0) | 60 / 30 | ◯ |
| `ARPositionalTrackingConfiguration` | (640.0, 480.0) | 10 | ✕ |

多くの点で更新があります。

- `3240x2160` の高解像度のビデオフォーマットが追加された。
- ほとんどの解像度で60 fpt / 30 fps両方が利用可能になった。
- iOS 16で `isVideoHDRSupported` が追加された。
    - HDRの項目が ◎ のものは、HDR対応・非対応両方のビデオフォーマットが利用可能。
    - HDRの項目が ◯ のものは、HDR対応のビデオフォーマットだけが利用可能。
    - HDRの項目が ✕ のものは、HDR非対応のビデオフォーマットだけが利用可能。

## どう使い分けるのか？

`supportedVideoFormat`で得られる`ARConfiguration.VideoFormat`の配列は、**品質の高い順**に並んでいます。

> the order of this array always puts higher-quality formats before lower-quality formats. 

そしてデフォルトでは、配列の先頭にある動画キャプチャフォーマットがコンフィギュレーションにセットされています。つまり、**デフォルトではもっとも高品質なフォーマットが使われている**わけです。

> By default, the videoFormat property for a new session configuration matches the first video capture format in this array. 

つまり本APIの（現在の設定をgetする以外の）用途としては、あえて低い解像度や低いフレームレートにしたいケース、ということになります。UIやキャプチャした動画データのPre/Post処理でGPU負荷の高い処理をしたい場合等に必要になってくるかもしれません。