原文地址:magdamiu.com/2020/08/10/…
作者:MAGDA MIU
在我之前关于CameraX的文章中,我介绍了使用最古老的Camera API所面临的挑战,以及使用这个新API的优势。
用例驱动的方法是使用CameraX最重要的优势之一。UseCase是一个抽象类,目前它支持3个实现,每个用例是完全独立的。我们可以只使用其中一个,也可以将它们结合起来。
预览用例
使用表面显示摄像机的实时馈送。
对于每个用例,首先我们将检查实现步骤,然后检查每个步骤的分配代码。
步骤1:添加gradle依赖项
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
def camerax = "1.0.0-beta07"
implementation "androidx.camera:camera-camera2:${camerax}"
implementation "androidx.camera:camera-lifecycle:${camerax}"
implementation 'androidx.camera:camera-view:1.0.0-alpha11'
implementation 'androidx.camera:camera-extensions:1.0.0-alpha11'
步骤2:权限处理
// manifest
<uses–feature android:name="android.hardware.camera.any" />
<uses–permission android:name="android.permission.CAMERA" />
// fragment or activity
if (areAllPermissionsGranted()) {
startCamera()
} else {
ActivityCompat.requestPermissions(
this, PERMISSIONS, CAMERA_REQUEST_PERMISSION_CODE)
}
-
添加android.hardware.camera.any确保设备有摄像头。指定. any意味着它可以是前置摄像头或后置摄像头。
-
如果我们使用没有**. any的android.hardware.camera**,如果你有一个没有后置摄像头的设备,比如大多数Chromebook,它就无法工作。第二行添加了访问该摄像机的权限。
步骤3:在布局中添加Preview View
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.camera.view.PreviewView
android:id="@+id/preview"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</androidx.camera.view.PreviewView>
</FrameLayout>
-
自测试版发布以来,Preview View是实现相机预览的推荐方式。
-
如果你想使用你自己的曲面(例如,纹理视图),那么你必须实现你自己的曲面提供程序,以及确保你处理适当的大小和方向,这可能很棘手。
幕后发生了什么?
-
Preview View是一个自定义视图,用于显示CameraX预览用例的相机馈送。
-
Preview View还扩展了Frame Layout,我们都知道它是一个View Group。
-
默认实现是Surface View。
-
但是如果相机设备运行在向后兼容模式下,在代码中这意味着设备具有支持的相机硬件级别相机特性#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,实际实现模式将是纹理视图。
val previewView = findViewById(R.id.preview)
// initialize the Preview object (current use case)
val preview = Preview.Builder().build()
为了在初始化CameraX时进行精细控制,我们可以实现CameraX Config。应用程序类中的提供程序接口。
步骤4:创建Process Camera Provider的实例
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
// used to bind the lifecycle of camera to the lifecycle owner
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// add a listener to the cameraProviderFuture
val cameraExecutor = ContextCompat.getMainExecutor(this)
cameraProviderFuture.addListener(Runnable {}, cameraExecutor)
-
Process Camera Provider是一个单例,可用于将相机的生命周期绑定到应用程序流程中的任何Life cle Owner。
-
进程中只能存在单个进程摄像机提供程序,并且可以使用*get Instance(*Context)检索它。
-
它帮助我们不用担心打开和关闭相机,因为CameraX是生命周期感知的。
-
是一个运行在主线程上的执行器。
-
将监听器添加到包含2个参数: Runna ble和执行程序的Cameron Provider Future。
步骤5:选择Camera并将其绑定到生命周期
val backCamera = CameraSelector.LENS_FACING_BACK;
val frontCamera = CameraSelector.LENS_FACING_FRONT;
val cameraSelector = CameraSelector.Builder().requireLensFacing(backCamera).build()
cameraProviderFuture.addListener(Runnable {
cameraProvider.unbindAll();
camera = cameraProvider.bindToLifecycle(
this as LifecycleOwner,
cameraSelector,
preview
)
preview?.setSurfaceProvider(previewView.createSurfaceProvider(camera?.cameraInfo))
}, cameraExecutor)
-
此代码将被添加到Runna ble
-
还建议创建一个try块,并在其中添加此代码。此代码可能会失败,例如,如果应用不再处于焦点中。
-
在重新绑定之前取消绑定用例。
-
建议我们在一次调用中通过CameraX将用例绑定到生命周期,并使用相同的生命周期所有者。
-
通过一次提供所有用例,我们给CameraX一个找到折衷方案的机会,这样所有用例都可以运行。
捕获用例
它用于保存高质量的图像。
步骤1:创建Image Capture引用
val imageCapture = ImageCapture.Builder().build()
// SETUP CAPTURE MODE
// to optimize photo capture for quality
val captureMode = ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY
// to optimize photo capture for latency (default)
val captureMode = ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY
imageCapture = ImageCapture.Builder()
.setCaptureMode(captureMode)
.build()
// SETUP FLASH MODE
// flash will always be used when taking a picture
val flashMode = ImageCapture.FLASH_MODE_ON
// flash will never be used when taking a picture (default)
val flashMode = ImageCapture.FLASH_MODE_OFF
// flash will be used according to the camera system's determination
val flashMode = ImageCapture.FLASH_MODE_AUTO
imageCapture = ImageCapture.Builder()
.setFlashMode(flashMode)
.build()
// SETUP ASPECT RATIO
// 16:9 standard aspect ratio
val aspectRatio = AspectRatio.RATIO_16_9
// 4:3 standard aspect ratio (default)
val aspectRatio = AspectRatio.RATIO_4_3
imageCapture = ImageCapture.Builder()
.setTargetAspectRatio(aspectRatio)
.build()
// SETUP TARGET RESOLUTION
val metrics = DisplayMetrics().also { previewView.display.getRealMetrics(it) }
val screenSize = Size(metrics.widthPixels, metrics.heightPixels)
imageCapture = ImageCapture.Builder()
.setTargetResolution(screenSize)
.setTargetName("CameraConference")
.build()
-
通过一次提供所有用例,我们给CameraX一个找到折衷方案的机会,这样所有用例都可以运行。
-
如果我们想在捕获图像时拥有更多的控制权,我们可以向构建器添加不同的功能,如照片捕获优化、闪光模式、纵横比或目标分辨率。
-
捕获模式:如果未设置,默认值为Image Capture。CAPTURE_MODE_MINIMIZE_LATENCY
-
闪存模式:如果不设置默认值是Image Capture。FLASH_MODE_OFF
-
宽高比:如果没有设置,宽高比为4:3的分辨率将被优先考虑。
-
set Target分辨率:如果未设置,将选择要使用的最大可用分辨率。
-
set Target Name(调试目的):如果不设置,目标名称将默认为自动生成的唯一名称,带有类规范名称和随机UUID
步骤2:添加定向事件侦听器
val orientationEventListener = object : OrientationEventListener(this as Context) {
override fun onOrientationChanged(orientation: Int) {
val rotation: Int = when (orientation) {
in 45..134 -> Surface.ROTATION_270
in 135..224 -> Surface.ROTATION_180
in 225..314 -> Surface.ROTATION_90
else -> Surface.ROTATION_0
}
// default => Display.getRotation()
imageCapture.targetRotation = rotation
}
}
orientationEventListener.enable()
步骤3:图像文件管理
val file = File(
externalMediaDirs.first(),
"${System.currentTimeMillis()}.jpg"
)
val outputFileOptions = ImageCapture.OutputFileOptions.Builder(file).build()
-
*Image Capture.*Output File Options为我们提供了保存捕获图像的选项
-
此类的生成器用于配置保存位置,可以是:
- a文件(如代码示例中所示)
- a Media Store或
- 输出流。
步骤4:调用get Picture()
imageCapture.takePicture(outputFileOptions, cameraExecutor,
object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(outputFileResult: ImageCapture.OutputFileResults) {
// yey!!! 🙂
}
override fun onError(exception: ImageCaptureException) {
// ohhh!!! 😦
}
})
-
此方法捕获图像并将其保存到作为参数提供的文件中(第一个)
-
第二个参数表示将在其中运行回调方法的执行程序
-
对于这个方法的每次调用,回调只会被调用一次,它包含了2个方法的实现
- on Image Saved:当图像已成功保存时调用
-
on Error:当试图保存图像时发生错误时调用
步骤5:更新调用以绑定生命周期
// bind the image capture use case to camera
camera = cameraProvider.bindToLifecycle(
this as LifecycleOwner,
cameraSelector,
preview,
imageCapture
)
图像捕捉用例旨在捕捉高清晰度和高质量的照片,并提供自动白平衡、自动曝光和自动对焦(3A)功能,以及简单的手动相机控制。调用方负责决定如何使用捕获的图像:
-
[get Picture(Execitor, On Image Capture Callback](developer.android.com/reference/a…, androidx.camera.core.ImageCapture.OnImageCapturedCallback))):提供捕获图像的内存缓冲区。
-
get Picture(Output File Options, Execitor, On Image Saved Callback):将捕获的[图像保存](developer.android.com/reference/a…, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback))到提供的文件位置。
如果有什么不清楚或有问题,请随时留下评论。如果你喜欢它,请分享!
感谢您的阅读!