当前位置:首页 > 资讯 > 正文

Android Camera2 全屏预览+实时获取预览帧进行图像处理手机怎么调横竖屏「Android Camera2 全屏预览+实时获取预览帧进行图像处理」

之前公司有一个需求:全屏预览的同时将预览图像传到物体检测算法中,得到检测结果(含有识别出的物体的矩阵信息,可以在传入的图像上将其框出来)并实时在预览图像上画出检测框。这里使用的是Camera2 API,而不是Camera。

需要解决的问题有:

  1. Android调用相机在自己的应用内实现视频预览:google自己的Camear2Basic例子中就有这部分内容,需要修改(Google/Camera Samples)。
  2. 实时获取预览的图像资源:这一部分花了我最长时间,网上比较少有详细的说明。
  3. 手机屏幕适配、预览拉伸问题:由于相机输出的分辨率和屏幕上图层的分辨率不一定能百分百吻合,所以得做一些判断和选择。
  4. 物体识别算法会返回根据图片识别出的多个物体的坐标位置和结果,需要实时将其“画”在屏幕上:用一个透明的SurfaceView放置在预览图层之上就可以画框了。
  5. 手机屏幕旋转时的画框问题

开启正文之前先上效果图(后面有源码)

说是全屏,但由于相机输出尺寸和屏幕尺寸并不能完全吻合,而缩放会导致预览拉伸。所以在全面屏上竖直方向上会有留白,一些手机上能达到全屏预览效果(亲测)。
效果图

问题1:Google-Camera2Basic

Google的这个例子很有代表性,虽然里面实现的是在程序内调用相机拍照并保存JPEG图片,但其中调用相机预览的逻辑是可以直接用的,网上也有很多博客对其进行了详细的介绍,这里不是本篇文章的重点,就不再累述了。以下内容也是认为读者已经对该例子基本熟悉,里面的几个函数名和一些变量名我沿用了下来。

ps:建议在官方文档上查找google例子中出现的各种API,文档上很全。至于博客里的,重在看逻辑。

问题2:实时获取预览的图像

2.1 ImageReader设置

这里只讲结论,不讲分析(因为我也不懂图像编码的知识)。
直接上代码:创建ImageReader对象,参数是输入尺寸、格式(ImageFormat)和maxImages,尺寸之后再说,格式选择YUV_420_888(众所周知,JPEG太大,传来传去会很卡),maxImages的大小没什么区别,选5即可。

 
2.2 将ImageReader的Surface设为CaptureRequest的target之一
 
2.3 ImageReader的回调函数
  • 回调函数中能得到的是Image对象,由于用于物体识别的函数参数需要的是cv::Mat的对象,所以我必须将YUV_420_888格式的图像转为cv::Mat,这部分没有学过,但运气很好找到了GitHub上的一个开源算法,很好用:GitHub-quickbirdstudios / yuvToMat,有需要的朋友用的时候记得给个Star啊!
  • 然后这个回调频率和预览刷新的帧率是一样的,帧率太快这里可能会造成crash,所以用一个小技巧来降低调用耗时函数的频率,代码中有备注。
  • 最后记得用完Image一定要close(),不然肯定会crash的。
 

问题3:手机屏幕适配、预览拉伸问题

这部分问题主要涉及到

  1. 屏幕实际尺寸
  2. 相机可用尺寸(是一个列表)
  3. 预览用的TextureView尺寸

前两个在一部手机上是固定的,我们需要根据前两个尺寸来决定预览尺寸(预览尺寸也就决定了画框用的SurfaceView尺寸和ImageReader初始化时的尺寸)。在Google的例子中,预览的尺寸并不是全屏,所以这部分得重写。网上有方案是对TextureView进行缩放:使用TextureView setTransform(Matrix)方法,解决Camera显示变形问题
才用那种方案时,我还需要将图像进行缩放才能保证框能够准确的画在物体上,但缩放会导致预览拉伸,这里是个矛盾的点。
我最终使用了折中的方案:根据相机所能提供的分辨率和屏幕分辨率之间做“适配”,在做到预览不拉伸的前提下尽可能让预览尺寸接近全屏。

3.1 屏幕尺寸获取

这里的逻辑有点乱,主要是因为横竖屏的问题(后来固定竖屏了,这部分没改过来,因为照样可以用)

 
3.2 chooseOptimalSize函数重写
 
3.3 预览TextureView、ImageReader和surfaceView尺寸设置
 

问题4:画框和结果

画框倒是不难的,首先清空Canvas上已有框,然后根据识别出来的坐标画上去即可。

 

问题5:手机屏幕旋转时的画框问题

由于横竖屏切换时用户体验不好,实现起来也比较费劲,而且有一些奇怪的问题我无法解决(这才是主要原因)。所以换成固定竖屏,然后调整Canvas坐标系来适应手机的旋转。

5.1 监听屏幕旋转

首先得监听屏幕方向的旋转,这里选取了四个角度:竖屏、home键朝左、home键朝右和竖屏并上下颠倒。监听可以在onStart()或onResume()回调中开启。

 
5.2 根据屏幕旋转方向调整坐标系

这里需要知道,Android手机固定竖屏时,坐标原点始终在“左上角”,这个左上角指的是正常竖屏放置时的左上角。但输入图像检测时一直都是正常竖直的,所以结果中的坐标也是以图像左上角为坐标原点,如果直接画框,方向肯定是错的。
最简单的解决方案就是旋转Canvas的坐标系,因为它已经提供了函数,很简单使用:canvas.translate和canvas.rotate。这里就不讲Canvas的知识了,网上有很多。

 

源码

github/Preview_Detect
csdn/Preview_Detect

最新文章