Camera2 了解传感器和设备方向

Camera2 understanding the sensor and device orientations

我在尝试使用 Android Camera2 实现触摸对焦功能时遇到了问题。

理论很简单:

有很多例子展示了如何处理第一点和最后一点,但以可理解的方式处理第二点和第三点的例子并不多。文档和示例不是很清楚,可能真的很混乱。

我们开始...


CameraCharacteristics.SENSOR_ORIENTATION 描述为

Clockwise angle through which the output image needs to be rotated to be upright on the device screen in its native orientation.

知道传感器坐标系定义为 (0,0) 是活动像素阵列中左上角的像素,我将其解读为旋转在传感器坐标系中捕获的图像所需的角度 到使图像在原始方向上看起来直立的位置。因此,如果传感器的顶部面向 phone 的右侧,并且具有纵向原生方向,则 SENSOR_ORIENTATION 将为 90°。


通过mActivity.getWindowManager().getDefaultDisplay().getRotation();获得的显示方向记录为:

Returns the rotation of the screen from its "natural" orientation. The returned value may be Surface.ROTATION_0 (no rotation), Surface.ROTATION_90, Surface.ROTATION_180, or Surface.ROTATION_270. For example, if a device has a naturally tall screen, and the user has turned it on its side to go into a landscape orientation, the value returned here may be either Surface.ROTATION_90 or Surface.ROTATION_270 depending on the direction it was turned. The angle is the rotation of the drawn graphics on the screen, which is the opposite direction of the physical rotation of the device. For example, if the device is rotated 90 degrees counter-clockwise, to compensate rendering will be rotated by 90 degrees clockwise and thus the returned value here will be Surface.ROTATION_90.

我觉得这个定义比sensor orientation的定义清楚多了,没有解释的地方。


现在事情开始变得丑陋了...

我决定利用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;
}

这里是table phone 纵向原生方向的后置和前置摄像头的不同输出。

我注意到的第一件事是,如果我考虑所描述的输出(从相机传感器方向到设备当前方向的旋转), 为了有意义,我必须考虑输出旋转 逆时针 (不同于传感器方向和设备方向)!! 例如,如果我们采用典型的 90° 传感器和 0° 设备方向,结果是 90°,如果我的分析没有弄错的话,它只能是逆时针。

假设我对传感器和设备方向的理解是正确的(对此不确定),那么上述 tables 的结果一定有问题,因为如果你看90° 传感器和 90° 设备方向情况下,它不能是 180°,应该是 0°。 下一张图片是我对 90° 传感器方向所有这些的理解的直观表示 phone。

我继续在 R2 中实施我的基础更改,以将我的点击点从屏幕基础变为传感器基础,并添加预期的偏移量。

我观察到,如果我切换 180° 和 0° 计算,那么我的触摸对焦效果很好。从传感器到当前设备方向的旋转的正确观测值实际上对应于前置摄像头的 table。

所以我的直觉是 sensorToDeviceRotation 有缺陷,return 值应该是:

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

就计算的内容而言实际上更合乎逻辑...

有人可以证实吗?还是我误解了什么地方?

干杯

是的,这是 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;
}