マルチカメラ時代のスマホで、「どの背面カメラが一番広角なのか?」を人力で探すのは面倒です。 widestfov は、端末の“いちばん広角な背面カメラ”を自動で選び、 できるだけクロップされないプレビューを表示することに特化したテストアプリです。
最近のスマホは、標準・超広角・望遠など複数の背面カメラを搭載しています。 しかしアプリ側で適切にカメラを選ばないと、 「論理カメラ」経由のクロップ済み映像しか出なかったり、 超広角レンズをうまく使えなかったりします。
widestfov では、Camera2 / CameraX から取得できる 焦点距離(focal length)とセンササイズなどの情報を列挙し、 「実効的にもっとも広い画角」を持つ背面カメラを自動選択します。 そのうえでプレビューのアスペクト比・スケーリングを調整し、 可能な限りセンサ全域に近い映像をそのまま表示することを目指しています。
Camera2 / CameraX からすべての背面カメラ情報を取得し、 FOV を計算したうえで「最も広角な物理カメラ」を選択。 選択結果を UI 上に表示しつつ、そのカメラをプレビューにバインドします。
CameraCharacteristics から取得できる LENS_INFO_AVAILABLE_FOCAL_LENGTHS と
SENSOR_INFO_PHYSICAL_SIZE を使い、
水平方向の画角を
FOV ≒ 2 × arctan((sensorWidth / 2) / focalLength)
として近似します。
この FOV が最大のものを「最も広角な背面カメラ」として選択します。
val sensorWidth = size.width
val f = focalLength
val fovRad = 2f * atan((sensorWidth / 2f) / f)
val fovDeg = fovRad * 180f / PI.toFloat()
近年の端末では、複数の物理カメラを束ねた「論理カメラ ID」が用意されています。 widestfov では、論理カメラ経由と物理カメラ ID 直指定の両方を試し、 実際にどれくらいクロップされるかを画面比較できるようにします。
端末によっては、「同じ ID でもズーム率で切り替わる」など挙動が異なるため、 実験ログを残すことで将来のアプリ設計の参考になります。
単に「大きい解像度」を選ぶだけでは、表示側のアスペクト比との違いから さらにクロップされてしまうことがあります。 widestfov では、センサの縦横比に近いプレビューサイズを優先し、 Letterbox を許容しても FOV を優先するかたちでパラメータを選びます。
val sensorAspect = sensorWidth / sensorHeight
val candidateSizes = streamConfig.getOutputSizes(SurfaceTexture::class.java)
val best = candidateSizes.minBy { size ->
abs(size.width.toFloat() / size.height - sensorAspect)
}
実際には、すべての端末がセンササイズや物理カメラ情報を きれいに公開しているわけではありません。 そのため、情報が足りない場合は 「最小焦点距離」ベースの簡易比較にフォールバックするなど、 現実的な妥協も組み込んでいます。
同じ端末で「標準カメラアプリ」と「widestfov」のプレビューを並べて比較し、 実際にどれくらい画角が広くなっているか、 どれくらいクロップが減っているかを目視で確認しました。
実験の結果、端末によっては 「超広角カメラの情報は公開されているが、Preview には選べない」 「論理カメラ経由だとズーム比によって物理カメラが切り替わる」 など、さまざまな挙動が確認できました。
・論理カメラ / 物理カメラの仕様が端末ごとにばらついている ・一部端末では、開発者向けには情報が見えても一般アプリからは選べないカメラがある ・プレビュー回転・アスペクト比の調整が複雑になりがちで、 UI レイアウトとの両立が難しい などの課題があります。
アプリ起動 → カメラ列挙 → FOV 計算 → 最も広角なカメラに自動切り替えされる様子を記録したデモ動画です。 画面上部には現在のカメラ ID や FOV、プレビュー解像度がオーバーレイ表示されます。
widestfov は、最終的なユーザー向けアプリというより、 自分がカメラアプリを書くときのための“観察ツール”という位置づけです。 端末ごとのカメラ ID・FOV・クロップ挙動を把握しておくことで、 将来のアプリで「最適なカメラ選択」ロジックを書くための知見を貯めています。
将来的には、収集したデータを元に 「このメーカーの端末ではこういうパターンが多い」 といったカメラ設計の傾向も分析してみたいと考えています。
カメラ選択ロジック・UI・端末ごとの検証フローを少しずつ整えていきます。
カメラアプリを書こうとするとき、 「とりあえず CameraX でプレビューが出れば OK」にしてしまいがちですが、 widestfov を作る中で、 端末側のカメラ設計をきちんと観察することの大切さを実感しました。
同時に、API 仕様書だけでは見えてこない「メーカーごとのクセ」も多く、 実際に動かしてログを取ることの重要性も強く感じています。 このアプリで得た知見は、今後のローバーやその他カメラアプリの設計に そのまま活きてくると考えています。