使用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_CAMERAtry {//解绑所有摄像头使用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 ?: returnval 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 = nullreturn}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 = nullLog.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?.meteringPointFactorymeteringPointFactory?.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?.zoomStateval zoomRatio: Float? = zoomState?.value?.zoomRatio        //当前值val maxZoomRatio: Float? = zoomState?.value?.maxZoomRatio//缩放最大值val minZoomRatio: Float? = zoomState?.value?.minZoomRatio //缩放最小值if (out) {//放大if (zoomRatio!! < maxZoomRatio!!) {cameraControl?.setZoomRatio((zoomRatio + zoomCoefficient))}} else {//缩小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 {//获取managerval extensionsManager = ExtensionsManager.getInstanceAsync(mLifecycleOwner!!, cameraProvider!!).await()//判断设备是否支持扩展程序if (extensionsManager.isExtensionAvailable(cameraSelector,cameraParams?.extensionMode!!)) {//如果支持,则传入对应的mode 模式,如BOKEHLog.d(TAG, "支持" + cameraParams?.extensionMode)val extensionId = extensionsManager.getExtensionEnabledCameraSelector(cameraSelector,cameraParams?.extensionMode!!)startPreView = truebindCameraId(extensionId)} else {startPreView = falseLog.d(TAG, "不支持" + cameraParams?.extensionMode)}}/*** 绑定相机id*/private fun bindCameraId(cameraSelector: CameraSelector) {try {cameraProvider?.unbindAll()// 绑定输出camera = cameraProvider?.bindToLifecycle(mLifecycleOwner!!,cameraSelector,mPreView,imageCapture,videoCapture)if (!isInt) {isInt = truecallBack?.ratioCallBack(cameraParams?.mRatioType)}cameraControl = camera?.cameraControlfocus(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

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

  1. Android学习之调用系统相机实现拍照功能

    一.今天,来介绍如何调用系统自带的相机进行拍照,主要有以下2种实现的方式: 1.Camera应用程序包含了一个意图过滤器,即intent filter,它使得开发人员能够提供与Camera应用程序同等 ...

  2. 仿天猫 购物车(Android studio 仿天猫 详情页面 添加购物车选择 颜色 尺寸demo)

    这是我第一次编写博客,有不好的地方请发邮件或留言告知. 注*请勿转载-转载需博主同意 1.首先就是设计页面了–先效果图 2.现在开始看代码,没有啥好说的 这是布局文件 MainActivity 里面的 ...

  3. android com.mylhyl,Android 高仿微信朋友圈拍照上传功能

    模仿微信朋友圈发布动态,输入文字支持文字多少高度自增,有一个最小输入框高度,输入文字有限制,不过这些都很easy! 1. photopicker的使用 这是一个支持选择多张图片,点击图片放大,图片之间 ...

  4. Android 调用系统中的相机应用及静默拍照

    通过Intent直接调用系统相机 直接调用系统的相机应用,只需要在Intent对象中传入相应的参数即可,总体来说需要以下三步: 1. Compose a Camera Intent MediaStor ...

  5. android 微信高仿,Android 高仿微信朋友圈拍照上传功能

    模仿微信朋友圈发布动态,输入文字支持文字多少高度自增,有一个最小输入框高度,输入文字有限制,不过这些都很easy! 1. PhotoPicker的使用 这是一个支持选择多张图片,点击图片放大,图片之间 ...

  6. 记录--uniapp自定义相机 自定义界面拍照录像闪光灯切换摄像头

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 因公司业务需要,需要开发水印相机功能,而项目代码用的uniapp框架,App端只能简单调用系统的相机,无法自定义界面,在此基础上,只能开发 ...

  7. Qt for Android调用原生接口打开相机拍照并存储照片

    Qt开发Android应用,需求是通过调用Android原生接口去打开系统相机拍照,并返回拍摄的照片.原理很简单,现在Java文件中写android代码调用相机,拍照后将将相片存储在SD卡,然后在C+ ...

  8. android编程 自动裁剪图片,Android编程实现调用相册、相机及拍照后直接裁剪的方法...

    本文实例讲述了Android编程实现调用相册.相机及拍照后直接裁剪的方法.分享给大家供大家参考,具体如下: package com.cvte.health.phone; import java.io. ...

  9. android intent拍照,Android通过Intent方式调用相机拍照取得图片

    Android通过Intent方式调用相机拍照取得图片 AndroidManifest.XML 权限设置: XML布局设置: 代码: public classMainActivityextendsAp ...

  10. Android camera相机开发拍照功能

    在Android 5.0(SDK 21)中,Google使用Camera2替代了Camera接口.Camera2在接口和架构上做了巨大的变动,但是基于众所周知的原因,我们还必须基于 Android 4 ...

最新文章

  1. SpringBoot巧用 @Async 提升API接口并发能力!
  2. 软件测试数据怎么找,作为软件测试人员怎么能快速找到bug
  3. 计算机管理窗口下的菜单,win7电脑右键打不开管理菜单的详细攻略
  4. php数据库根据相似度排序,php数组字段相似度排序
  5. folders默认配置 shell_更改windows默认的User Shell Folders
  6. linux --- 进阶指令
  7. 用Python开始机器学习(4:KNN分类算法)
  8. JPA /休眠刷新策略初学者指南
  9. BoostrapTable的refresh和refreshOptions区别
  10. OpenCV版本与EmguCV版本匹配问题
  11. Linux远程传输命令scp、rsync(tar打包归档并在系统之间传输文件)
  12. HTML5+CSS简单的期末大作业:体育运动主题网站设计——羽毛球网页(5页) HTML+CSS+JavaScript 学生DW网页设计作业成品 web课程设计网页规划与设计 大学生毕设网页设计
  13. snownlp 原理_情感分析snownlp包部分核心代码理解
  14. VC++程序设计与应用--数据库编程
  15. /etc/fstab文件的详解
  16. InputDispatcher: Untrusted touch due to occlusion by
  17. 最好的输入法--陈桥五笔5.806(绿色可自动卸载版)
  18. 【教程】win10下安装Biolinux双系统
  19. 洛谷4550 收集邮票(期望DP)
  20. [附源码]Java计算机毕业设计SSM电脑配件仓储后台管理系统

热门文章

  1. 企业私有云资源规划及设计
  2. 小米平板2 android6,小米平板2终于来了MIUI7/Win10双系统
  3. Miller_Rabin(米勒拉宾)素数测试
  4. 无法安装冰点还原_冰点还原精灵能用Windows10吗
  5. 自动化车辆的开发、测试和验证场景
  6. foxmail邮件备份到服务器上,foxmail发送邮件自动保存到邮件服务器的方法
  7. 什么是直方图,如何使用它来改善照片?
  8. dnplayerext2文件夹删不掉怎么解决
  9. python股票量化交易(13)---使用pyqt5构建股票交易K线形态
  10. win2008服务器c盘在线扩容,win7 win10 win2008系统给主分区C盘增加空间 不破坏原硬盘内容扩充C盘 MiniTool Partition Wizard...