
Android
本文总结了Android相机开发的相关知识和过程,以及容易遇到的陷阱。希望以后可以与Android相机开发联系的朋友能尽快入门,节省时间并避免弯路。Android系统提供了两种使用手机的相机资源来实现拍摄功能的方法。一种是通过Intent直接调用系统摄像机组件。
该方法快速便捷,适用于直接获取照片的场景,例如上传相册和微博。,从朋友圈中发送照片等。另一种方法是使用相机API自定义自定义相机。此方法适用于需要自定义相机界面或开发特殊相机功能(例如裁剪,滤镜处理,添加标签,表情符号和位置标签)的场景。

手机
主要方法如下:SurfaceView:用于绘制相机预览图像的类,为用户提供实时预览图像。普通视图和派生类都共享同一表面,并且所有绘制都必须在UI线程中完成。表面视图是一个相对特殊的视图。它不与其他普通视图共享该表面,但在内部拥有一个独立的表面。
Surfaceview负责管理表面的格式,大小和显示位置。由于UI线程还必须同时处理其他交互逻辑,因此无法保证视图的更新速度和帧速率,并且由于surfaceview具有独立的表面,因此可以在独立的线程中绘制它,因此它可以提供更高的帧速率。
由于自定义相机的预览图像需要较高的更新速度和帧速率,因此更适合于带有表面视图的显示。SurfaceHolder:SurfaceHolder是控制表面的抽象界面,它可以控制表面的大小和格式,修改表面的像素,监视表面的变化等。SurfaceHolder的典型应用是用于表面视图。
Surfaceview通过getHolder()方法获取Surfaceholder实例,并通过后者来管理表面的状态。SurfaceHolder。Callback接口:负责监视表面状态变化的接口,有三种方法:在解释此问题之前,首先介绍Android手机上几个方向的概念:屏幕方向:在Android系统中,屏幕的左上角是坐标系的原点(0,0)坐标。
原点向右的延伸是X轴的正方向,原点向右是Y轴的正方向。相机传感器方向:手机相机的图像数据来自相机硬件的图像传感器。固定在手机上后,该传感器具有默认的视图方向,如下图2所示,坐标的原点位于水平位置。时间的左上角与水平屏幕应用程序的屏幕X方向相同。
。换句话说,它与人像应用程序的屏幕X方向成90度角。图2相机传感器方向相机预览方向:由于手机屏幕可以旋转360度,因此无论手机如何旋转,为了确保用户都能看到“正确”的预览屏幕(此“正确”是指屏幕上显示的屏幕UI预览界面和人眼您前面的屏幕是一致的),Android系统的底层根据当前手机屏幕的方向旋转由图像传感器收集的数据,然后将其发送到显示器系统,因此您可以确保预览屏幕始终“正确”。
可以通过setDisplayOrientation()在相机API中设置相机预览方向。默认情况下,该值为0,与图像传感器一致。因此,对于横向应用Android切换,由于相同的屏幕方向和预览方向,预览图像不会反转90度。但是,对于纵向应用程序,屏幕方向和预览方向是垂直的,因此会出现90度的倒置现象。
为了获取正确的预览图片,您必须通过API将相机的预览方向旋转90度,以使其与屏幕方向保持一致,如图3所示。图3摄像机预览方向(红色箭头是预览方向,蓝色方向是屏幕方向)相机的拍摄方向:单击拍摄按钮时,捕获的照片由图像传感器直接在SD卡上收集的数据生成。
因此,相机的拍摄方向与传感器的方向一致。在解释此问题之前,让我们先谈谈与相机相关的一些尺寸。SurfaceView大小:即,用于在自定义相机应用程序中显示相机预览图像的View的大小。全屏显示时,它就是屏幕的大小。在这里,由Surfaceview显示的预览图像临时称为手机预览图像。
Previewsize:相机硬件提供的预览帧数据大小。预览帧数据被传递到SurfaceView,以实现预览图像的显示。这里,与预览帧数据相对应的预览图像临时称为相机预览图像。Picturesize:相机硬件提供的拍摄框数据的大小。拍摄帧数据可以生成位图文件,最后将其另存为。
jpg或。png格式的图片。这里与捕获的帧数据相对应的图像称为照相机捕获图像。图4说明了上述图像和照片之间的关系。手机预览图像是直接提供给用户观看的图像。它是由相机预览图像生成的,用于拍摄照片的数据来自相机图像。图4几张图像之间的关系以下是我在开发过程中遇到的三种拉伸变形现象:1。
手机预览屏幕中的对象被拉伸和变形。2。照片中的对象被拉伸并变形。3。单击以拍照时,手机的预览屏幕将停止,这时的图像被拉伸并变形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手机上尝试使用前置。比较预览图像和照片之间的差异。这是因为在传输前部摄像机的预览数据时,底部摄像机会进行水平翻转转换,即x方向上的反射镜被翻转180度。
此更改还将影响上一个垂直屏幕预览的方向。最初,如果将后置旋转90度,则预览视图将是正确的。对于前置,如果还旋转了90度,则可以上下看到预览图像。它是上下颠倒的(因为x方向已旋转180度),因此必须再旋转180度才能正确显示。如图5所示,您可以将其与上一个相机预览方向的一起理解。
图5前置预览方向此外,由于捕获的图像没有水平翻转,因此用户会发现前拍摄的照片在预览中向左和向右翻转。这将在一定程度上影响用户体验。为解决此问题,可以在生成位图文件时向前置捕获的图像添加水平翻转矩阵变换。为了节省手机电量而不浪费相机资源,在开发的自定义相机中,如果不再需要显示预览图像,例如按Home键盘切换背景或锁定屏幕,则您应该关闭预览并保存相机资源已发布。
请参阅官方API文档。当surfaceView变为可见时,它将创建一个表面并在surfaceHolder。callback接口中触发surfaceCreated回调函数。当surfaceview变为不可见时,将破坏该表面并触发受表面破坏的回调函数。
我们可以在相应的回调函数中处理与相机相关的操作,例如连接到曲面以及打开/关闭预览。至于相机资源的释放,可以在Acticity暂停的情况下执行。相应地,当您要再次还原预览图像时,可以将应用程序和相机资源的初始化放置在onResumeofActicity中,然后创建Surfaceview,连接相机和曲面并开始预览。
但是,在开发过程中,发现当您按下HOME按钮切换到背景场景时,程序可以正常运行。对于锁定屏幕方案,重新申请摄像机资源时将发生崩溃,表明无法访问摄像机资源。那是什么原因呢?我在代码中添加了调试日志,并检查了代码的执行顺序。结果如下:在自定义相机页面上按下HOME按钮时的执行流程:发现问题。
锁定屏幕后,未执行callback的callback方法,这导致相机和预览之间的连接未断开,并且相机资源被释放。因此,当摄像机资源被重新应用时,系统报告崩溃。根据上面的文档,推测锁定屏幕下的系统没有更改Surfaceview的可见性,因此我尝试在onPause和onResume期间手动设置Surfaceview的visibile属性,发现回调函数可以正常触发。
由于用户在切割背景或锁定屏幕时不应看到表面视图,因此这种手动更改表面视图可见性的方法不会影响用户的体验。
Copyright © 2025 IZhiDa.com All Rights Reserved.
知答 版权所有 粤ICP备2023042255号