Android Camera开发实践(1)预览,vue总结来了

2023-05-16

1.2打开Camera硬件

配置相机、存储权限

设置SurfaceCallback,回调中,启动预览。注意,surfaceChanged至少回调一次

SurfaceView cameraPreview = findViewById(R.id.camera_preview);
cameraPreview.getHolder().addCallback(new PreviewSurfaceCallback());

private class PreviewSurfaceCallback implements SurfaceHolder.Callback{

@Override
public void surfaceCreated(SurfaceHolder holder) {

}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
mPreviewSurface = holder;
mPreviewSurfaceWidth = width;
mPreviewSurfaceHeight = height;
if(mCameraHandler != null){
mCameraHandler.obtainMessage(MSG_SET_PREVIEW_SIZE, width, height).sendToTarget();
mCameraHandler.obtainMessage(MSG_SET_PICTURE_SIZE).sendToTarget();
mCameraHandler.obtainMessage(MSG_SET_PREVIEW_SURFACE, holder).sendToTarget();
mCameraHandler.sendEmptyMessage(MSG_START_PREVIEW);
}
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mPreviewSurface = null;
mPreviewSurfaceWidth = 0;
mPreviewSurfaceHeight = 0;
}
}

打开相机,参数为cameraid

private void openCamera(int cameraId) {
Camera camera = mCamera;

if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED){
//打开相机
mCamera = Camera.open(cameraId);
mCameraId = cameraId;
mCameraInfo = cameraId == mFrontCameraId ? mFrontCameraInfo : mBackCameraInfo;
// 设置相机方向,后面2.1处详细讲述
mCamera.setDisplayOrientation(getCameraDisplayOrientation(mCameraInfo));
}
}

1.3设置预览属性,尺寸、编码格式

查询支持的预览尺寸、编码格式,根据需要设置。

private void setPreviewSize(int shortSide, int longSide) {
if (mCamera != null && shortSide != 0 && longSide != 0){
float aspectRatio = (float)longSide / shortSide;
Camera.Parameters parameters = mCamera.getParameters();
List<Camera.Size> supportedPreviewSizes = parameters.getSupportedPreviewSizes();
for (Camera.Size previewSize : supportedPreviewSizes) {
//1.设置预览尺寸
if((float)previewSize.width / previewSize.height == aspectRatio && previewSize.height <= shortSide && previewSize.width <= longS

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整资料开源分享

ide) {
parameters.setPreviewSize(previewSize.width, previewSize.height);

//2.设置预览的编码格式,此处PREVIEW_FORMAT = ImageFormat.NV21
// NV21 即 YUV
if(isPreviewFormatSupported(parameters, PREVIEW_FORMAT)){
parameters.setPreviewFormat(PREVIEW_FORMAT);
int frameWidth = previewSize.width;
int frameHeight = previewSize.height;
int previewFormat = parameters.getPreviewFormat();
PixelFormat pixelFormat = new PixelFormat();
PixelFormat.getPixelFormatInfo(previewFormat, pixelFormat);
int bufferSize = (frameWidth * frameHeight * pixelFormat.bitsPerPixel) / 8;
//3.设置预览的缓冲数组
mCamera.addCallbackBuffer(new byte[bufferSize]);
mCamera.addCallbackBuffer(new byte[bufferSize]);
mCamera.addCallbackBuffer(new byte[bufferSize]);
}

mCamera.setParameters(parameters);
}
}
}
}

1.4设置预览surface,即接收并显示图像的容器

实际设置的是surfaceHolder

private void setPreviewSurface(SurfaceHolder previewSurface) {
if (mCamera != null && previewSurface != null) {
try {
mCamera.setPreviewDisplay(previewSurface);
} catch (IOException e) {
e.printStackTrace();
}
}
}

1.5启动预览

private void startPreview() {
if (mCamera != null && mPreviewSurface != null) {
// 增加callback,便于buffer复用
mCamera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
// 使用完buffer之后回收复用
camera.addCallbackBuffer(data);
}
});
mCamera.startPreview();
}
}

二、相机预览方向校正

因为手机摄像头硬件的设计,不做额外的处理,相机预览的图像角度是错误的,准确的说竖屏状态下,逆时针偏了90°。

上文有一句代码,设置相机预览的旋转方向,此处补充说明.

mCamera.setDisplayOrientation(getCameraDisplayOrientation(mCameraInfo));

完整代码出自于google/Android官方文档 “Android developer”)

private int getCameraDisplayOrientation(Camera.CameraInfo cameraInfo) {
int roration = getWindowManager().getDefaultDisplay().getRotation();
// 屏幕显示方向角度(相对局部坐标Y轴正方向夹角)
int degrees = 0;
switch (roration) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;

case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;

if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){
result = (cameraInfo.orientation + degrees) % 360;
result = (360 - result) % 360;
} else {
result = (cameraInfo.orientation - degrees + 360) %360;
}
// 相机需要校正的角度
return result;
}

相机预览方向矫正相对复杂些,查阅了许多资料,大多照搬google代码,讲的模棱两可。上面这段代码相信许多朋友都见过,但是对最后result的计算不一定了解。

要讲清楚相机方向矫正,先介绍几个重要的概念

  • 手机自然方向
  • 局部坐标系
  • 显示方向
  • 摄像头传感器方向

2.1手机自然方向和局部坐标系

手机默认是竖屏,短边朝上为自然方向,平板默认是横屏,宽边朝上为自然方向。

局部坐标系与手机的自然状态相关,Y轴与手机自然状态时朝上的方向对齐,下图中手机的局部坐标系y轴朝上:

局部坐标系

为方便说明,后面讲各个方向,均以局部坐标Y轴正方向为基准

2.2显示方向

显示方向与横竖屏状态有关。竖屏时,显示方向朝上,显示方向与局部坐标Y轴一致,横屏时显示方向朝上与局部坐标x轴对齐。

注意,向左旋转横屏时,显示方向朝上,相对局部坐标Y轴的夹角为90°,即Y轴顺时针旋转90°才能对齐显示方向,向右旋转横屏时,该夹角为270°。

务必理解这个概念,后面计算相机角度校正要用到。

向右横屏状态

2.3摄像头传感器方向

以后置摄像头为例

开发中,竖屏状态下, window view的坐标系是短边为y轴,长边为x轴

image.png

相对手机自然方向,摄像头硬件安装时顺时针旋转了90°,短边为X轴,长边为Y轴。看起来像是专门为pad横屏设计的。(why?我也母鸡。。)

image.png

将手机朝左横屏时,两个坐标系刚好对齐,开发中不用适配显示也是对的。

向左横屏不用适配

上面代码中 cameraInfo.orientation 获取的就是相机摄像头的方向(相对局部坐标系Y轴)

2.4后置摄像头画面校正

如上所述,因为摄像头安装角度、手机横竖屏状态切换导致的显示方向变化,摄像头采集的图像显示到屏幕上就可能会产生偏角。实际开发中,我们需要计算出这个偏角,以做校正。

如果不做任何处理,degree(显示方向)为0,orientation(摄像头方向)为90°,预览是歪着的。

再次说明,角度均以局部坐标y轴正方向为参考基准

image.png

怎么理解呢?你可以想象自己的头是摄像头,你的头向右倒90°看到的图像可不就是歪的么。然后你把看到的图像传给显示屏,显示屏可不知道你是歪着脑袋采集数据的。

校正需要调用 mCamera.setDisplayOrientation(int arg),设置一个角度,将采集的图像顺时针旋转arg角度,以补偿摄像头的偏角。

以向左横屏为例说明:

arg = orientation - degree //所以如果是朝左横屏时
arg = 90 - 90 = 0 //碰巧显示对了,不用校正

可以理解为:摄像头采集的数据超前了90度(相对局部坐标系),而向左横屏造成显示方向超前了90度,如此摄像头方向和显示的方向刚好扯平对齐了。

image.png

朝右横屏呢:

// 摄像头相对局部坐标Y轴不变: orientation = 90
// 显示方向朝上,相对局部坐标Y轴顺时针旋转 degree = 270
arg = orientation - degree + 360 = 90 - 270 + 360 = 180

则需要补偿180度,其中+360是为了使旋转方向始终朝顺时钟方向,使arg不为负数,其实-180和+180是一样的。demo里也确实上下颠倒,需要补偿180°。

2.5前置摄像头画面校正

前置稍微麻烦点,区别在于

1. 自拍时自己看到的旋转角度和摄像头得到的真实角度是相反的,即你看到逆时针,真实的是顺时针
2. 相机系统在处理前置拍摄时,会左右镜像,以模拟人照镜子时的效果,所以显示屏上得到的像素是已经左右对调处理了。
这两点造成前置摄像头的校正理解起来稍微费解点,但是代码看起来差不多。
此处有点绕,笔者晚上洗澡时想这个问题走神了,在卫生间发呆了一个多小时,老婆还以为我洗澡出事了。

所以,仅考虑自拍角度相反的因素,

arg = orientation - (-degree) = orientation + degree

再考虑镜像,最终的补偿角度为:

result = 360 - arg,

这就和google官方文档提供的模板代码一致了。朋友,能看到这都理解了,为自己的好学点个赞吧。

看下图,左右镜像后,A镜像为B,A点转到Y轴正方向角度为a,B点转到Y轴正方向为b,a + b = 360,所以镜像后,真正需要补偿的角度为360 - arg

补充:最后取模360,也很好理解,保证角度在一个周期内.

result = (360 - result) % 360;

egree

再考虑镜像,最终的补偿角度为:

result = 360 - arg,

这就和google官方文档提供的模板代码一致了。朋友,能看到这都理解了,为自己的好学点个赞吧。

看下图,左右镜像后,A镜像为B,A点转到Y轴正方向角度为a,B点转到Y轴正方向为b,a + b = 360,所以镜像后,真正需要补偿的角度为360 - arg

[外链图片转存中…(img-Yk9Hqwcu-1641177552975)]

补充:最后取模360,也很好理解,保证角度在一个周期内.

result = (360 - result) % 360;

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android Camera开发实践(1)预览,vue总结来了 的相关文章

  • 爬虫实战(三)

    随着互联网的不断发展 xff0c 网络数据的规模和价值也不断提升 在这个大数据时代 xff0c 如何从海量数据中提取有价值的信息并加以利用 xff0c 成为了数据科学 商业分析 金融预测 社会研究等领域中一个重要的问题 而网络爬虫作为一种数
  • Linux (9)引导过程与服务控制

    本章结构 1 Linux操作系统引导过程 2 排除启动类故障 3 服务控制及切换运行级别 4 优化启动过程 1 Linux操作系统引导过程 linux系统引导过程 1 开机自检 服务器主机开机以后 xff0c 将根据主板 BIOS 中的设置
  • Android App开发之Jetpack架构,从思维图到基础再到深入

    在UI组件日益完善的同时 xff0c 也开始出现了RecyclerView ConstraintLayout MotionLayout等一些可以辅助大家写出更加符合性能要求的界面效果 在UI控件日益满足需求的同时 xff0c 系统的安全与稳
  • Android-Notes|BottomNavigationView-爱上-Lottie,kotlin声明数组

    selected xff1a 选中才显示标题 xff1b labeled xff1a 标题一直显示 xff1b unlabeled xff1a 只显示 icon xff0c 不显示标题 2 Lottie 对于这个东东 xff0c 不知道说啥
  • Linux生产者消费者与信号量

    目录 一 生产者消费者概念 二 模拟实现基于阻塞队列的生产消费模型 2 1概念 2 2构造阻塞队列 三 信号量 3 1原理 3 2信号量函数 3 3信号量模拟互斥功能 一 生产者消费者概念 生产者消费者模式就是通过一个容器来解决生产者和消费
  • 短视频文案怎么写?优质短视频文案写作技巧

    抖音短视频的质量仔细推敲起来确实会涉及到非常多的因素 xff0c 但真正决定你视频曝光的关键就是视频文案 xff0c 从剧情的铺垫 冲突 反转 xff0c 这在一定程度上能够吸引不少的观众 又或者小说开篇要么叙述宏达的故事背景 xff0c
  • Windows如何登录linux?

    1 用SSH命令 xff0c windows连接Linux xff08 1 xff09 ssh l root 192 168 5 15 xff08 2 xff09 ssh root 64 192 168 5 10 首次连接yes 即可 2
  • 单链表及其Java代码实现

    众所周知 xff0c 数组和链表都有内存寻址的功能 而数组元素的内存地址是连续的 xff0c 在寻址的时候很容易就可以找到下一个节点的值 而链表中元素的地址不是连续的 xff0c 那我们应该怎么去寻址呢 xff1f 假设现在计算机中有三个节
  • 创建Java Web项目并实现前后端交互

    目录 一 xff1a 使用工具 二 xff1a 创建Java Web项目 三 xff1a 编写代码 一 xff1a 使用工具 Eclipse 版本如下 xff1a 注 xff1a 不同版本的eclipse创建的项目基础目录可能会有所不同 二
  • 不坠华年(大一篇)

    秒速5厘米的樱花 这一年 xff0c 我遇到了想共度一生的人 xff0c 但是 从来没谈过恋爱的我根本不知道如何去追女孩子 xff0c 算了 xff0c 只要她快乐就好 xff0c 喜欢也不一定会在一起吧 xff0c 我总是说愿意等 xff
  • 数据结构之平衡有序二叉树

    我们知道引入树是为了提高数据存储 xff0c 读取的效率 可是有的二叉树并不能提高效率 xff0c 例如下面的这个树 这是一种极端的情况 xff0c 实际上它已经和链表一样了 xff0c 现在对它进行查询 xff0c 时间复杂度已经成为了O
  • 数据结构之B+树

    B 43 树结构特点 1 非叶子节点仅具有索引作用 xff0c 也就是说 xff0c 非叶子节点只能存储Key 不能存储value xff1b 2 树的所有叶节点构成一个有序链表 xff0c 可以按照key排序的次序依次遍历全部数据 B 4
  • MyBatis之Maven配置

    一 什么是Maven Maven是一个项目管理工具 xff0c 它包含了一个对象模型 一组标准集合 xff0c 一个依赖管理系统 和用来运行定义在生命周期阶段中插件目标和逻辑 二 下载配置相关版本的Maven 解压之后做相关的配置 1 配置
  • 数据库三大范式

    第一范式 xff08 1NF xff09 xff1a 在设计数据库时 xff0c 第一范式是对数据库的基本要求 满足第一范式的关系数据库的每一个域均为原子性的 xff0c 即数据库表的每一列都是不可分割的原子项 xff0c 而不能是集合 数
  • 数据库设计规范

    字符集 表格创建规范 所有的表都必须有这几个字段 删除一般都是软删除 xff0c 01删除标志 id等数字类型的字段不能只使用bigint用bigint unsigned xff08 为什么 xff1a xff09 当数据库中该属性添加un
  • git的版本控制流程以及特性分支之间怎样切换

    git xff1a 版本控制工具 xff08 例 xff1a 淘宝每次升级版本号加1 xff0c git来控制版本 xff09 命令 git pull xff1a 用于从远程更新存储库的本地版本 git commit xff1a 主要用于将
  • Android _ ViewBinding 与 Kotlin 委托双剑合璧,从思维图到基础再到深入

    lt LinearLayout tools viewBindingIgnore 61 true gt 3 2 创建绑定类 有三个创建绑定类的 API xff1a fun bind view View T fun inflate inflat
  • Android语音播报、后台播报、语音识别,android程序开发

    lt xml version 61 34 1 0 34 encoding 61 34 gt Android学习笔记总结 43 最新移动架构视频 43 大厂安卓面试真题 43 项目实战源码讲义 gt gt docs qq com doc DS
  • Spring框架介绍和使用

    一 Spring框架介绍 1 Spring简介 Spring是2003年兴起的一个Java轻量级框架 xff0c 它是为解决企业级开发的复杂性而创建的一个框架 它是一个分层的JavaSE EE Full Stack xff08 一站式 xf
  • SpringMVC注解开发运行原理

    服务器初始化过程 xff1a 1 xff1a 服务器初始化 加载继承 AbstractDispatcherServletInitializer即springmvc定义的代替web xml的 类初始化web容器 然后重写三个方法 xff1a

随机推荐

  • Unity3d游戏开发之C#开发(一)

    概要 撰写原因 xff1a 当今市面上关于Unity的教程的脚本几乎都是用js来当做教程语言的 xff0c 因为js比较容易学习 xff0c 所以如果是新学的朋友建议学js的版本 xff0c 如有特殊要求需要学习C 写脚本的话那么这系列文章
  • Spring配置文件详解

    Spring配置文件详解 1 spring的配置文件详解 Bean标签基本配置 用于配置对象让 spring 来创建的 默认情况下它调用的是类中的无参构造函数 如果没有无参构造函数则不能创建成功 属性 xff1a id 给对象在容器之中提供
  • [WinError 10061] 由于目标计算机积极拒绝,无法连接。解决办法

    相信来到这的人一定遇到这样的情况 xff0c 十分的难受 这里给大家总结了三种方法 xff0c 看看能不能解决大家的困难 1 代理问题 大家看看自己是不是因为正在搞东西 xff0c 列如 xff1a burpsuite xff0c 设置了代
  • 快速解决eclipse无法启动,一启动就报错,且整个项目显示红色感叹号和×

    eclipse中由于没有适配的server xff0c 所以需要用Tomcat来支持项目的运行 xff0c 也会出现各种各样的错误 xff0c 比如eclipse无法启动 xff0c 整个项目显示红色 xff01 和红色 该如何解决 xff
  • un7.10:在IDEA中使用若依框架实现增删改查功能。

    在java的世界中 xff0c 有很多框架提供我们使用 xff0c 今天我们就来讲一讲若依框架 若依框架是一款非常便捷的框架 xff0c 他相对于spring boot框架而言 xff0c 显得更为简单 xff0c 更为便捷 xff0c 比
  • docker常用操作命令。

    docker是一款基于Linux之上的容器 xff0c 由于它的抽象层比虚拟机少 xff0c 而且利用的是主机内流 xff0c 不需要价值操作系统的内核 xff0c 所以它比传统的虚拟机更快 xff0c 所以越来越多的人选择用docker了
  • un8.21:用html实现增删改查功能(代码篇)。

    在项目中 xff0c 我们不仅要在后端代码实现增删改查的功能 xff0c 前端也是必不可少的 xff0c 那么在前端页面中应该如何实现完整的一套增删该查呢 xff1f 接下来附上代码 xff0c 之后的文章里会有详解 一 在html中写出大
  • 达梦(DM)数据库介绍。

    达梦数据库管理系统是达梦公司推出的具有完全自主知识产权的高性能数据库管理系统 简称DM 达梦数据库也属于关系型数据库 xff0c 主要有以下几个概念 数据库 实例 用户 表空间 模式 表 角色 数据文件 DM8采用全新的体系架构 xff0c
  • @TableId注解详细介绍

    64 TableId注解是专门用在主键上的注解 xff0c 如果数据库中的主键字段名和实体中的属性名 xff0c 不一样且不是驼峰之类的对应关系 xff0c 可以在实体中表示主键的属性上加 64 Tableid注解 xff0c 并指定 64
  • mybatis-plus自动填充功能

    有些时候我们可能会有这样的需求 xff0c 插入或者更新数据时 xff0c 希望有些字段可以自动填充数据 xff0c 比如密码 version等 在MP中提供了这样的功能 xff0c 可以实现自动填充 一 添加 64 TableField注
  • mybatis-plus之逻辑删除及通用枚举

    开发系统时 xff0c 有时候在实现功能时 xff0c 删除操作需要实现逻辑删除 xff0c 所谓逻辑删除就是将数据标记为删除 xff0c 而并非真正的物理删除 xff08 非delete操作 xff09 xff0c 查询时需要携带状态条件
  • MATLAB R2014b 的安装破解

    注 xff1a 本博文纯供技术学习之用 xff0c 无意侵权 xff0c 请不要传播转载并在破解24小时之内删除 提要 xff1a 因为考虑到数学建模和日常的数学学习只用安装的matlab xff0c 现在我了解的最新的应该就是matlab
  • 解决Field ‘name‘ doesn‘t have a default value报错

    今天写代码的时候报错Field 39 name 39 doesn 39 t have a default value xff0c 如下图 xff1a 是数据库属性字段没有赋初值 xff0c 然后我就去看数据库 xff0c 发现数据库 先说解
  • 仿macos风格的windows11桌面(适用win10,win11,齐全模板与配件,及相关问题解决方案)

    仿macos风格的windows11桌面在一定程度上加大了对win11的美化同时在原有的操作风格上对win11也进行了风格上的统一 xff0c 废话不多说 xff0c 先上效果图 是不是一眼就有所心动呢 xff0c 先介绍一下这个桌面上真正
  • retina屏是什么意思(Retina屏和一般显示屏幕的区别)

    可能许多比较关注电脑方面的信息或者有关于苹果的消息的小伙伴们都听说过 34 Retina 34 这个词 苹果手机 xff0c Retina视网膜屏幕 xff0c 是指人眼在正常观察距离下 xff0c 视网膜无法区分单个像素 xff0c 不再
  • 新员工-产品经理如何上手一个新产品,进行产品规划并开始工作

    产品规划 nbsp nbsp nbsp 是指产品规划人员通过调查研究 在研究市场 探寻客户 消费者需求 分析竞争对手 衡量外在机会与风险 以及对市场和技术发展态势综合研究的基础上 根据公司自身的情况和发展方向 制定出可以把握市场机会 满足消
  • Lottie动画资源放到服务器预下载,2021年Android开发突破20k有哪些有效的路径

    资源打包成zip文件放到了服务器上 xff0c 所以下载下来要解压缩 LottieAnimationUtils unZip download file parentPath downloadCount true override fun o
  • OkHttp的使用之{RequestBody、FormBody,【一步教学,一步到位