Android Camera2 拍照入门学习

来源:互联网 发布:mac os.ios镜像文件 编辑:程序博客网 时间:2024/05/16 15:49

学习资料:

  • 肾虚将军android camera2 详解说明
  • 极客学院android.hardware.camera2 使用指南

Android 5.0(21)之后,android.hardware.Camera被废弃(下面称为Camera1),还有一个android.graphics.Camera,这个android.graphics.Camera不是用来照相的,是用来处理图像的,可以做出3D的图像效果之类的,之前的Camera1则由android.hardware.Camera2来代替

Camera2支持RAW输出,可以调节曝光,对焦模式,快门等,功能比原先Camera强大


1.Camera1使用


使用步骤:

  1. 调用Camera.open(),打开相机,默认为后置,可以根据摄像头ID来指定打开前置还是后置
  2. 调用Camera.getParameters()得到一个Camera.Parameters对象
  3. 使用步骤2得到的Camera.Parameters对象,对拍照参数进行设置
  4. 调用Camera.setPreviewDispaly(SurfaceHolder holder),指定使用哪个SurfaceView来显示预览图片
  5. 调用Camera.startPreview()方法开始预览取景
  6. 调用Camera.takePicture()方法进行拍照
  7. 拍照结束后,调用Camera.stopPreview()结束取景预览,之后再replease()方法释放资源

这几个步骤从疯狂Android讲义中学到


1.1简单使用

使用SurfaceView进行取景的预览,点击屏幕进行拍照,用ImageView来展示拍的照片


取景

拍照预览

想买关于操作系统和C的书看,知乎很多人推荐这两本,就买了,感觉确实不错

布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">    <SurfaceView        android:id="@+id/surface_view_camera2_activity"        android:layout_width="match_parent"        android:layout_height="match_parent" />    <ImageView        android:id="@+id/iv_show_camera2_activity"        android:layout_width="180dp"        android:layout_height="320dp"        android:visibility="gone"        android:layout_centerInParent="true"        android:scaleType="centerCrop" /></RelativeLayout>

Activity代码:

public class CameraActivity extends AppCompatActivity implements View.OnClickListener {    private SurfaceView mSurfaceView;    private SurfaceHolder mSurfaceHolder;    private Camera mCamera;    private ImageView iv_show;    private int viewWidth, viewHeight;//mSurfaceView的宽和高    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_camera2);        initView();    }    /**     * 初始化控件     */    private void initView() {        iv_show = (ImageView) findViewById(R.id.iv_show_camera2_activity);        //mSurfaceView        mSurfaceView = (SurfaceView) findViewById(R.id.surface_view_camera2_activity);        mSurfaceHolder = mSurfaceView.getHolder();        // mSurfaceView 不需要自己的缓冲区        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);        // mSurfaceView添加回调        mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {            @Override            public void surfaceCreated(SurfaceHolder holder) { //SurfaceView创建                // 初始化Camera                initCamera();            }            @Override            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {            }            @Override            public void surfaceDestroyed(SurfaceHolder holder) { //SurfaceView销毁                // 释放Camera资源                if (mCamera != null) {                    mCamera.stopPreview();                    mCamera.release();                }            }        });        //设置点击监听        mSurfaceView.setOnClickListener(this);    }    @Override    public void onWindowFocusChanged(boolean hasFocus) {        super.onWindowFocusChanged(hasFocus);        if (mSurfaceView != null) {            viewWidth = mSurfaceView.getWidth();            viewHeight = mSurfaceView.getHeight();        }    }    /**     * SurfaceHolder 回调接口方法     */    private void initCamera() {        mCamera = Camera.open();//默认开启后置        mCamera.setDisplayOrientation(90);//摄像头进行旋转90°        if (mCamera != null) {            try {                Camera.Parameters parameters = mCamera.getParameters();                //设置预览照片的大小                parameters.setPreviewFpsRange(viewWidth, viewHeight);                //设置相机预览照片帧数                parameters.setPreviewFpsRange(4, 10);                //设置图片格式                parameters.setPictureFormat(ImageFormat.JPEG);                //设置图片的质量                parameters.set("jpeg-quality", 90);                //设置照片的大小                parameters.setPictureSize(viewWidth, viewHeight);                //通过SurfaceView显示预览                mCamera.setPreviewDisplay(mSurfaceHolder);                //开始预览                mCamera.startPreview();            } catch (IOException e) {                e.printStackTrace();            }        }    }    /**     * 点击回调方法     */    @Override    public void onClick(View v) {        if (mCamera == null) return;        //自动对焦后拍照        mCamera.autoFocus(autoFocusCallback);    }    /**     * 自动对焦 对焦成功后 就进行拍照     */    Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {        @Override        public void onAutoFocus(boolean success, Camera camera) {            if (success) {//对焦成功                camera.takePicture(new Camera.ShutterCallback() {//按下快门                    @Override                    public void onShutter() {                      //按下快门瞬间的操作                    }                }, new Camera.PictureCallback() {                    @Override                    public void onPictureTaken(byte[] data, Camera camera) {//是否保存原始图片的信息                    }                }, pictureCallback);            }        }    };    /**     * 获取图片     */    Camera.PictureCallback pictureCallback = new Camera.PictureCallback() {        @Override        public void onPictureTaken(byte[] data, Camera camera) {            final Bitmap resource = BitmapFactory.decodeByteArray(data, 0, data.length);            if (resource == null) {                Toast.makeText(CameraActivity.this, "拍照失败", Toast.LENGTH_SHORT).show();            }            final Matrix matrix = new Matrix();            matrix.setRotate(90);            final Bitmap bitmap = Bitmap.createBitmap(resource, 0, 0, resource.getWidth(), resource.getHeight(), matrix, true);            if (bitmap != null && iv_show != null && iv_show.getVisibility() == View.GONE) {                mCamera.stopPreview();                iv_show.setVisibility(View.VISIBLE);                mSurfaceView.setVisibility(View.GONE);                Toast.makeText(CameraActivity.this, "拍照", Toast.LENGTH_SHORT).show();                iv_show.setImageBitmap(bitmap);            }        }    };}

权限:

<uses-permission android:name="android.permission.CAMERA" />

在获得图片后,想要显示的效果是照片是竖直显示,resource显示的却是逆时针旋转了90°,照片是横着的,就使用matrix.setRotate(90)进行旋转


2.Camera2


Camera2拍照示意图

这里引用了管道的概念将安卓设备和摄像头之间联通起来,系统向摄像头发送 Capture 请求,而摄像头会返回 CameraMetadata。这一切建立在一个叫作 CameraCaptureSession 的会话中。


camera2中主要的类

以上从极客学院android.hardware.camera2 使用指南摘抄

  • CameraManaer 摄像头管理器,用于检测摄像头,打开系统摄像头,调用CameraManager.getCameraCharacteristics(String)可以获取指定摄像头的相关特性
  • CameraCharacteristics 摄像头的特性
  • CameraDevice 摄像头,类似android.hardware.Camera也就是Camera1Camera
  • CameraCaptureSession 这个对象控制摄像头的预览或者拍照,setRepeatingRequest()开启预览,capture()拍照,CameraCaptureSession提供了StateCallback、CaptureCallback两个接口来监听CameraCaptureSession的创建和拍照过程。
  • CameraRequest和CameraRequest.Builder,预览或者拍照时,都需要一个CameraRequest对象。CameraRequest表示一次捕获请求,用来对z照片的各种参数设置,比如对焦模式、曝光模式等。CameraRequest.Builder用来生成CameraRequest对象。

以上从肾虚将军的android camera2 详解说明摘抄


2.1 简单使用

使用的依然是SurfaceView来进行展示预览

主要思路:

  1. 获得摄像头管理器CameraManager mCameraManagermCameraManager.openCamera()来打开摄像头
  2. 指定要打开的摄像头,并创建openCamera()所需要的CameraDevice.StateCallback stateCallback
  3. CameraDevice.StateCallback stateCallback中调用takePreview(),这个方法中,使用CaptureRequest.Builder创建预览需要的CameraRequest,并初始化了CameraCaptureSession,最后调用了setRepeatingRequest(previewRequest, null, childHandler)进行了预览
  4. 点击屏幕,调用takePicture(),这个方法内,最终调用了capture(mCaptureRequest, null, childHandler)
  5. new ImageReader.OnImageAvailableListener(){}回调方法中,将拍照拿到的图片进行展示

代码:

public class Camera2Activity extends AppCompatActivity implements View.OnClickListener {    private static final SparseIntArray ORIENTATIONS = new SparseIntArray();    ///为了使照片竖直显示    static {        ORIENTATIONS.append(Surface.ROTATION_0, 90);        ORIENTATIONS.append(Surface.ROTATION_90, 0);        ORIENTATIONS.append(Surface.ROTATION_180, 270);        ORIENTATIONS.append(Surface.ROTATION_270, 180);    }    private SurfaceView mSurfaceView;    private SurfaceHolder mSurfaceHolder;    private ImageView iv_show;    private CameraManager mCameraManager;//摄像头管理器    private Handler childHandler, mainHandler;    private String mCameraID;//摄像头Id 0 为后  1 为前    private ImageReader mImageReader;    private CameraCaptureSession mCameraCaptureSession;    private CameraDevice mCameraDevice;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_camera2);        initVIew();    }    /**     * 初始化     */    private void initVIew() {        iv_show = (ImageView) findViewById(R.id.iv_show_camera2_activity);        //mSurfaceView        mSurfaceView = (SurfaceView) findViewById(R.id.surface_view_camera2_activity);        mSurfaceView.setOnClickListener(this);        mSurfaceHolder = mSurfaceView.getHolder();        mSurfaceHolder.setKeepScreenOn(true);        // mSurfaceView添加回调        mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {            @Override            public void surfaceCreated(SurfaceHolder holder) { //SurfaceView创建                // 初始化Camera                initCamera2();            }            @Override            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {            }            @Override            public void surfaceDestroyed(SurfaceHolder holder) { //SurfaceView销毁                // 释放Camera资源                  if (null != mCameraDevice) {                        mCameraDevice.close();                     Camera2Activity.this.mCameraDevice = null;                }            }        });    }    /**     * 初始化Camera2     */    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)    private void initCamera2() {        HandlerThread handlerThread = new HandlerThread("Camera2");        handlerThread.start();        childHandler = new Handler(handlerThread.getLooper());        mainHandler = new Handler(getMainLooper());        mCameraID = "" + CameraCharacteristics.LENS_FACING_FRONT;//后摄像头        mImageReader = ImageReader.newInstance(1080, 1920, ImageFormat.JPEG,1);        mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { //可以在这里处理拍照得到的临时照片 例如,写入本地            @Override            public void onImageAvailable(ImageReader reader) {                mCameraDevice.close();                mSurfaceView.setVisibility(View.GONE);                iv_show.setVisibility(View.VISIBLE);                // 拿到拍照照片数据                Image image = reader.acquireNextImage();                ByteBuffer buffer = image.getPlanes()[0].getBuffer();                byte[] bytes = new byte[buffer.remaining()];                buffer.get(bytes);//由缓冲区存入字节数组                final Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);                if (bitmap != null) {                    iv_show.setImageBitmap(bitmap);                }            }        }, mainHandler);        //获取摄像头管理        mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);        try {            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {                return;            }            //打开摄像头            mCameraManager.openCamera(mCameraID, stateCallback, mainHandler);        } catch (CameraAccessException e) {            e.printStackTrace();        }    }    /**     * 摄像头创建监听     */    private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {        @Override        public void onOpened(CameraDevice camera) {//打开摄像头            mCameraDevice = camera;            //开启预览            takePreview();        }        @Override        public void onDisconnected(CameraDevice camera) {//关闭摄像头            if (null != mCameraDevice) {                mCameraDevice.close();                Camera2Activity.this.mCameraDevice = null;            }        }        @Override        public void onError(CameraDevice camera, int error) {//发生错误            Toast.makeText(Camera2Activity.this, "摄像头开启失败", Toast.LENGTH_SHORT).show();        }    };    /**     * 开始预览     */    private void takePreview() {        try {            // 创建预览需要的CaptureRequest.Builder            final CaptureRequest.Builder previewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);            // 将SurfaceView的surface作为CaptureRequest.Builder的目标            previewRequestBuilder.addTarget(mSurfaceHolder.getSurface());            // 创建CameraCaptureSession,该对象负责管理处理预览请求和拍照请求            mCameraDevice.createCaptureSession(Arrays.asList(mSurfaceHolder.getSurface(), mImageReader.getSurface()), new CameraCaptureSession.StateCallback() // ③            {                @Override                public void onConfigured(CameraCaptureSession cameraCaptureSession) {                    if (null == mCameraDevice) return;                    // 当摄像头已经准备好时,开始显示预览                    mCameraCaptureSession = cameraCaptureSession;                    try {                        // 自动对焦                        previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);                        // 打开闪光灯                        previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);                        // 显示预览                        CaptureRequest previewRequest = previewRequestBuilder.build();                        mCameraCaptureSession.setRepeatingRequest(previewRequest, null, childHandler);                    } catch (CameraAccessException e) {                        e.printStackTrace();                    }                }                @Override                public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {                    Toast.makeText(Camera2Activity.this, "配置失败", Toast.LENGTH_SHORT).show();                }            }, childHandler);        } catch (CameraAccessException e) {            e.printStackTrace();        }    }    /**     * 点击事件     */    @Override    public void onClick(View v) {        takePicture();    }    /**     * 拍照     */    private void takePicture() {        if (mCameraDevice == null) return;       // 创建拍照需要的CaptureRequest.Builder        final CaptureRequest.Builder captureRequestBuilder;        try {            captureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);            // 将imageReader的surface作为CaptureRequest.Builder的目标            captureRequestBuilder.addTarget(mImageReader.getSurface());            // 自动对焦            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);            // 自动曝光            captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);            // 获取手机方向            int rotation = getWindowManager().getDefaultDisplay().getRotation();            // 根据设备方向计算设置照片的方向            captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));            //拍照            CaptureRequest mCaptureRequest = captureRequestBuilder.build();            mCameraCaptureSession.capture(mCaptureRequest, null, childHandler);        } catch (CameraAccessException e) {            e.printStackTrace();        }    }}

布局代码以及权限与Camera1中一样,效果一样

预览时,是将mSurfaceHolder.getSurface()作为目标
显示拍照结果时,是将mImageReader.getSurface()作为目标


3.最后

Camera2的功能很强大,暂时也只是学习了最基本的思路

住的地方,没有桌子,于是坐地上,趴在床上敲代码,腰疼。逛淘宝买桌子去

感谢极客学院和肾虚将军的学习资料



文/英勇青铜5(简书作者)
原文链接:http://www.jianshu.com/p/7f766eb2f4e7
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
0 0
原创粉丝点击