Camera2 で視野角 (画角) を取得するにはどうすればいいかというご質問を頂いたのでお答えします。
Camera.Parameters
の getHorizontalViewAngle()
や getVerticalViewAngle()
を使って簡単に角度が取得できた以前の Camera API とは違って、新しい Camera2 API では少し込み入った計算を行う必要がありますが、そのぶん柔軟性の高い対応が可能です。
説明
焦点距離を $f$ とし、センサーの物理寸法 (幅または高さ) を $d$ としたとき、視野角 $\alpha$ は以下の式で求めることができます。
\alpha = 2 \arctan \frac {d} {2 f}
焦点距離は CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS で取得できます。配列の形で返されますが、入っている要素は 1 つです。光学ズームをサポートしたカメラでは複数の要素が返されますが、現状そのようなデバイスは存在しません。
センサー全体の物理サイズは
CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE で取得できます。単位はミリメートルです。
画像処理を目的とする場合には必ずしも画素配列全体を利用するわけではありません。ほとんどのセンサーでは端に余分な画素があります。完全な領域は
CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE で取得できますが、画像 (写真) を生成する上で有効な領域は CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE で取得できます。
もし CaptureRequest.html.SCALER_CROP_REGION を使ってデジタル ズームを適用しているのであれば、それも勘案に入れる必要があります。
最後に、出力と切り取り領域のアスペクト比が一致しない場合は、FOV がさらに狭められている可能性があります。こちらのダイアグラムを参考にしてください。
例
以下のような CameraCharacteristics を持った端末を考えます。
焦点距離 = 3 mm
画素配列の物理サイズ = 3 x 2 mm
画素配列の画素数 = 3200 x 2132
有効な配列領域 = 上 100, 左 100, 幅 3000, 高さ 2000
切り取り領域 = 0, 0, 3000, 2000 (フルサイズ)
また、出力は以下に設定しているとします。
出力ストリーム = (1980, 1080) [1080p 16:9]
この 1080p 出力における、横と縦両方の FOV を求めるには、
出力のアスペクト比 = 16:9
切り取り領域のアスペクト比 = 3:2
16/9 > 3/2 なので 出力ストリームの面積を最大化するためには縦に切り取る必要があります。
出力ストリームの横方向の画素数 = 切り取り領域の幅 = 3000
出力ストリームの縦方向の画素数 = 「横」方向の画素数 / (16 / 9) = 1687
出力ストリームの横方向の物理サイズ = センサー幅 * 出力画素幅 / 画素配列幅 = 3 mm * 2667 / 3200 = 2.5 mm
出力ストリームの縦方向の物理サイズ = センサー高さ * 出力画素高さ / 画素配列高さ = 2mm * 200 / 2132 = 1.88 mm
よって
横 FOV = 2 * arctan (2.5 mm / (2 * 3 mm)) = 45.2 度
縦 FOV = 2 * arctan (1.88 mm / (2 * 3 mm)) = 34.8 度
以上です。