我想实现标准的用户体验,在预览中点击一个点,以将自动对焦和自动曝光点调整到他们点击的位置。我找到了 Preview.focus() 函数,但是它说它需要“传感器坐标系”中的尺寸,我假设它与 TextureView 的 TouchEvent 像素坐标不同。
如何从 TextureView 预览的触摸坐标转换为 Preview.focus() 预期的“传感器坐标框架”?
如果这个示例是示例代码的一部分,那就太好了,因为它似乎是一个几乎每个人都会期望的非常常见的用例。
我想实现标准的用户体验,在预览中点击一个点,以将自动对焦和自动曝光点调整到他们点击的位置。我找到了 Preview.focus() 函数,但是它说它需要“传感器坐标系”中的尺寸,我假设它与 TextureView 的 TouchEvent 像素坐标不同。
如何从 TextureView 预览的触摸坐标转换为 Preview.focus() 预期的“传感器坐标框架”?
如果这个示例是示例代码的一部分,那就太好了,因为它似乎是一个几乎每个人都会期望的非常常见的用例。
TextureView 的坐标与传感器坐标不同。请参考此处的示例代码(请注意,“CameraView”尚未在 maven 存储库中公开,因此我们不鼓励您现在使用它)。我们知道这些工作量很大,因此 CameraX 团队也在开发对开发人员更友好的对焦/测光 API 版本。
基本流程如下: (1) 从视图触摸事件中获取 x, y。(2) 使用设备方向和camera2 CameraCharacteristics.SENSOR_ORIENTATION计算相对相机方向。该值表示传感器图像在当前设备方向上需要旋转到直立的顺时针角度。
(3) 将 x, y 交换为 90 / 270 度,并通过方向适当地反转 x, y。反转 x 以进行镜像(前置摄像头) (4) 使用 CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE 转换为传感器坐标,查看宽度/高度。
注意:对于相机 ID,现在您可以在 mCameraManager.getCameraIdList() 中找到第一个 camera_id 并具有正确的镜头朝向。但是算法可以改变。
这篇由 Google 工程师撰写的博客文章准确地解释了如何做到这一点(在 Kotlin 中)。
这是在 Java 中实现相同的方法:
private void setUpTapToFocus() {
textureView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_UP) {
/* Original post returns false here, but in my experience this makes
onTouch not being triggered for ACTION_UP event */
return true;
}
TextureViewMeteringPointFactory factory = new TextureViewMeteringPointFactory(textureView);
MeteringPoint point = factory.createPoint(event.getX(), event.getY());
FocusMeteringAction action = FocusMeteringAction.Builder.from(point).build();
cameraControl.startFocusAndMetering(action);
return true;
}
});
}
cameraControl
对象可以这样实例化:
CameraControl cameraControl = CameraX.getCameraControl(CameraX.LensFacing.BACK);
但要确保你有
implementation "androidx.camera:camera-view:1.0.0-alpha03"
在您的build.gradle
依赖项中。
作为参考,这里是来自Husayn Hakeem 博客文章的原始 Kotlin 代码:
private fun setUpTapToFocus() {
textureView.setOnTouchListener { _, event ->
if (event.action != MotionEvent.ACTION_UP) {
return@setOnTouchListener false
}
val factory = TextureViewMeteringPointFactory(textureView)
val point = factory.createPoint(event.x, event.y)
val action = FocusMeteringAction.Builder.from(point).build()
cameraControl.startFocusAndMetering(action)
return@setOnTouchListener true
}
}
如今,这可以很容易地使用LifecycleCameraController.setController(cameraController)
.
从文档中:
设置后,控制器将使用 PreviewView 显示相机预览提要。它还使用 PreviewView 的布局尺寸为所有用例设置裁剪矩形,以便其他用例的输出与最终用户在 PreviewView 中看到的相匹配。它还支持点击对焦和捏合缩放等功能。
这是一个关于如何使用它的简短示例(我使用的是 Kotlin,但在 Java 中也是如此)。
fun startCamera(
context: Context,
lifecycleOwner: LifecycleOwner,
previewView: PreviewView
): LifecycleCameraController {
//create camera instance
val cameraController = LifecycleCameraController(context)
//start camera
cameraController.bindToLifecycle(lifecycleOwner)
//enable camera preview feed and features like tap-to-focus and pinch-to-zoom
previewView.controller = cameraController
return cameraController
//...
//cameraController.takePicture(OutputFileOptions, Executor, OnImageSavedCallback) //take picture
//cameraController.unbind() //close camera
}