Android CameraX 仿一甜相机(录像、拍照、可调节尺寸、聚焦、照明、网格线),最全的CameraX教程
使用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教程相关推荐
- Android学习之调用系统相机实现拍照功能
一.今天,来介绍如何调用系统自带的相机进行拍照,主要有以下2种实现的方式: 1.Camera应用程序包含了一个意图过滤器,即intent filter,它使得开发人员能够提供与Camera应用程序同等 ...
- 仿天猫 购物车(Android studio 仿天猫 详情页面 添加购物车选择 颜色 尺寸demo)
这是我第一次编写博客,有不好的地方请发邮件或留言告知. 注*请勿转载-转载需博主同意 1.首先就是设计页面了–先效果图 2.现在开始看代码,没有啥好说的 这是布局文件 MainActivity 里面的 ...
- android com.mylhyl,Android 高仿微信朋友圈拍照上传功能
模仿微信朋友圈发布动态,输入文字支持文字多少高度自增,有一个最小输入框高度,输入文字有限制,不过这些都很easy! 1. photopicker的使用 这是一个支持选择多张图片,点击图片放大,图片之间 ...
- Android 调用系统中的相机应用及静默拍照
通过Intent直接调用系统相机 直接调用系统的相机应用,只需要在Intent对象中传入相应的参数即可,总体来说需要以下三步: 1. Compose a Camera Intent MediaStor ...
- android 微信高仿,Android 高仿微信朋友圈拍照上传功能
模仿微信朋友圈发布动态,输入文字支持文字多少高度自增,有一个最小输入框高度,输入文字有限制,不过这些都很easy! 1. PhotoPicker的使用 这是一个支持选择多张图片,点击图片放大,图片之间 ...
- 记录--uniapp自定义相机 自定义界面拍照录像闪光灯切换摄像头
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 因公司业务需要,需要开发水印相机功能,而项目代码用的uniapp框架,App端只能简单调用系统的相机,无法自定义界面,在此基础上,只能开发 ...
- Qt for Android调用原生接口打开相机拍照并存储照片
Qt开发Android应用,需求是通过调用Android原生接口去打开系统相机拍照,并返回拍摄的照片.原理很简单,现在Java文件中写android代码调用相机,拍照后将将相片存储在SD卡,然后在C+ ...
- android编程 自动裁剪图片,Android编程实现调用相册、相机及拍照后直接裁剪的方法...
本文实例讲述了Android编程实现调用相册.相机及拍照后直接裁剪的方法.分享给大家供大家参考,具体如下: package com.cvte.health.phone; import java.io. ...
- android intent拍照,Android通过Intent方式调用相机拍照取得图片
Android通过Intent方式调用相机拍照取得图片 AndroidManifest.XML 权限设置: XML布局设置: 代码: public classMainActivityextendsAp ...
- Android camera相机开发拍照功能
在Android 5.0(SDK 21)中,Google使用Camera2替代了Camera接口.Camera2在接口和架构上做了巨大的变动,但是基于众所周知的原因,我们还必须基于 Android 4 ...
最新文章
- SpringBoot巧用 @Async 提升API接口并发能力!
- 软件测试数据怎么找,作为软件测试人员怎么能快速找到bug
- 计算机管理窗口下的菜单,win7电脑右键打不开管理菜单的详细攻略
- php数据库根据相似度排序,php数组字段相似度排序
- folders默认配置 shell_更改windows默认的User Shell Folders
- linux --- 进阶指令
- 用Python开始机器学习(4:KNN分类算法)
- JPA /休眠刷新策略初学者指南
- BoostrapTable的refresh和refreshOptions区别
- OpenCV版本与EmguCV版本匹配问题
- Linux远程传输命令scp、rsync(tar打包归档并在系统之间传输文件)
- HTML5+CSS简单的期末大作业:体育运动主题网站设计——羽毛球网页(5页) HTML+CSS+JavaScript 学生DW网页设计作业成品 web课程设计网页规划与设计 大学生毕设网页设计
- snownlp 原理_情感分析snownlp包部分核心代码理解
- VC++程序设计与应用--数据库编程
- /etc/fstab文件的详解
- InputDispatcher: Untrusted touch due to occlusion by
- 最好的输入法--陈桥五笔5.806(绿色可自动卸载版)
- 【教程】win10下安装Biolinux双系统
- 洛谷4550 收集邮票(期望DP)
- [附源码]Java计算机毕业设计SSM电脑配件仓储后台管理系统
热门文章
- 企业私有云资源规划及设计
- 小米平板2 android6,小米平板2终于来了MIUI7/Win10双系统
- Miller_Rabin(米勒拉宾)素数测试
- 无法安装冰点还原_冰点还原精灵能用Windows10吗
- 自动化车辆的开发、测试和验证场景
- foxmail邮件备份到服务器上,foxmail发送邮件自动保存到邮件服务器的方法
- 什么是直方图,如何使用它来改善照片?
- dnplayerext2文件夹删不掉怎么解决
- python股票量化交易(13)---使用pyqt5构建股票交易K线形态
- win2008服务器c盘在线扩容,win7 win10 win2008系统给主分区C盘增加空间 不破坏原硬盘内容扩充C盘 MiniTool Partition Wizard...