iOS のカメラアプリでズーム機能を実装する。標準カメラへの切り替え方法も

QRefineというQRコード読み取りアプリを作っています。
QRefineでズーム機能を実装してほしいという要望があったので先日実装を入れたのですが、iOSのカメラのズーム機能の実装で結構詰まる部分があったので実装したコード踏まえて書いておきます。
TL;DR
- スライダーなどの UI を使ってズーム機能を実装するのに便利な関数 ramp(toVideoZoomFactor:withRate:) があり、これを使うと便利
- ただし指定するズームの設定値
videoZoomFactor
は最大画角からの倍率を示した相対値であり、一般的なズーム倍率 x倍とかの値とは異なるので注意が必要
- ただし指定するズームの設定値
- 超広角レンズを搭載したカメラでズーム機能を実装する場合、標準カメラを使うためのズーム設定値は virtualDeviceSwitchOverVideoZoomFactorsを使って調べることができそう
動作確認環境
- iOS 16.6
- iPhone 13 Pro
実装方法
サンプルは GitHub にあげてますのでそちら参照ください。
このような、スライダーでズームを制御できるカメラアプリになっています。
かいつまんでポイント説明していきます。
カメラの初期化
カメラデバイスの準備は、AVCaptureDevice.DiscoverySession
関数で行います。
この関数では事前に受け入れることができるカメラの種別を指定することができます。
1 2 3 4 5 6 |
let deviceTypes: [AVCaptureDevice.DeviceType] = [.builtInTripleCamera, .builtInDualWideCamera, .builtInDualCamera, .builtInWideAngleCamera] let mediaType: AVMediaType = .video device = AVCaptureDevice.DiscoverySession(deviceTypes: deviceTypes, mediaType: mediaType, position: .back).devices.first |
ここで指定できる AVCaptureDevice.builtInTripleCamera などの識別子は、物理的に単一のカメラデバイスを指しているわけではなく、複数のカメラデバイスをズーム倍率等で切り替えれることを示すものです。
.builtInTripleCamera
の場合だと、デバイスの種類としては .builtInUltraWideCamera(超広角カメラ)、 .builtInWideAngleCamera(広角カメラ)、.builtInTelephotoCamera(望遠カメラ)の3種類をズーム等の設定値によって切り替えれる仮想的なデバイスを使うという意味になっています。
こらら3つのカメラをズーム倍率等で切り替えて使ってくれるわけですが、ズーム倍率がいくつになったら望遠カメラを使う、といったカメラの切り替えの処理をアプリ側で記述しなくてもいいので、その点便利かなと思います。
ちなみに標準的な背面カメラは .builtInWideAngleCamera
のことかと。
ズームの設定方法
そのズームの設定についてですが、実際の API としては ramp(toVideoZoomFactor:withRate:) になります。
またはアニメーションしない場合は、videoZoomFactor に設定することになります。
ただし、ここで使用している設定値 videoZoomFactor
はよくいうズーム倍率x倍とかの値とは違う、相対的なものになるということに注意が必要です。
videoZoomFactor
の API リファレンスを見ると詳細が書いてありますが、この値は最大画角からの相対的な倍率を示すもののようです。
最小の 1.0 で、最大画角になるようです。
最大については、AVCaptureDevice#maxAvailableVideoZoomFactor で調べることができます。
また、videoZoomFactor
でどういう値を設定すると物理的なカメラが切り替わるかは、AVCaptureDevice#virtualDeviceSwitchOverVideoZoomFactors で調べることができます。APIの説明に書いてある通り、このAPIでは AVCaptureDevice#continuentDevices の各デバイスが切り替わる時の値を確認することができるようになっています。
わたしの手持ちの端末 iPhone 13Pro で試したところ、下記のような結果が得られました。
項目 | 値 |
---|---|
maxAvailableVideoZoomFactor | 123.75 |
virtualDeviceSwitchOverVideoZoomFactors | [2, 6] |
この状況を図示すると、下記のような感じになるかと。
注意点として、この環境だとvideoZoomFactorの初期値は最小値の1になっていました。つまり、何も設定しないと超広角カメラが使われる状態になっていました。
ズーム設定ができるカメラアプリで、標準カメラを使う場合
上述の通り、videoZoomFactor
を何も設定しないとデフォルトで超広角カメラが使われる状態でしたが、標準カメラを使いたい場合は下記のようなコードで超広角カメラから切り替わる時の videoZoomFactor
の値を調べてセットしてあげると良いかと思います。
1 2 3 4 5 6 7 8 9 10 |
standardZoomFactor = 1 for (index, actualDevice) in device.constituentDevices.enumerated() { if (actualDevice.deviceType != .builtInUltraWideCamera) { if index > 0 && index <= device.virtualDeviceSwitchOverVideoZoomFactors.count { standardZoomFactor = CGFloat(truncating: device.virtualDeviceSwitchOverVideoZoomFactors[index - 1]) } break } } |
私の環境だとこの時の standardZoomFactor
は 2 だったので、2 を設定したところ、標準のカメラに切り替わってズームの倍率も 1 倍になっていました。
ちなみに 1 倍の確認方法としては、iOSの標準カメラアプリで 1 倍 を指定して撮影した内容を見比べて同じ画角になっているということで確認しました。
まとめ
QRefine でズーム機能を実装した時の標準カメラ選択の実装部分をサンプルを使って解説しました。
実際には QRefine の QRコード読み取り部分は mobile_scanner という Flutter のパッケージを使っているのですが、最初にこのパッケージを使った時は超広角カメラの読み取りになってしまっており、issueもあがっておりました。
いろいろ調べたところ上記のような標準カメラに切り替える設定必要とわかったので、PR を出してマージしてもらったという経緯があります。
せっかく頑張って実装したので、また同じように実装で苦労したところがブログで紹介したいと思います。
最後まで読んでいただきありがとうございます。 このブログを「いいな」と感じていただけましたら、Twiter にてフォローいただけるとうれしいです。ブログ更新情報などもお届けします。
Follow @ryuta461
この記事をシェアする