Android 相机详解

Camera 相机详解(上)

2019-08-06  本文已影响0人  LiChengZe_Blog
image

前言


进行Camra开发主要用到了以下两个类:

  1. Camera
  2. SurfaceView (当然也可以是TextureView,本文我们使用SurfaceView)

这两者的关系如下图:

image

一、 SurfaceView 、Surface 、 SurfaceHolder

关系图

image

Surface

什么是Surface?源码中是这样描述的:


 * Handle onto a raw buffer that is being managed by the screen compositor.
 *
 * <p>A Surface is generally created by or from a consumer of image buffers (such as a
 * {@link android.graphics.SurfaceTexture}, {@link android.media.MediaRecorder}, or
 * {@link android.renderscript.Allocation}), and is handed to some kind of producer (such as
 * {@link android.opengl.EGL14#eglCreateWindowSurface(android.opengl.EGLDisplay,android.opengl.EGLConfig,java.lang.Object,int[],int) OpenGL},
 * {@link android.media.MediaPlayer#setSurface MediaPlayer}, or
 * {@link android.hardware.camera2.CameraDevice#createCaptureSession CameraDevice}) to draw
 * into.</p>

简单翻译一下,大概意思就是:

Surfaces是用来处理屏幕显示内容合成器所管理的原始缓存区的工具。它通常由图像缓冲区的消费者来创建(如:SurfaceTexture,MediaRecorder),然后被移交给生产者(如:MediaPlayer)或者是显示到其上(如:CameraDevice)

SurfaceHolder

源码描述:

 * Abstract interface to someone holding a display surface.  Allows you to
 * control the surface size and format, edit the pixels in the surface, and
 * monitor changes to the surface.  This interface is typically available
 * through the {@link SurfaceView} class.

简单翻译一下:

一个抽象接口,给持有surface的对象使用。它可以控制surface的大小和格式,编辑surface中的像素,以及监听surface的变化。这个接口通常通过SurfaceView类获得

SurfaceHolder中有一个Callbcak接口,它有3个回调方法

这个回调接口就是源码中所提到的 “monitor changes to the surface”(监听surface的变化),我们后面会用到

SurfaceView

源码描述:

 * Provides a dedicated drawing surface embedded inside of a view hierarchy.
 * You can control the format of this surface and, if you like, its size; the
 * SurfaceView takes care of placing the surface at the correct location on the
 * screen

大致翻译一下:

SurfaceView提供了嵌入视图层级中的专用surface。你可以控制surface的格式或大小。SurfaceView负责把surface显示在屏幕的正确位置

SurfaceView继承自View,其中有两个成员变量,一个是Surface对象,一个是SuraceHolder对象。(请参考上面第二幅关系图)

SurfaceView小结

  1. SurfaceView是一个view对象,用于在屏幕上显示相机的预览画面
  2. SurfaceView中有两个对象,Surface和SuraceHolder。 我们通过SuraceHolder中的回调可以知道Surface的状态(创建、变化、销毁)
  3. 通过getHolder()方法获得当前SurfaceView的SuraceHolder对象

二、Camera

概览图

Camera类中主要的内部类和接口,如下图:

image

Camera类中有很多内部类和方法,下面分别对这些类和方法做介绍:

Camera类中的内部类

CameraInfo

CameraInfo类用来描述相机信息,通过Camera类中getCameraInfo(int cameraId, CameraInfo cameraInfo)方法获得,主要包括以下两个成员变量:

CAMERA_FACING_BACK 和 CAMERA_FACING_FRONT 是CameraInfo类中的静态变量

         * <p>The orientation of the camera image. The value is the angle that the
         * camera image needs to be rotated clockwise so it shows correctly on
         * the display in its natural orientation. It should be 0, 90, 180, or 270.</p>
         *
         * <p>For example, suppose a device has a naturally tall screen. The
         * back-facing camera sensor is mounted in landscape. You are looking at
         * the screen. If the top side of the camera sensor is aligned with the
         * right edge of the screen in natural orientation, the value should be
         * 90\. If the top side of a front-facing camera sensor is aligned with
         * the right of the screen, the value should be 270.</p>

翻译一下,大概意思是:

orientation是相机采集图片的角度。这个值是相机所采集的图片需要顺时针旋转至自然方向的角度值。它必须是0,90,180或270中的一个。
举个栗子:
假如你自然地竖着拿着手机(就是自拍时候的样子...),后置摄像头的传感器在手机里是水平方向的,你现在看着手机,如果传感器的顶部在自然方向上手机屏幕的右边(此时,手机是竖屏,传感器是横屏),那么这个orientation的值就是90。 如果前置摄像头的传感器顶部在手机屏幕右边,那么这个值就是270.

     * Set the clockwise rotation of preview display in degrees. This affects
     * the preview frames and the picture displayed after snapshot. This method
     * is useful for portrait mode applications. Note that preview display of
     * front-facing cameras is flipped horizontally before the rotation, that
     * is, the image is reflected along the central vertical axis of the camera
     * sensor. So the users can see themselves as looking into a mirror.

翻译一下:

设置预览画面顺时针旋转的角度。这个方法会影响预览图像和拍照后显示的照片。这个方法对竖屏应用非常有用。
注意,前置摄像头在进行角度旋转之前,图像会进行一个水平的镜像翻转。
所以用户在看预览图像的时候就像照镜子,看到的是现实的水平方向的镜像。

注:setDisplayOrientation(int degrees)是Camea类中的一个方法,之所以穿插在这里来讲,是为了和上面提到的orientation做一个统一讲解,因为这两个都涉及到了方向问题

看了上面的介绍是不是有点懵逼。。。没关系,下面给小伙伴们详细介绍一下Android手机上几个方向的概念以及在使用Camera过程中会遇到的方向问题:

注:如果你是第一次使用Camera的话,首先要了解以下几点:

  1. 相机图像数据都是来自于相机硬件的图像传感器(Image Sensor),这个Sensor被固定到手机之后是有一个默认的取景方向,且不会改变
  2. 相机在预览的时候是有一个预览方向的,可以通过setDisplayOrientation()设置
  3. 相机所采集的照片也是有一个方向的(就是上面刚刚提到的orientation),这个方向与预览时的方向互不相干
image image image

这里先做个小结:

这些都是些理论,在下篇文章中,会通过实例代码一步步地验证。

好,我们接着看Camera类中的内部类:

Size

图片大小,里面包含两个变量:width和height(图片的宽和高)

Parameters

Parameters是相机服务设置,不同的相机可能是不相同的。比如相机所支持的图片大小,对焦模式等等。下面介绍一下这个类中常用的方法

PreviewCallback

PreviewCallback是一个抽象接口

这些预览到的原始数据是非常有用的,比如我们可以保存下来当做一张照片,还有很多第三方的人脸检测及静默活体检测的sdk,都需要我们把相机预览的数据实时地传递过去。

Face

Face类用来描述通过Camera的人脸检测功能检测到的人脸信息

注意:这个Rect对象中的坐标系并不是安卓屏幕的坐标系,需要进行转换后才能使用,具体会在后面实现人脸检测功能的时候详细介绍

leftEye ,rightEye和mouth这3个人脸中关键点,并不是所有相机都支持的,如果相机不支持的话,这3个的值为null

FaceDetectionListener

这是一个抽象接口,当开始人脸检测时开始回调

Camera类中的方法

设备上每一个物理摄像都是有一个id的,id从0开始,到getNumberOfCameras() - 1 结束

例如,一般的手机上都有前后两个摄像头,那么后置摄像头id就是0,前置摄像头id就是1

  public final void setPreviewDisplay(SurfaceHolder holder) throws IOException {
        if (holder != null) {
            setPreviewSurface(holder.getSurface());
        } else {
            setPreviewSurface((Surface)null);
        }
    }

 public native final void setPreviewSurface(Surface surface) throws IOException;

可以看到 ,这个方法调用了setPreviewSurface(Surface surface),传入的surface对象是holder.getSurface()
那么holder.getSurface()所表示的surface是什么呢?
在SurfaceView的源码中(1088行)找到了答案:

        @Override
        public Surface getSurface() {
            return mSurface;
        }

holder.getSurface()所返回的surface对象就是SurfaceView中的mSurface对象! 这三者的关系见图二

三、总结

  1. Camera负责采集数据和各种操作,SurfaceView负责把Camera采集到的数据实时地显示在屏幕上

  2. 我们通过SuraceHolder中的回调可以监听Surface的状态(创建、变化、销毁)

  3. 相机图像数据都是来自于相机硬件的图像传感器这个方向是不能改变的

  4. 相机在预览的时候是有一个预览方向的,可以通过setDisplayOrientation()设置

  5. 前置摄像头在进行角度旋转之前,图像会进行一个水平的镜像翻转,所以用户在看预览图像的时候就像照镜子一样

  6. 相机所采集的照片也是有一个方向的,这个方向与预览时的方向互不相干

  7. 我们可以通过setParameters(Parameters params)设置当前相机的参数信息,比如 保存的图片大小,对焦模式等等

  8. 在关闭页面 或者 打开其他摄像头之前,一定要先调用release()方法释放当前相机资源

好,到这里关于Camera开发所需要的知识点已经介绍完了。看了这么多枯燥的知识点是不是已经双手痒痒,迫不及待动手撸代码了?在下篇文章中,我将会带着小伙们一块,从零开始实现自己的Camera相机!

上一篇下一篇

猜你喜欢

热点阅读