美文网首页android影音
Android相机<第三篇>:Camera详解

Android相机<第三篇>:Camera详解

作者: NoBugException | 来源:发表于2019-09-16 17:26 被阅读0次

    当我们自定义相机时,常常使用Camera对象完成拍照流程,本文的重点在于研究Camera 各个方法的作用。

    [方法一] 获取Camera对象

    Camera mCamera = Camera.open();
    

    [方法二] 拍照

    public final void takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback postview, PictureCallback jpeg)
    

    使用方法如下:

        mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(byte[] data, Camera camera) {
    
            }
        });
    

    它有一个回调,拍完照片之后会执行onPictureTaken回调方法,data参数为图片的字节数组。

    [方法三] 自动聚焦

    自动聚焦的监听必须放在启动预览界面(mCamera.startPreview())之后,否则部分手机会崩溃。

    实现代码如下:

        //自动获取焦点
        mCamera.autoFocus(autoFocusCallback );
    
    private Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
        @Override
        public void onAutoFocus(boolean success, Camera camera) {
    
        }
    };
    

    此时发现,自动聚焦的回调方法始终只执行一次,那么怎么做才能无限聚焦呢?只要在自动聚焦的回调方法中添加两句代码即可。

    private Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
        @Override
        public void onAutoFocus(boolean success, Camera camera) {
            mCamera.cancelAutoFocus();
            camera.autoFocus(autoFocusCallback);
        }
    };
    

    与设置自动聚焦相比,还有一个方法取消自动聚焦cancelAutoFocus

    以上是实现自动聚焦的其中一个方法,当然还有其它方法,文章下面会介绍。

    [方法四] 锁定、解锁、重连

    //锁定摄像机硬件资源
    mCamera.lock();
    //解锁摄像机硬件资源
    mCamera.unlock();
    //重连
    mCamera.reconnect();
    

    为了防止相机被其它资源利用,相机默认是锁定状态。当其它资源想要利用相机时,必须解锁和重连后才能继续使用相机服务。

    如果仅仅使用拍照,您可能不需要使用这三个方法,当使用MediaRecorder录制时会使用这三个方法获取相机服务。

    [方法五] 设置预览方向

    mCamera.setDisplayOrientation(90);
    

    预览方向默认是横屏的,所以这里要调整一下预览方向。

    [方法六] 设置预览界面

    目前拍照涉及到的预览界面主要有两种:TextureViewSurfaceView

            mCamera.setPreviewDisplay(SurfaceHolder);
            mCamera.setPreviewTexture(SurfaceTexture);
    

    有关TextureViewSurfaceView会在第四篇第五篇介绍。

    [方法七] 设置预览监听

            mCamera.setPreviewCallback(new Camera.PreviewCallback() {
                @Override
                public void onPreviewFrame(byte[] data, Camera camera) {
                    
                }
            });
    

    这个监听最强大的地方在于可以不停的返回一帧画面的图像数据,可以利用OpenGL对图片进行处理。

    设置监听的方法还有一个,如下:

            mCamera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
                @Override
                public void onPreviewFrame(byte[] data, Camera camera) {
                    
                }
            });
    

    这个方法应该是和mCamera.addCallbackBuffer(byte[] callbackBuffer)一起使用,mCamera.addCallbackBuffer(byte[] callbackBuffer)是向缓存队列中添加一个预览帧。

    这两种监听的工作方式差不多,他们都会不停的回调当前预览帧,那么如果获取拍照或者触发聚焦时的预览帧的话,就会使用以下预览监听方案:

            mCamera.setOneShotPreviewCallback(new Camera.PreviewCallback() {
                @Override
                public void onPreviewFrame(byte[] data, Camera camera) {
    
                }
            });
    

    如果处于预览状态,那么会立即回调一个预览帧。

    当触发聚焦时,此时的画面最为清晰,可以使用这个监听获取当前预览帧,根据回调返回的字节数组来处理图像。

    [方法八] 开始预览和停止预览

    当Camera绑定预览界面后,Camera就可以启动预览界面和停止预览界面。

    //启动预览界面
    mCamera.startPreview();
    
    //停止预览界面
    mCamera.stopPreview();
    

    只有启动预览界面之后,预览监听才会收到回调。

    [方法九] 平滑缩放

    有些手机的相机自带缩放功能,当我们用双指缩放预览界面时会触发平滑缩放监听。当然,一些手机不支持平滑缩放功能。

    监听代码如下:

            mCamera.setZoomChangeListener(new Camera.OnZoomChangeListener() {
                @Override
                public void onZoomChange(int zoomValue, boolean stopped, Camera camera) {
                    
                }
            });
    

    zoomValue为当前缩放因子,stopped表示当前缩放是否结束,如果为false则表示缩放正在进行,如果为true表示缩放结束。

    调用startSmoothZoom方法后开始启动平滑缩放功能,代码如下:

            Camera.Parameters parameters = mCamera.getParameters();
            if(parameters.isSmoothZoomSupported()){
                mCamera.startSmoothZoom(1);
            }
    

    startSmoothZoom方法传递一个数值,这个数值就是缩放因子,它的取值范围是:[0,parameters.getMaxZoom()],取值不可超过这个范围,否则报错,在设置缩放因子之前必须先判断手机是否支持平滑缩放,否则设置无效或者异常,设置缩放因子后,缩放监听开始执行。假设当前缩放因子为0,那么执行以下语句:

            if(parameters.isSmoothZoomSupported()){
                mCamera.startSmoothZoom(12);
            }
    

    那么,它不会直接从0变成12,设置缩放因子需要消耗一定的时间,它的变化过程如下:

    • 当从0变成1时,触发一次监听回调,zoomValue=1,stopped=false
    • 当从1变成2时,触发一次监听回调,zoomValue=2,stopped=false
    • 当从2变成3时,触发一次监听回调,zoomValue=3,stopped=false
    • 当从3变成4时,触发一次监听回调,zoomValue=4,stopped=false
    • 当从4变成5时,触发一次监听回调,zoomValue=5,stopped=false
    • 当从5变成6时,触发一次监听回调,zoomValue=6,stopped=false
    • 当从6变成7时,触发一次监听回调,zoomValue=7,stopped=false
    • 当从7变成8时,触发一次监听回调,zoomValue=8,stopped=false
    • 当从8变成9时,触发一次监听回调,zoomValue=9,stopped=false
    • 当从9变成10时,触发一次监听回调,zoomValue=10,stopped=false
    • 当从10变成11时,触发一次监听回调,zoomValue=11,stopped=false
    • 当从11变成12时,触发一次监听回调,zoomValue=12,stopped=true

    也就是说,平滑缩放的监听回调执行了12次。

    在这个过程中,可以提前停止缩放,只要执行这个方法即可

        mCamera.stopSmoothZoom();
    

    startSmoothZoomstopSmoothZoom这两个方法必须在启动预览界面(mCamera.startPreview())之后执行,否则会报错。

    [方法十] 相机异常监听

            mCamera.setErrorCallback(new Camera.ErrorCallback() {
                @Override
                public void onError(int error, Camera camera) {
                    switch (error){
                        case Camera.CAMERA_ERROR_UNKNOWN:
                            System.out.println("相机未知错误");
                            break;
                        case Camera.CAMERA_ERROR_EVICTED:
                            System.out.println("相机已断开连接");
                            break;
                        case Camera.CAMERA_ERROR_SERVER_DIED:
                            System.out.println("媒体服务器死机");
                            break;
                        default:
                            System.out.println("未知异常error:"+error);
                            break;
    
                    }
                }
            });
    

    可以监听相机使用过程之的错误。

    [方法十一] 设置拍照后,存入本地图片的格式

            Camera.Parameters parameters = mCamera.getParameters();
            parameters.setPictureFormat(ImageFormat.JPEG);
            mCamera.setParameters(parameters);
    

    setPictureFormat可以设置图片格式。

    [方法十二] 解决输出图片旋转90度问题

            Camera.Parameters parameters = mCamera.getParameters();
            parameters.setRotation(90);
            mCamera.setParameters(parameters);
    

    [方法十三] 设置预览大小和图片大小

    设置预览大小就是设置预览界面的显示图像的分辨率

            Camera.Parameters parameters = mCamera.getParameters();
            Camera.Size previewSize = getCameraSize(parameters.getSupportedPreviewSizes(), width, height);
            parameters.setPreviewSize(previewSize.width, previewSize.height);
            mCamera.setParameters(parameters);
    

    设置图片大小就是设置保存到本地的图片分辨率

            Camera.Parameters parameters = mCamera.getParameters();
            Camera.Size pictureSize = getCameraSize(parameters.getSupportedPictureSizes(), width, height);
            parameters.setPictureSize(pictureSize.width, pictureSize.height);
            mCamera.setParameters(parameters);
    

    其中getCameraSize方法就是筛选出最适合的分辨率。

    /**
     * 获取最合适的Size
     * @param sizeList
     * @param width
     * @param height
     * @return
     */
    private Camera.Size getCameraSize(List<Camera.Size> sizeList, int width, int height){
    
        Camera.Size tempSize = null;
        float aspectRatio = height * 1.0f / width;//求出预期横宽比
        float offset = aspectRatio;//预期横宽比和实际横宽比误差
    
        for(Camera.Size size : sizeList){
    
            if(size.width < height || size.height < width){
                continue;
            }
    
            //误差最小值
            if(Math.abs(aspectRatio - size.width * 1.0f / size.height) < offset){
                offset = Math.abs(aspectRatio - size.width * 1.0f / size.height);
                tempSize = size;
            }
        }
    
        if(tempSize == null){
            tempSize = sizeList.get(0);
        }
    
    
        return tempSize;
    }
    

    [方法十四] 聚焦模式

    Camera.Parameters parameters = mCamera.getParameters();
    parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
    mCamera.setParameters(parameters);
    

    调用setFocusMode方法可以设置聚焦模式,聚焦模式有很多:

    FOCUS_MODE_AUTOFOCUS_MODE_INFINITYFOCUS_MODE_MACROFOCUS_MODE_FIXEDFOCUS_MODE_EDOFFOCUS_MODE_CONTINUOUS_VIDEOFOCUS_MODE_CONTINUOUS_PICTURE,这些模式用到的有两种模式,分别是:FOCUS_MODE_CONTINUOUS_PICTUREFOCUS_MODE_CONTINUOUS_VIDEO

    这两个参数最大的作用是可以不断的触发聚焦,并且可以接收到监听的回调。

            mCamera.setAutoFocusMoveCallback(new Camera.AutoFocusMoveCallback() {
                @Override
                public void onAutoFocusMoving(boolean start, Camera camera) {
                    
                }
            });
    

    监听setAutoFocusMoveCallback与聚焦模式结合使用可以实现随时聚焦功能,类似于[方法三]中说到的自动聚焦,但是autoFocus不可以和setAutoFocusMoveCallback混用,有些手机混用是没有问题的,但是有些手机一旦触发了autoFocus监听,那么setAutoFocusMoveCallback监听就会中断,所以这两个触发聚焦功能只能选择一个。

    代码实现如下:

            mCamera.setAutoFocusMoveCallback(new Camera.AutoFocusMoveCallback() {
                @Override
                public void onAutoFocusMoving(boolean start, Camera camera) {
    
                }
            });
    
    parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);     
    
    //或者     
    //parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
    

    [方法十五] 拍照声音

    enableShutterSound方法可以打开拍照声音,如下:

            mCamera.enableShutterSound(true);
    

    true为打开拍照声音,false为关闭拍照声音。

    不过,有一点需要注意

        //拍照
        mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(byte[] data, Camera camera) {
    
            }
        });
    

    如果takePicture的第一个参数为null,那么不管怎么设置enableShutterSound都不会有拍照声音。

        //拍照
        mCamera.takePicture(new Camera.ShutterCallback() {
            @Override
            public void onShutter() {
                
            }
        }, null, null, new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(byte[] data, Camera camera) {
    
            }
        });
    

    如上代码,保证第一个参数不为空,这样enableShutterSound才能保证有效。

    [方法十六] 人脸检测

    自从Android 6.0开始,Android就开始支持人脸识别功能。

    设置面部识别监听:

            mCamera.setFaceDetectionListener(new Camera.FaceDetectionListener() {
                @Override
                public void onFaceDetection(Camera.Face[] faces, Camera camera) {
                    if(faces != null && faces.length > 0){
    
                    }
                }
            });
    

    开始面部识别:

            mCamera.startFaceDetection();
    

    停止面部识别:

            mCamera.stopFaceDetection();
    

    [方法十七] 释放相机资源

    mCamera.release();
    

    请注意,一旦释放了相机资源,想要重启相机时必须重新执行以下代码:

    Camera mCamera = Camera.open();
    
    说明

    另外,Camera.Parameters还有需要参数都没有讲到,因为感觉只要说明一下常用的即可。在Andorid5.0开始,Camera已被废弃,改为Camera2Camera2将会在后面章节会讲到。

    [本章完...]

    相关文章

      网友评论

        本文标题:Android相机<第三篇>:Camera详解

        本文链接:https://www.haomeiwen.com/subject/bbrcyctx.html