Camera2 APIでSensor.ORIENTATIONというパラメータがあります。長年、この意味が不明でした。最近ようやく理解が進んだので紹介します。
目次
Sensor.ORIENTATIONの出現
カメラのライブラリがAPI≧21でCamera⇒Camera2 APIに変更されました。その時、登場したのがSensor.ORIENTATIONというパラメータです。
このパラメータはAndroid端末に実装されたイメージセンサー毎の固有値で、CameraCharacteristicsクラスから取得できます。取得された値の単位は[度]です。いくつかのAndroid端末で調べてみたところ、90度と270度以外を見たことがありません。
マニュアルはSensor.ORIENTATIONを次のように説明しています。
---
デバイスが自然な向きの時、出力画像がスクリーン上で直立になるように、回転させるために必要な時計回りの角度。
最初、私にはさっぱり理解できませんでした。パラメータ名から推測してセンサーの向きなのは分かります。では、どのような向きななのか?!
理解するには「自然な向き」と「出力画像」の知識が必要です。
自然な向き
Sensor.ORIENTATIONを理解するには「自然な向き」の理解が必要です。
Androidデバイス
Androidデバイスはスマートフォーンという名前が表している通り電話機です。なので、電話を使うときの向きが「自然な向き」になります。
イメージセンサー
フィルムカメラは人の目に映る情景をフィルムに写し撮ります。デジタルカメラはイメージセンサーに写し撮ります。イメージセンサーはフィルムが置き換わったものです。なので、フィルムに合わせて横長に使うのが「自然な向き」になります。
横長に使うのは、人間の視野が上下に狭く左右に広いので、撮影された写真の範囲が自然で、見た目の違和感が少ないためだと思われます。
イメージセンサーの出力画像
Sensor.ORIENTATIONを理解するには「出力画像」の理解が必要です。
イメージセンサーが自然な向きの時で考えます。
レンズを通ってイメージセンサーへ到達した光はセンサー上に結像します。この時に結像した画像は図のように上下左右が反転します。
イメージセンサーは結像した画像をデジタル値に変換して、下から上に向かって行単位(ピンクの矢印)で読み出します。この読み出されたデジタル値が画像データです。
画像データはAndroidの内部で一枚の画像として扱われる時、左上を原点にした座標系(右をxの+、下をyの+)が用いられます。この座標系に従って、イメージセンサーから読み出した画像データを順番(ピンクの矢印)に並べたものが、イメージセンサーの出力画像です。
出力画像は黄色の矢印の向きに撮影対象を見た場合の情景です。
Sensor.ORIENTATION
90度
Sensor.ORIENTATIONを考える場合の前提条件は、Androidデバイスが「自然な向き」であることです。
図のように、イメージセンサ―がAndroidデバイスへ実装されているとします。この時、イメージセンサーの出力画像は、人物の頭が右に倒れた画像になります。人物の頭が上になる(これを直立といいます)ようにするには、画像を時計回りに90度回転させる必要があります。
これが、Sensor.ORIENTATION⇒90度の意味です。Androidデバイスが「自然な向き」のとき、図の向きにセンサーは実装されています。
270度
90度の場合と同様です。
人物の頭が上になるようにするには、画像を時計回りに270度回転させる必要があります。
これが、Sensor.ORIENTATION⇒270度の意味です。Androidデバイスが「自然な向き」のとき、図の向きにセンサーは実装されています。
市販のAndroid端末の値
Android端末のSensor.ORIENTATIONを調べてみました。
端末名 | Frontカメラ | Backカメラ |
---|---|---|
Huawei Y6 | 270 | 90 |
Nexus7(2013) | 270 | 90 |
Freetel REI2 Dual | 270 | 90 |
Nexus 5X | 270 | 270 |
Nexus 6P | 90 | 90 |
以前、Nexus 5Xでサードパーティ製のカメラアプリを使うと、プレビュー画像が上下反転するという騒動がありました。原因はイメージセンサーの実装の向きにあったようです。Nexus 5Xは筐体のスペースの関係で、今までの機種と異なる向きにイメージセンサーが実装されているという報告が上がっています。確かに、Sensor.ORIENTATIONが他の機種とは違う270度になっています。
Camera2 APIはSensor.ORIENTATIONの影響が補正された画像を出力します。たぶん、騒動の発端となったサードバーティ製のアプリはCamera API時代のアプリなのでしょう!
なぜ90度または270度なのか?
スマホで写真を撮るとき、スクリーンに映る画像(プレビュー画像)を見ながら撮ります。スマホのスクリーンは長方形です。より大きなプレビュー画像を映したければ、スクリーンとイメージセンサーの長辺を合わせるのが適しています。
そのため、長辺を合わせるように実装すると、Sensor.ORIENTATION=90度または270度になってしまいます。