Android CameraX 似乎会针对特定的 PreviewView 尺寸略微裁剪分析图像
Android CameraX seems to crop analysis images slightly for specific PreviewView sizes
使用的依赖项:
implementation 'androidx.camera:camera-camera2:1.1.0-alpha04'
implementation 'androidx.camera:camera-lifecycle:1.1.0-alpha04'
implementation 'androidx.camera:camera-view:1.0.0-alpha24'
为简单起见,假设您使用的设备具有:
- 纵向默认方向
- 1080x1920 屏幕分辨率
ImageAnalysis
配置为使用 1080x1920 作为帧分析分辨率
当 PreviewView
的布局尺寸接近 1080x1920
和 FILL_CENTER
作为比例类型,
我们得到的分析框架与我们在 PreviewView
中看到的内容相同 - 没关系。
当我们的 PreviewView
变得更窄一点时,
例如 700x1920 - 它得到分析帧的裁剪部分:
左右画面的某些部分现在看起来被裁剪了 - 也没关系。
但是当我们改变 PreviewView
的尺寸使其看起来像横向时,
例如 - 到 1080x500 时出现问题。
我们的 PreviewView
使相机的帧看起来被裁剪了
从顶部和底部 - 没关系。
但不正常的是 - 我们的分析框架变得 实际上 被裁剪 略微
在左边和右边。
这意味着我希望在 PreviewView
和帧中看到相同的水平捕获边界
(因为由于缩放只裁剪了垂直部分),
但 PreviewView
实际上在其宽度上显示了更多一点
而不是相应的框架,所以看起来框架在水平方向上松动了大约 20px,
什么不应该发生,因为由于帧 (1080x1920) 和 PreviewView
(1080x500) 大小,
只应剪掉垂直部分。
附上插图:
有人在 CameraX 中遇到过相同的行为吗?
UPD:我是怎么发现这个的? - 通过将帧(图像)保存到文件。
帧缓冲区转换为 cv::Mat
s:
void nv21_buffer_to_bgr_mat(JNIEnv* env,
jbyteArray nv21_buffer,
jint width,
jint height,
cv::Mat& mat)
{
// To YUV.
jbyte* nv21_buffer_bytes = env->GetByteArrayElements(nv21_buffer, nullptr);
cv::Mat yuv(height + height / 2, width, CV_8UC1, nv21_buffer_bytes);
// To BGR.
cvtColor(yuv, mat, cv::COLOR_YUV2BGR_NV21, 3);
env->ReleaseByteArrayElements(nv21_buffer, nv21_buffer_bytes, 0);
}
UPD2:也许上述案例的布局检查器图像会有所帮助:
底层 camera2 API 在裁剪方面有一套相当严格的规则,关于如何使用多个输出分辨率。
SCALER_CROP_REGION(数字缩放)控件的文档对此有 useful diagrams;对于您的情况,假设 CROP_REGION 覆盖了整个活动数组。
最重要的是,CameraX PreviewView 对其输入应用了进一步的裁剪,因为相机设备本身只支持几种尺寸。因此 PreviewView 会选择一个具有合理纵横比的受支持分辨率,然后在显示时根据需要裁剪它以填充您的视图布局区域。
因此,ImageAnalysis 和 Preview 用例及其视野之间的关系取决于 CameraX 在底层为用例选择的分辨率,以及 PreviewView 的额外裁剪。
这里可能发生的情况是,您的横向 PreviewView 正在选择比 ImageAnalysis 正在选择的基础分辨率更宽。如果您拥有设备的开发人员访问权限,而您的应用是 运行,则您可以通过 adb shell dumpsys media.camera
检查实际选择的内容。该命令转储了很多信息,包括 CameraX 为相机设备配置的确切内容。
您可以尝试在 Preview.Builder 上使用 setTargetAspectRatio or the setTargetResolution 方法来匹配 ImageAnalysis 的纵横比;这应该确保 PreviewView 只是 ImageAnalysis 接收到的内容的一部分。
使用的依赖项:
implementation 'androidx.camera:camera-camera2:1.1.0-alpha04'
implementation 'androidx.camera:camera-lifecycle:1.1.0-alpha04'
implementation 'androidx.camera:camera-view:1.0.0-alpha24'
为简单起见,假设您使用的设备具有:
- 纵向默认方向
- 1080x1920 屏幕分辨率
ImageAnalysis
配置为使用 1080x1920 作为帧分析分辨率
当 PreviewView
的布局尺寸接近 1080x1920
和 FILL_CENTER
作为比例类型,
我们得到的分析框架与我们在 PreviewView
中看到的内容相同 - 没关系。
当我们的 PreviewView
变得更窄一点时,
例如 700x1920 - 它得到分析帧的裁剪部分:
左右画面的某些部分现在看起来被裁剪了 - 也没关系。
但是当我们改变 PreviewView
的尺寸使其看起来像横向时,
例如 - 到 1080x500 时出现问题。
我们的 PreviewView
使相机的帧看起来被裁剪了
从顶部和底部 - 没关系。
但不正常的是 - 我们的分析框架变得 实际上 被裁剪 略微
在左边和右边。
这意味着我希望在 PreviewView
和帧中看到相同的水平捕获边界
(因为由于缩放只裁剪了垂直部分),
但 PreviewView
实际上在其宽度上显示了更多一点
而不是相应的框架,所以看起来框架在水平方向上松动了大约 20px,
什么不应该发生,因为由于帧 (1080x1920) 和 PreviewView
(1080x500) 大小,
只应剪掉垂直部分。
附上插图:
有人在 CameraX 中遇到过相同的行为吗?
UPD:我是怎么发现这个的? - 通过将帧(图像)保存到文件。
帧缓冲区转换为 cv::Mat
s:
void nv21_buffer_to_bgr_mat(JNIEnv* env,
jbyteArray nv21_buffer,
jint width,
jint height,
cv::Mat& mat)
{
// To YUV.
jbyte* nv21_buffer_bytes = env->GetByteArrayElements(nv21_buffer, nullptr);
cv::Mat yuv(height + height / 2, width, CV_8UC1, nv21_buffer_bytes);
// To BGR.
cvtColor(yuv, mat, cv::COLOR_YUV2BGR_NV21, 3);
env->ReleaseByteArrayElements(nv21_buffer, nv21_buffer_bytes, 0);
}
UPD2:也许上述案例的布局检查器图像会有所帮助:
底层 camera2 API 在裁剪方面有一套相当严格的规则,关于如何使用多个输出分辨率。 SCALER_CROP_REGION(数字缩放)控件的文档对此有 useful diagrams;对于您的情况,假设 CROP_REGION 覆盖了整个活动数组。
最重要的是,CameraX PreviewView 对其输入应用了进一步的裁剪,因为相机设备本身只支持几种尺寸。因此 PreviewView 会选择一个具有合理纵横比的受支持分辨率,然后在显示时根据需要裁剪它以填充您的视图布局区域。
因此,ImageAnalysis 和 Preview 用例及其视野之间的关系取决于 CameraX 在底层为用例选择的分辨率,以及 PreviewView 的额外裁剪。
这里可能发生的情况是,您的横向 PreviewView 正在选择比 ImageAnalysis 正在选择的基础分辨率更宽。如果您拥有设备的开发人员访问权限,而您的应用是 运行,则您可以通过 adb shell dumpsys media.camera
检查实际选择的内容。该命令转储了很多信息,包括 CameraX 为相机设备配置的确切内容。
您可以尝试在 Preview.Builder 上使用 setTargetAspectRatio or the setTargetResolution 方法来匹配 ImageAnalysis 的纵横比;这应该确保 PreviewView 只是 ImageAnalysis 接收到的内容的一部分。