widestfov で広角プレビューを表示している画面

widestfov – 端末の「いちばん広角な背面カメラ」を自動で選ぶテストアプリ

マルチカメラ時代のスマホで、「どの背面カメラが一番広角なのか?」を人力で探すのは面倒です。 widestfov は、端末の“いちばん広角な背面カメラ”を自動で選び、 できるだけクロップされないプレビューを表示することに特化したテストアプリです。

作品の説明

最近のスマホは、標準・超広角・望遠など複数の背面カメラを搭載しています。 しかしアプリ側で適切にカメラを選ばないと、 「論理カメラ」経由のクロップ済み映像しか出なかったり、 超広角レンズをうまく使えなかったりします。

widestfov では、Camera2 / CameraX から取得できる 焦点距離(focal length)とセンササイズなどの情報を列挙し、 「実効的にもっとも広い画角」を持つ背面カメラを自動選択します。 そのうえでプレビューのアスペクト比・スケーリングを調整し、 可能な限りセンサ全域に近い映像をそのまま表示することを目指しています。

  • ① CameraManager / CameraCharacteristics で背面カメラを列挙
  • ② 物理カメラごとの焦点距離・センササイズを取得
  • ③ 水平方向の FOV を概算し、最大のカメラを選択
  • ④ センサのアスペクト比に合わせて Preview サイズを決定
  • ⑤ SurfaceView / TextureView / Compose Preview にバインド
  • ⑥ 端末ごとのクロップ挙動を観察し、メモを残すためのデバッグオーバーレイを表示

システム概要

widestfov のシステム構成図

Camera2 / CameraX からすべての背面カメラ情報を取得し、 FOV を計算したうえで「最も広角な物理カメラ」を選択。 選択結果を UI 上に表示しつつ、そのカメラをプレビューにバインドします。

技術スタック

  • Android / Camera: Kotlin, Camera2 API / CameraX
  • Device Info: CameraCharacteristics, SCALER_STREAM_CONFIGURATION_MAP
  • Math: 焦点距離とセンササイズからの FOV 近似計算
  • UI: Jetpack Compose or View + TextureView / SurfaceView

主要コンポーネント

  • CameraEnumerator: 端末内のすべての背面カメラ ID を列挙し、物理カメラの特性を読み取るクラス。
  • FovCalculator: 焦点距離・センササイズから水平方向の FOV を近似計算し、ランキングするモジュール。
  • PreviewController: 選択されたカメラを用いて、アスペクト比・回転を考慮したプレビューをセットアップ。
  • DebugOverlay: 現在使用中のカメラ ID / FOV / 解像度 / クロップ率などを画面上に表示するオーバーレイ。

技術解説

FIELD OF VIEW

焦点距離とセンササイズから「広角度」を見積もる

CameraCharacteristics から取得できる LENS_INFO_AVAILABLE_FOCAL_LENGTHSSENSOR_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()
LOGICAL CAMERA

論理カメラと物理カメラの違いを観察する

近年の端末では、複数の物理カメラを束ねた「論理カメラ ID」が用意されています。 widestfov では、論理カメラ経由と物理カメラ ID 直指定の両方を試し、 実際にどれくらいクロップされるかを画面比較できるようにします。

端末によっては、「同じ ID でもズーム率で切り替わる」など挙動が異なるため、 実験ログを残すことで将来のアプリ設計の参考になります。

PREVIEW PIPELINE

できるだけクロップされないプレビューを作る

単に「大きい解像度」を選ぶだけでは、表示側のアスペクト比との違いから さらにクロップされてしまうことがあります。 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)
}
DEVICE VARIATION

端末ごとの「カメラ事情」と向き合う

実際には、すべての端末がセンササイズや物理カメラ情報を きれいに公開しているわけではありません。 そのため、情報が足りない場合は 「最小焦点距離」ベースの簡易比較にフォールバックするなど、 現実的な妥協も組み込んでいます。

実験・結果・課題

標準カメラ vs widestfov の比較

同じ端末で「標準カメラアプリ」と「widestfov」のプレビューを並べて比較し、 実際にどれくらい画角が広くなっているか、 どれくらいクロップが減っているかを目視で確認しました。

標準カメラアプリのプレビュー
(a) 標準カメラアプリ(想定図)
widestfov アプリのプレビュー
(b) widestfov のプレビュー(より広い画角)

端末間での挙動差

実験の結果、端末によっては 「超広角カメラの情報は公開されているが、Preview には選べない」 「論理カメラ経由だとズーム比によって物理カメラが切り替わる」 など、さまざまな挙動が確認できました。

端末 A: 超広角プレビュー取得成功 端末 B: 超広角 ID がユーザーアプリから使用不可

現在の課題

・論理カメラ / 物理カメラの仕様が端末ごとにばらついている ・一部端末では、開発者向けには情報が見えても一般アプリからは選べないカメラがある ・プレビュー回転・アスペクト比の調整が複雑になりがちで、  UI レイアウトとの両立が難しい などの課題があります。

すべての端末で超広角が使えるわけではない Device ごとの挙動メモを蓄積中

デモ動画

アプリ起動 → カメラ列挙 → FOV 計算 → 最も広角なカメラに自動切り替えされる様子を記録したデモ動画です。 画面上部には現在のカメラ ID や FOV、プレビュー解像度がオーバーレイ表示されます。

widestfov – 自動で「いちばん広角」なカメラに切り替えるデモ

まだできていない部分と今後

「カメラ選択のチートシート」として活かしたい

widestfov は、最終的なユーザー向けアプリというより、 自分がカメラアプリを書くときのための“観察ツール”という位置づけです。 端末ごとのカメラ ID・FOV・クロップ挙動を把握しておくことで、 将来のアプリで「最適なカメラ選択」ロジックを書くための知見を貯めています。

将来的には、収集したデータを元に 「このメーカーの端末ではこういうパターンが多い」 といったカメラ設計の傾向も分析してみたいと考えています。

  • 短期: 手元の複数端末で挙動を確認し、カメラマップを作る。
  • 中期: 他のカメラ系アプリ(CanSat ローバーなど)に選択ロジックを移植。
  • 長期: Device ごとのカメラ特性データベースを整備し、 オープンな資料として公開することも検討。

これからの改善点と開発計画

カメラ選択ロジック・UI・端末ごとの検証フローを少しずつ整えていきます。

  • ロジック: FOV 計算の安定化、端末差に対するフォールバック戦略。
  • UI: プレビュー倍率・クロップ率を視覚化するオーバーレイ。
  • 実験: メーカー・シリーズごとのカメラ ID パターンの収集。
17
18
19
20
21
22
23
24
25
26
27
28
29
30
FOV 計算・フォールバック処理の整理
デバッグオーバーレイ UI の強化
複数端末での検証・カメラマップ作成

このプロジェクトを通して

感じていること

カメラアプリを書こうとするとき、 「とりあえず CameraX でプレビューが出れば OK」にしてしまいがちですが、 widestfov を作る中で、 端末側のカメラ設計をきちんと観察することの大切さを実感しました。

同時に、API 仕様書だけでは見えてこない「メーカーごとのクセ」も多く、 実際に動かしてログを取ることの重要性も強く感じています。 このアプリで得た知見は、今後のローバーやその他カメラアプリの設計に そのまま活きてくると考えています。

今の自分へのメモ

  • ・仕様書を読むだけでなく、必ず 2〜3 台は実機で検証する。
  • ・「よくわからない挙動」もちゃんとスクショとメモで残しておく。

リファレンス & リンク

リファレンス

  • Android Developers – Camera2 API / CameraCharacteristics
  • Android Developers – CameraX CameraSelector / UseCase
  • 一般的な写真光学の教科書(画角と焦点距離の関係)

リンク