Camera2理解传感器和设备方向

33

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

理论很简单:

  • 获取预览表面上的点击位置
  • 将其映射到传感器或传感器裁剪区域(如缩放)的尺寸,并确保在需要时反转尺寸
  • 应用一个基础变换以最终处于与传感器相同的基础上
  • 从结果中制作一个 MeteringRectangle 并在新的 CaptureRequest 中使用它

已经有很多例子展示了如何处理第一个和最后一个步骤,但是很少有例子能够明确地解释第二个和第三个步骤。文档和例子并不太清晰,可能会让人感到困惑。


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

我继续在R2中实现了我的基础变换,将触摸点从屏幕基准转换为传感器基准,并添加了预期的偏移量。

我发现,如果我交换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;

从计算的角度来看,这样做实际上更合乎逻辑...

有人可以确认一下吗?或者我哪里理解错了吗?

谢谢

1个回答

9

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

1
我注意到Camera2Raw计算方向的方式似乎基于JPEG_ORIENTATION文档中的示例代码。这是否意味着文档中的示例也是错误的? https://developer.android.com/reference/android/hardware/camera2/CaptureResult.html#JPEG_ORIENTATION - PerracoLabs
我确实看过那段代码,但因为如果我绘制前置和后置相机的结果(表格不只是交换了),它并不会给出相同的结果,所以我不能假设我是正确的。顺便说一下,前置摄像头的行为很奇怪,当我旋转屏幕时,预览是倒置的。我还没有深入研究,所以我不能告诉你更多,但可能与此有关。 - Dude

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接