Android Camera2.0 结合ImageReader拍照并解决图片偏转问题

前文Android Camera2.0 API实现摄像头预览并获取人脸关键坐标已经介绍了Camera2.0的基础内容,在2.0的API中,要想实现拍照功能,则要借助于ImageReader。

首先在自定义的TextureView.SurfaceTextureListener的实现类中,维护ImageReader的引用

private ImageReader mImageReader ;

然后在setUpCamera方法中对ImageReader进行初始化

/**
     * 设置camera2.0的初始化参数
     */
    private void setUpCamera() {
        cameraManager = (CameraManager)mContext.getSystemService(Context.CAMERA_SERVICE);
        try{
            for (String id : cameraManager.getCameraIdList()) {

                //获取代表摄像头特征类characteristics
                characteristics = cameraManager.getCameraCharacteristics(id);

                //如果是前置摄像头
                if (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT) {
                    mCameraId = id ;

                    StreamConfigurationMap streamConfigurationMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

                    sizes = streamConfigurationMap.getOutputSizes(SurfaceHolder.class);

                    //设置预览大小
                    mPreviewSize = sizes[0];

                    //imageReader初始化
                    mImageReader = ImageReader.newInstance(mPreviewSize.getWidth(),
                            mPreviewSize.getHeight(),
                            ImageFormat.JPEG,
                            2 );
                    mImageReader.setOnImageAvailableListener(onImageAvailableListener , mBackgroundHandler);

                    //获取人脸检测参数
                    int[] FD =characteristics.get(CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES);
                    int maxFD=characteristics.get(CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT);

                    if (FD.length>0) {
                        List<Integer> fdList = new ArrayList<>();
                        for (int FaceD : FD
                                ) {
                            fdList.add(FaceD);
                            Log.e(TAG, "setUpCameraOutputs: FD type:" + Integer.toString(FaceD));
                        }
                        Log.e(TAG, "setUpCameraOutputs: FD count" + Integer.toString(maxFD));

                        if (maxFD > 0) {
                            mFaceDetectSupported = true;
                            mFaceDetectMode = Collections.max(fdList);
                        }
                    }
                }
            }
        } catch ( CameraAccessException e ){
            e.printStackTrace();
        }
    }

然后将ImageReader的Surface添加进CaptureRequest.Builder中
在startPreview()方法中添加

previewRequestBuilder.addTarget(mImageReader.getSurface());

接下来创建一个类实现ImageReader.OnImageAvailableListener接口,在其中获取每一帧的Image对象,并生成一个Bitmap,并对该Bitmap进行镜像和旋转操作,因为摄像头获取的原始图像和预览中见到的图像是并不一样

/**
*OnImageAvailableListener实现类
*/
    
   private final ImageReader.OnImageAvailableListener onImageAvailableListener = new ImageReader.OnImageAvailableListener() {
        @Override
        public void onImageAvailable(ImageReader reader) {

            Image image = reader.acquireNextImage() ;

            ByteBuffer byteBuffer = image.getPlanes()[0].getBuffer();
            byte[] bytes = new byte[byteBuffer.remaining()];
            byteBuffer.get(bytes);

            try {
                Bitmap temp = BitmapFactory.decodeByteArray(bytes,0,bytes.length);
                Bitmap newBitmap = Bitmap.createBitmap(mPreviewSize.getWidth(),mPreviewSize.getWidth(),temp.getConfig());

                Canvas canvas = new Canvas(newBitmap);
                Paint paint = new Paint();
                Matrix matrix = new Matrix();
                //图片镜像并旋转90度
                matrix.setScale(-1, 1);
                matrix.postTranslate(temp.getWidth(), 0);
                matrix.postRotate(90 ,temp.getWidth()/2,temp.getHeight()/2);
                matrix.postTranslate(0,(temp.getWidth()-temp.getHeight())/2);

                canvas.drawBitmap(temp, matrix , paint );

                File newFile = new File( Environment.getExternalStorageDirectory() , "345.jpg");
                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(newFile));
                newBitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
                bos.flush();
                bos.close();
                temp.recycle();
                newBitmap.recycle();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                image.close();
                byteBuffer.clear();
            }

            image.close();



        }
    };

上面做的是用ImageReader获取每一帧实时图像,要想实现拍照,调用CameraCaptureSession的capture方法即可

public void captureStillImage(){
        try {

            CaptureRequest.Builder captureStillBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            captureStillBuilder.addTarget(mImageReader.getSurface());
            // 设置自动对焦模式
            captureStillBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            // 设置自动曝光模式
            captureStillBuilder.set(CaptureRequest.CONTROL_AE_MODE,
                    CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
            
            int rotation = ((Activity)mContext).getWindowManager().getDefaultDisplay().getRotation();
            captureStillBuilder.set( CaptureRequest.JPEG_ORIENTATION ,
                    ORIENTATIONS.get(rotation));

            CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
                @Override
                public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
                    super.onCaptureCompleted(session, request, result);

                    Toast.makeText(mContext,"Image Captured" , Toast.LENGTH_SHORT).show();
                }



            };

            captureSession.stopRepeating();
            captureSession.capture( captureStillBuilder.build() , captureCallback , null );
            captureSession.setRepeatingRequest(captureRequest, new CameraCaptureSession.CaptureCallback() {
                @Override
                public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber) {
                    super.onCaptureStarted(session, request, timestamp, frameNumber);
                }
            },mBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

在成员变量中设置ROTATION

//设置Surface旋转角
    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);
    }

也欢迎关注个人公众号,移动开发,音视频,图形图像,大厂内推,不定时更新
在这里插入图片描述

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,以下是一个简单的Android Camera2的ImageReader回调函数示例代码,用于将Image的YUV数据转换为RGB格式的Bitmap并保存到本地。在这个示例中,我们将使用JavaCV库来进行YUV转RGB的操作,并使用Bitmap类来保存图像。 ```java private ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { Image image = reader.acquireNextImage(); if (image == null) { return; } // 获取图像的宽度和高度 int width = image.getWidth(); int height = image.getHeight(); // 将YUV数据转换为RGB格式的Bitmap Mat yuvMat = new Mat(height + height / 2, width, CvType.CV_8UC1); ByteBuffer buffer = image.getPlanes()[0].getBuffer(); byte[] data = new byte[buffer.remaining()]; buffer.get(data); yuvMat.put(0, 0, data); Mat rgbMat = new Mat(height, width, CvType.CV_8UC3); Imgproc.cvtColor(yuvMat, rgbMat, Imgproc.COLOR_YUV2RGB_NV21); Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Utils.matToBitmap(rgbMat, bitmap); // 保存Bitmap到本地 String fileName = "image_" + System.currentTimeMillis() + ".jpg"; String filePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + File.separator + fileName; try { FileOutputStream outputStream = new FileOutputStream(filePath); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream); outputStream.close(); } catch (Exception e) { e.printStackTrace(); } image.close(); } }; ``` 请注意,这只是一个简单的示例代码,可能需要根据你的实际需求进行修改。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值