Android CameraX 仿一甜相机(录像、拍照、可调节尺寸、聚焦、照明、网格线),最全的CameraX教程

您所在的位置:网站首页 android相机 Android CameraX 仿一甜相机(录像、拍照、可调节尺寸、聚焦、照明、网格线),最全的CameraX教程

Android CameraX 仿一甜相机(录像、拍照、可调节尺寸、聚焦、照明、网格线),最全的CameraX教程

2024-07-14 01:50:42| 来源: 网络整理| 查看: 265

使用cameraX 仿一甜相机

前言

1、导入相关库 2、绑定LifeCycle生命周期并开启预览流 3、绑定ImageCapture图形捕捉以及VideoCapture视频帧捕捉 4、拍照 5、录像 6、聚焦 7、切换摄像头 8、缩放 9、闪光灯 10、照明、补光 11、Extensions 扩展程序使用

前言

CameraX 是jetpack 组件库中的一个非常重要的API,不同于Camera和Camera2,CameraX 在api解耦性上做出了非常大的调整。其中:

1、新增了生命周期绑定管理,解决了老版本Camera的内存泄漏问题2、分辨率自动找寻最接近匹配问题,解决了开发者手动去查询支持分辨率列表(从中去找寻最匹配的分辨率)3、增加ImageAnalysis图像分析,可以在图像输出前对像素进行YUV 转换并且预处理等操作4、增加了 Extensions 扩展程序包括(AUTO、HDR、焦外成像(BOKEH)、夜景(NIGHT)、脸部照片修复(FACE_RETOUCH))等模式,当然,目前国内手机厂商都还没兼容当前的扩展模式,大部分还只有三星手机支持。期待 手机厂商抓紧适配,减少不必要的算法融合。

以上的一些新增内容,足够我们去替换老板本的Camera或者Camera2 Api。下面就是CameraX 的基础用法和Extensions 用法。

CameraX仿一甜相机

请添加图片描述

请添加图片描述

1、导入相关库 def camerax_version = "1.2.0-alpha04" implementation "androidx.camera:camera-core:${camerax_version}" implementation "androidx.camera:camera-camera2:${camerax_version}" implementation "androidx.camera:camera-lifecycle:${camerax_version}" implementation "androidx.camera:camera-video:${camerax_version}" implementation "androidx.camera:camera-view:${camerax_version}" implementation "androidx.camera:camera-extensions:${camerax_version}" 2、绑定LifeCycle生命周期并开启预览流 fun openCamera(){ val cameraProviderFuture = ProcessCameraProvider.getInstance(mLifecycleOwner!!) cameraProviderFuture.addListener({ // 绑定生命周期 val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() // Preview 预览流 val preview = Preview.Builder() .build() .also { it.setSurfaceProvider(preview?.surfaceProvider) } //选择后置摄像头 val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA try { //解绑所有摄像头使用 cameraProvider.unbindAll() // 绑定输出 camera = cameraProvider.bindToLifecycle( mLifecycleOwner!!, cameraSelector, preview ) } catch (exc: Exception) { Log.e(TAG, "Use case binding failed", exc) } }, ContextCompat.getMainExecutor(mLifecycleOwner!!)) } 3、绑定ImageCapture图形捕捉以及VideoCapture视频帧捕捉 //图像捕捉 imageCapture = ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY) .build() // 绑定输出 camera = cameraProvider.bindToLifecycle( mLifecycleOwner!!, cameraSelector, imageCapture, preview ) 4、拍照 override fun takePhoto() { val imageCapture = imageCapture ?: return val name = SimpleDateFormat("yyyy-MM-dd", Locale.US) .format(System.currentTimeMillis()) val contentValues = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, name) put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg") if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image") } } val outputOptions = ImageCapture.OutputFileOptions .Builder( mLifecycleOwner?.contentResolver!!, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues ) .build() imageCapture.takePicture( outputOptions, ContextCompat.getMainExecutor(mLifecycleOwner!!), object : ImageCapture.OnImageSavedCallback { override fun onError(exc: ImageCaptureException) { Log.e(TAG, "Photo capture failed: ${exc.message}", exc) } override fun onImageSaved(output: ImageCapture.OutputFileResults) { val msg = "Photo capture succeeded: ${output.savedUri}" Toast.makeText(mLifecycleOwner, msg, Toast.LENGTH_SHORT).show() Log.d(TAG, msg) } } ) } 5、录像 @SuppressLint("CheckResult") override fun takeVideo() { val videoCapture = this.videoCapture ?: return //如果正在录制,则停止 if (recording != null) { recording?.stop() recording = null return } val name = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA) .format(System.currentTimeMillis()) val contentValues = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, name) put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4") if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { put(MediaStore.Video.Media.RELATIVE_PATH, "Movies/CameraX-Video") } } val mediaStoreOutputOptions = mLifecycleOwner?.contentResolver?.let { MediaStoreOutputOptions .Builder(it, MediaStore.Video.Media.EXTERNAL_CONTENT_URI) .setContentValues(contentValues) .build() } recording = videoCapture.output .prepareRecording(mLifecycleOwner!!, mediaStoreOutputOptions!!) .apply { if (ActivityCompat.checkSelfPermission( mLifecycleOwner!!, Manifest.permission.RECORD_AUDIO ) != PackageManager.PERMISSION_GRANTED ) { //启动音频 withAudioEnabled() } } .start(ContextCompat.getMainExecutor(mLifecycleOwner!!)) { recordEvent -> when (recordEvent) { is VideoRecordEvent.Start -> { //录制开始 Toast.makeText(mLifecycleOwner, "开始录制", Toast.LENGTH_SHORT) .show() } is VideoRecordEvent.Finalize -> { //录制结束 if (!recordEvent.hasError()) { val msg = "Video capture succeeded: " + "${recordEvent.outputResults.outputUri}" Toast.makeText(mLifecycleOwner, msg, Toast.LENGTH_SHORT) .show() Log.d(TAG, msg) } else { recording?.close() recording = null Log.e( TAG, "Video capture ends with error: " + "${recordEvent.error}" ) } } } } } 6、聚焦

聚焦分为三种模式

//使用PreviewView。用于自动聚焦,在previewView中创建一个坐标点 previewView.setOnTouchListener((view, motionEvent) -> { val meteringPoint = previewView.meteringPointFactory .createPoint(motionEvent.x, motionEvent.y) … } //使用DisplayOrientedMeteringPointFactory如果SurfaceView / TextureView用于 //预览。请注意,如果预览在视图中缩放或裁剪, //正确转换坐标是应用程序的责任 //这样工厂的宽度和高度代表完整的预览FOV。 //和(x,y)传入创建MeteringPoint可能需要调整 val meteringPointFactory = DisplayOrientedMeteringPointFactory( surfaceView.display, camera.cameraInfo, surfaceView.width, surfaceView.height ) //使用SurfaceOrientedMeteringPointFactory如果点指定在 //图形分析ImageProxy。 val meteringPointFactory = SurfaceOrientedMeteringPointFactory( imageWidth, imageHeight, imageAnalysis)

基于以上的point 创建方式,可以封装为自动聚焦和手动聚焦

/** * 聚焦 * @param auto 聚焦模式 */ @SuppressLint("RestrictedApi") override fun focus(x: Float, y: Float, auto: Boolean) { cameraControl?.cancelFocusAndMetering() val createPoint: MeteringPoint = if (auto) { val meteringPointFactory = DisplayOrientedMeteringPointFactory( preview?.display!!, camera?.cameraInfo!!, preview?.width?.toFloat()!!, preview?.height?.toFloat()!! ) meteringPointFactory.createPoint(x, y) } else { val meteringPointFactory = preview?.meteringPointFactory meteringPointFactory?.createPoint(x, y)!! } val build = FocusMeteringAction.Builder(createPoint, FLAG_AF) .setAutoCancelDuration(3, TimeUnit.SECONDS) .build() val future = cameraControl?.startFocusAndMetering(build) future?.addListener({ try { if (future.get().isFocusSuccessful) { //聚焦成功 Log.e(TAG, "聚焦成功") } else { //聚焦失败 Log.e(TAG, "聚焦失败") } } catch (e: Exception) { Log.e(TAG, "异常" + e.message) } }, ContextCompat.getMainExecutor(mLifecycleOwner!!)) } 7、切换摄像头 /** * 切换镜头 */ override fun switchCamera() { mFacingFront = !mFacingFront // 解除绑定 cameraProvider?.unbindAll() // 前后置摄像头选择器 val cameraSelector = CameraSelector.Builder() .requireLensFacing(if (mFacingFront) CameraSelector.LENS_FACING_FRONT else CameraSelector.LENS_FACING_BACK) .build() imageCapture = ImageCapture.Builder() .setTargetAspectRatio(AspectRatio.RATIO_4_3) .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY) .build() // 绑定输出 camera = cameraProvider?.bindToLifecycle( mLifecycleOwner!!, cameraSelector, imageCapture, videoCapture, mPreView ) } 8、缩放 /** * 缩放 */ override fun zoom(out: Boolean) { val zoomState = camera?.cameraInfo?.zoomState val zoomRatio: Float? = zoomState?.value?.zoomRatio //当前值 val maxZoomRatio: Float? = zoomState?.value?.maxZoomRatio//缩放最大值 val minZoomRatio: Float? = zoomState?.value?.minZoomRatio //缩放最小值 if (out) { //放大 if (zoomRatio!! //缩小 if (zoomRatio!! > minZoomRatio!!) { cameraControl?.setZoomRatio((zoomRatio - zoomCoefficient)) } } } 9、闪光灯 //闪光灯模式 val flashMode = if (cameraParams?.mSplashOn == true && cameraParams?.mFacingFront == false) { ImageCapture.FLASH_MODE_ON } else { ImageCapture.FLASH_MODE_OFF } imageCapture?.flashMode = flashMode 10、照明、补光 cameraControl?.enableTorch(cameraParams?.torchSwitch!!) 11、Extensions 扩展程序使用

以下是Extensions 支持的模式。

public final class ExtensionMode { /**正常无效果 */ public static final int NONE = 0; /** 焦外成像 */ public static final int BOKEH = 1; /** HDR */ public static final int HDR = 2; /** 在光线较暗的情况下,尤其是在夜间,获得最好的静止图像 */ public static final int NIGHT = 3; /**在拍摄静态图像时,修饰脸部皮肤色调,几何形状等 */ public static final int FACE_RETOUCH = 4; /** 自动 */ public static final int AUTO = 5;

使用方式

//协程挂起是必须的 mLifecycleOwner?.lifecycleScope?.launch { //获取manager val extensionsManager = ExtensionsManager.getInstanceAsync(mLifecycleOwner!!, cameraProvider!!).await() //判断设备是否支持扩展程序 if (extensionsManager.isExtensionAvailable( cameraSelector, cameraParams?.extensionMode!! ) ) { //如果支持,则传入对应的mode 模式,如BOKEH Log.d(TAG, "支持" + cameraParams?.extensionMode) val extensionId = extensionsManager.getExtensionEnabledCameraSelector( cameraSelector, cameraParams?.extensionMode!! ) startPreView = true bindCameraId(extensionId) } else { startPreView = false Log.d(TAG, "不支持" + cameraParams?.extensionMode) } } /** * 绑定相机id */ private fun bindCameraId(cameraSelector: CameraSelector) { try { cameraProvider?.unbindAll() // 绑定输出 camera = cameraProvider?.bindToLifecycle( mLifecycleOwner!!, cameraSelector, mPreView, imageCapture, videoCapture ) if (!isInt) { isInt = true callBack?.ratioCallBack(cameraParams?.mRatioType) } cameraControl = camera?.cameraControl focus(preview?.width?.div(2f)!!, preview?.height?.div(2f)!!, true) } catch (exc: Exception) { Log.e(TAG, "Use case binding failed", exc) } }

由于本人的设备不支持扩展程序,所以就没有展示效果了,希望国能厂商能升级ROM 支持一下吧。 后续有支持的设备后,会更新效果图上来。 代码已上传: https://github.com/ljlstudio/KtMvvm/tree/master/demo/src/main/java/com/kt/ktmvvm/jetpack/camerax



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭