Android相机开发陷阱

电脑杂谈  发布时间:2020-06-29 05:15:55  来源:网络整理

android 设置fragment切换效果_android 切换_android viewpager 图片滑动切换

最近,我负责开发与Android相机相关的要求. 新功能允许用户使用手机快速拍摄特定尺寸(1: 1或3: 4)的照片,并支持在拍摄的照片上粘贴标签. 相关操作. 由于我之前从未接触过Android相机开发,因此在整个开发过程中我走了很多路,这花了很多时间和精力. 本文总结了Android相机开发的相关知识和过程,以及容易遇到的陷阱. 希望以后可以与Android相机开发联系的朋友能尽快入门,节省时间并避免弯路.

Android系统提供了两种使用手机的相机资源来实现拍摄功能的方法. 一种是通过Intent直接调用系统摄像机组件. 该方法快速便捷,适用于直接获取照片的场景,例如上传相册和微博. ,从朋友圈中发送照片等. 另一种方法是使用相机API自定义自定义相机. 此方法适用于需要自定义相机界面或开发特殊相机功能(例如裁剪,滤镜处理,添加标签,表情符号和位置标签)的场景. 本文主要从如何使用相机API定制自定义相机的方向出发.

通过照相机API实现拍摄功能涉及以下关键类和接口:

相机: 最重要的类用于管理和操作相机资源. 它提供了完整的相机底部界面,支持相机资源切换,设置预览/拍摄尺寸,设置光圈,曝光,对焦和其他相关参数,并获得预览/拍摄帧数据和其他功能. 主要方法如下:

SurfaceView: 用于绘制相机预览图像的类,为用户提供实时预览图像. 普通视图和派生类都共享同一表面,并且所有绘制都必须在UI线程中完成. 表面视图是一个相对特殊的视图. 它不与其他普通视图共享该表面,但在内部拥有一个独立的表面. Surfaceview负责管理表面的格式,大小和显示位置. 由于UI线程还必须同时处理其他交互逻辑,因此无法保证视图的更新速度和帧速率,并且由于surfaceview具有独立的表面,因此可以在独立的线程中绘制它,因此它可以提供更高的帧速率. 由于自定义相机的预览图像需要较高的更新速度和帧速率,因此更适合于带有表面视图的显示.

SurfaceHolder: SurfaceHolder是控制表面的抽象界面,它可以控制表面的大小和格式,修改表面的像素,监视表面的变化等. SurfaceHolder的典型应用是用于表面视图. Surfaceview通过getHolder()方法获取Surfaceholder实例,并通过后者来管理表面的状态.

SurfaceHolder.Callback接口: 负责监视表面状态变化的接口,有三种方法:

在解释此问题之前,首先介绍Android手机上几个方向的概念:

屏幕方向: 在Android系统中,屏幕的左上角是坐标系的原点(0,0)坐标. 原点向右的延伸是X轴的正方向,原点向右是Y轴的正方向.

android 设置fragment切换效果_android 切换_android viewpager 图片滑动切换

相机传感器方向: 手机相机的图像数据来自相机硬件的图像传感器. 固定在手机上后,该传感器具有默认的视图方向,如下图2所示,坐标的原点位于水平位置. 时间的左上角与水平屏幕应用程序的屏幕X方向相同. . 换句话说,它与人像应用程序的屏幕X方向成90度角.

图2相机传感器方向

相机预览方向: 由于手机屏幕可以旋转360度,因此无论手机如何旋转,为了确保用户都能看到“正确”的预览屏幕(此“正确”是指屏幕上显示的屏幕UI预览界面和人眼您前面的屏幕是一致的),Android系统的底层根据当前手机屏幕的方向旋转由图像传感器收集的数据,然后将其发送到显示器系统,因此您可以确保预览屏幕始终“正确”. 可以通过setDisplayOrientation()在相机API中设置相机预览方向. 默认情况下,该值为0,与图像传感器一致. 因此,对于横向应用android 切换,由于相同的屏幕方向和预览方向,预览图像不会反转90度. 但是,对于纵向应用程序,屏幕方向和预览方向是垂直的,因此会出现90度的倒置现象. 为了获取正确的预览图片,您必须通过API将相机的预览方向旋转90度,以使其与屏幕方向保持一致,如图3所示.

图3摄像机预览方向

(红色箭头是预览方向,蓝色方向是屏幕方向)

相机的拍摄方向: 单击拍摄按钮时,捕获的照片由图像传感器直接在SD卡上收集的数据生成. 因此,相机的拍摄方向与传感器的方向一致.

在解释此问题之前,让我们先谈谈与相机相关的一些尺寸.

android viewpager 图片滑动切换_android 设置fragment切换效果_android 切换

SurfaceView大小: 即,用于在自定义相机应用程序中显示相机预览图像的View的大小. 全屏显示时,它就是屏幕的大小. 在这里,由Surfaceview显示的预览图像临时称为手机预览图像.

Previewsize: 相机硬件提供的预览帧数据大小. 预览帧数据被传递到SurfaceView,以实现预览图像的显示. 这里,与预览帧数据相对应的预览图像临时称为相机预览图像.

Picturesize: 相机硬件提供的拍摄框数据的大小. 拍摄帧数据可以生成位图文件,最后将其另存为.jpg或.png格式的图片. 这里与捕获的帧数据相对应的图像称为照相机捕获图像. 图4说明了上述图像和照片之间的关系. 手机预览图像是直接提供给用户观看的图像. 它是由相机预览图像生成的,用于拍摄照片的数据来自相机图像.

图4几张图像之间的关系

以下是我在开发过程中遇到的三种拉伸变形现象:

1. 手机预览屏幕中的对象被拉伸和变形.

2. 照片中的对象被拉伸并变形.

3. 单击以拍照时,手机的预览屏幕将停止,这时的图像被拉伸并变形android 切换,然后在恢复预览屏幕后,图像将再次恢复正常.

android viewpager 图片滑动切换_android 设置fragment切换效果_android 切换

现象1是SurfaceView和Previewsize的纵横比不一致. 因为手机预览视图的图像会根据SurfaceView的大小由相机预览图像缩放,所以当宽高比不一致时,图像将不可避免地变形. 后两种现象的原因是Previewsize和Picturesize的长宽比之间不一致. 检查相关信息,发现特定原因与某些手机硬件的基础实现有关. 简而言之,为了避免上述变形现象的发生,最好在开发过程中开发SurfaceView,PreviewSize和PictureSize的三个尺寸,以确保长宽比相同. 具体的实现方式可以首先通过camera.getSupportedPreviewSizes()和camera.getSupportedPictureSizes()获得相机硬件支持的所有预览和拍摄尺寸,然后过滤出与SurfaceView的长宽比一致的尺寸和合适的尺寸,通过camera.setPrameters更新设置. 注意: 市场上手机硬件支持的尺寸通常为4: 3或16: 9,因此SurfaceView的尺寸不要太奇怪,最好将其设置为这样的宽高比.

发生崩溃的前两个原因是: 相机硬件必须在对焦和拍照之前确保已将其连接到表面,并且相机预览已打开,并且表面已接收到预览数据. 如果在未调用camera.setPreviewDisplay或camera.startPreview之前调用camera.autofocus或camera.takepicture,则将发生此运行时异常. 对应于自定义相机的代码,在执行camera.autofocus或camera.takepicture之前,必须注意相机按钮,请确保检查相机是否已设置预览Surfaceview并打开相机预览. 这是一种判断预览状态的方法: Camera.setPreviewCallback是用于预览帧数据的回调函数. 当SurfaceView接收到相机的预览帧数据时将调用它,因此您可以设置是否允许聚焦并拍照.

还必须注意,camera.takePicture()将在执行过程中执行camera.stopPreview以获取拍摄帧数据,这显示为预览屏幕被卡住,并且如果用户单击此按钮时间,即所谓的相机拍摄,上面的崩溃也会出现,因此在开发过程中,您可能还需要阻止连续单击相机按钮.

第三次崩溃涉及裁剪图像. 由于需要支持1: 1或4: 3尺寸的镜头,因此有必要裁剪预览视图. 由于它是垂直屏幕应用程序,因此裁剪区域和相机传感器的坐标系方向为90度角. 在裁剪中,屏幕上的x方向对应于捕获图像上的高度方向,屏幕上的y方向对应于捕获图像上的宽度方向. 因此,计算时必须注意坐标系的转换和越界保护.

android 切换_android 设置fragment切换效果_android viewpager 图片滑动切换

Android相机硬件具有特殊设置. 对于前置,在显示预览视图时使用类似镜面的效果,并显示的镜像. 拍摄的照片仍会用相机成像. 看到这一点,您可能会有一些疑问. 您可以立即在Android手机上尝试使用前置. 比较预览图像和照片之间的差异. 这是因为在传输前部摄像机的预览数据时,底部摄像机会进行水平翻转转换,即x方向上的反射镜被翻转180度. 此更改还将影响上一个垂直屏幕预览的方向. 最初,如果将后置旋转90度,则预览视图将是正确的. 对于前置,如果还旋转了90度,则可以上下看到预览图像. 它是上下颠倒的(因为x方向已旋转180度),因此必须再旋转180度才能正确显示. 如图5所示,您可以将其与上一个相机预览方向的一起理解.

图5前置预览方向

此外,由于捕获的图像没有水平翻转,因此用户会发现前拍摄的照片在预览中向左和向右翻转. 这将在一定程度上影响用户体验. 为解决此问题,可以在生成位图文件时向前置捕获的图像添加水平翻转矩阵变换.

为了节省手机电量而不浪费相机资源,在开发的自定义相机中,如果不再需要显示预览图像,例如按Home键盘切换背景或锁定屏幕,则您应该关闭预览并保存相机资源已发布. 请参阅官方API文档. 当surfaceView变为可见时,它将创建一个表面并在surfaceHolder.callback接口中触发surfaceCreated回调函数. 当surfaceview变为不可见时,将破坏该表面并触发受表面破坏的回调函数. 我们可以在相应的回调函数中处理与相机相关的操作,例如连接到曲面以及打开/关闭预览. 至于相机资源的释放,可以在Acticity暂停的情况下执行. 相应地,当您要再次还原预览图像时,可以将应用程序和相机资源的初始化放置在onResume of Acticity中,然后创建Surfaceview,连接相机和曲面并开始预览.

但是,在开发过程中,发现当您按下HOME按钮切换到背景场景时,程序可以正常运行. 对于锁定屏幕方案,重新申请摄像机资源时将发生崩溃,表明无法访问摄像机资源. 那是什么原因呢?我在代码中添加了调试日志,并检查了代码的执行顺序. 结果如下:

在自定义相机页面上按下HOME按钮时的执行流程:

发现问题. 锁定屏幕后,未执行callback的callback方法,这导致相机和预览之间的连接未断开,并且相机资源被释放. 因此,当摄像机资源被重新应用时,系统报告崩溃. 根据上面的文档,推测锁定屏幕下的系统没有更改Surfaceview的可见性,因此我尝试在onPause和onResume期间手动设置Surfaceview的visibile属性,发现回调函数可以正常触发. 由于用户在切割背景或锁定屏幕时不应看到表面视图,因此这种手动更改表面视图可见性的方法不会影响用户的体验.


本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/ruanjian/article-262007-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      热点图片
      拼命载入中...