web-dev-qa-db-ja.com

Camera2センサーとデバイスの向きを理解する

Android Camera2 を使用してタッチトゥフォーカス機能を実装しようとしているときに問題にぶつかりました。

理論は簡単です:

  • プレビューサーフェイスのタップ位置を取得する
  • センサーまたはセンサークロップエリア(ズームの場合)の寸法にマッピングし、必要に応じて寸法を反転させます。
  • 根拠の変更を適用して、センサーと同じ根拠になる
  • 結果からMeteringRectangleを作成し、新しいCaptureRequestで使用します

最初と最後のポイントを処理する方法を示す多くの例がありますが、2番目と3番目を理解できる方法で処理する例は多くありません。ドキュメントと例は明確ではなく、非常に混乱する可能性があります。

さあ行こう...


_CameraCharacteristics.SENSOR_ORIENTATION_は、

ネイティブの向きでデバイスの画面に垂直になるように出力画像を回転させる必要がある時計回りの角度。

センサー座標系が(0,0)がアクティブピクセルアレイの左上のピクセルで定義されていることを知っているので、センサー座標系でキャプチャされた画像を画像はネイティブの向きで直立します。したがって、センサーの上部がネイティブの縦向きで電話の右側を向いている場合、_SENSOR_ORIENTATION_は90°になります。 Sensor Orientation


mActivity.getWindowManager().getDefaultDisplay().getRotation();を介して取得した表示方向は、次のように文書化されています。

画面の回転を「自然な」方向から返します。返される値は、Surface.ROTATION_0(回転なし)、Surface.ROTATION_90、Surface.ROTATION_180、またはSurface.ROTATION_270です。たとえば、デバイスの画面が自然に高く、ユーザーが横向きにして横向きにした場合、ここで返される値は、デバイスが回転した方向に応じて、Surface.ROTATION_90またはSurface.ROTATION_270のいずれかになります。角度は、画面上に描画されたグラフィックの回転です。これは、デバイスの物理的な回転の反対方向です。たとえば、デバイスが反時計回りに90度回転した場合、レンダリングを補正するために時計回りに90度回転するため、ここで返される値はSurface.ROTATION_90になります。

この定義はセンサーの向きの定義よりもはるかに明確であり、解釈する場所がないことがわかりました。


物事が醜くなり始めるところ...

Camera2Raw の例で提供されているメソッドを使用して、センサーの向きからデバイスの向きへの回転を取得することにしました。

_/**
 * Rotation need to transform from the camera sensor orientation to the device's current
 * orientation.
 *
 * @param c                 the {@link CameraCharacteristics} to query for the camera sensor
 *                          orientation.
 * @param deviceOrientation the current device orientation relative to the native device
 *                          orientation.
 * @return the total rotation from the sensor orientation to the current device orientation.
 */
private static int sensorToDeviceRotation(CameraCharacteristics c, int deviceOrientation) {
    int sensorOrientation = c.get(CameraCharacteristics.SENSOR_ORIENTATION);

    // Get device orientation in degrees
    deviceOrientation = ORIENTATIONS.get(deviceOrientation);

    // Reverse device orientation for front-facing cameras
    if (c.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT) {
        deviceOrientation = -deviceOrientation;
    }

    // Calculate desired JPEG orientation relative to camera orientation to make
    // the image upright relative to the device orientation
    return (sensorOrientation + deviceOrientation + 360) % 360;
}
_

これは、ポートレートネイティブの向きの電話の背面カメラと前面カメラのさまざまな出力の表です。 enter image description here

最初に気づいたのは、説明されている出力(カメラセンサーの向きからデバイスの現在の向きへの回転)を考慮する場合、それが意味を持つためには、出力の回転を反時計回り(センサーの向きやデバイスの向きとは異なります)!!たとえば、典型的な90°センサーと0°のデバイスの向きを使用すると、結果は90°になり、分析で間違っていない場合は、反時計回りにしかなりません。

センサーとデバイスの向きに関する私の理解は正しい(それについては定かではない)という仮説の下で、90°センサーと90°デバイスの向きのケースを見ると、上記の表の結果に何か問題があるはずです、180°にすることはできません。0°にしてください。次の写真は、90度センサーオリエンテーションの電話での私の理解を視覚的に表したものです。 enter image description here

私は先に進み、Rに基本的な変更を実装しました2 画面ベースからセンサーベースにタップポイントを取得し、予想されるオフセットを追加します。

180°計算と0°計算を切り替えると、フォーカスするためのタッチが完全に機能することがわかりました。センサーから現在のデバイスの向きへの回転の正しい観測値は、実際にはフロントカメラのテーブルに対応しています。

だから私の直感は、sensorToDeviceRotationに欠陥があり、戻り値が次のようになるはずだということです。

_// Calculate desired JPEG orientation relative to camera orientation to make
// the image upright relative to the device orientation
return (sensorOrientation - deviceOrientation + 360) % 360;
_

計算されたものに関しては、実際にはより論理的です...

誰かがこれを確認できますか?または私はどこかで何かを誤解しましたか?

乾杯

20
Dude

はい、これはCamera2Rawのバグです。捕まえてくれてありがとう.

Camera#setDisplayOrientation のリファレンスドキュメントのサンプルコードを比較すると、期待する計算が表示されます。

...
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
     result = (info.orientation + degrees) % 360;
     result = (360 - result) % 360;  // compensate the mirror
} else {  // back-facing
     result = (info.orientation - degrees + 360) % 360;
}
4
Eddy Talvala