美文网首页
android 相机预览拉伸问题

android 相机预览拉伸问题

作者: MrY_124d | 来源:发表于2019-08-01 15:36 被阅读0次

    相机拉升 是因为 SurfaceView预览 与 相机分辨率不一致导致的

            <com.android.opencvapplication.camera.CameraView
                android:id="@+id/cameraView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
    
    public class MatcherActivity{
        .....
        @Override
        protected void onStart() {
            cameraView.setListener(this);
            cameraView.startPreview(Camera.CameraInfo.CAMERA_FACING_BACK, CameraManager.PREVIEW_SIZE_480P);
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            cameraView.stopPreview();
        }
    }
    
    

    CameraView 讲解

    设置 SurfaceView 的大小和 camera 的大小一致;
    onMeasure 是重点,根据camera 大 设置 surfaceView大小

    public class CameraView extends SurfaceView implements SurfaceHolder.Callback, CameraManager.OnCameraManagerListener {
        .....
        private CameraManager mCameraManager;
        ....
        public CameraView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
    
        private void init() {
            getHolder().addCallback(this);
            mCameraManager = new CameraManager();
            mCameraManager.setListener(this);
        }
    
        onMeasure 是重点,根据camera 大 设置 surfaceView大小
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            int width = resolveSize(0, widthMeasureSpec);
            int height = resolveSize(width * mCameraSize.width / mCameraSize.height, heightMeasureSpec);
            setMeasuredDimension(width, height);
            L.d("onMeasure");
        }
    
        @Override
        public void onCamera(Camera camera) {
            L.d("onCamera");
            mCameraSize = camera.getParameters().getPreviewSize();
        }
    
       public void startPreview(int cameraId, int dpi) {
            mCameraManager.openCamera(cameraId, dpi);
            if (mSurfaceHolder != null) {
                mCameraManager.startPreview(mSurfaceHolder);
            }
        }
    
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            mCameraManager.releaseCamera();
        }
    }
    

    CameraManager 代码讲解

    public class CameraManager implements Camera.PreviewCallback {
        ....
        private int previewSize = PREVIEW_SIZE_720P;
        public static final int PREVIEW_SIZE_1080P = 1080;
        public static final int PREVIEW_SIZE_960P = 960;
        public static final int PREVIEW_SIZE_720P = 720;
        public static final int PREVIEW_SIZE_480P = 480;
    
        public void openCamera(int cameraId) {
            openCamera(cameraId, PREVIEW_SIZE_720P);
        }
    
        /**
         * @param cameraId    前后摄像头Id
         * @param previewSize def PREVIEW_SIZE_720P
         */
        public void openCamera(int cameraId, int previewSize) {
           ....
           获取相机硬件预览大小
            mParameters = mCamera.getParameters();
            mPictureSizes = mParameters.getSupportedPictureSizes();
            mPreviewSizes = mParameters.getSupportedPreviewSizes();
            Collections.reverse(mPictureSizes);
            Collections.reverse(mPreviewSizes);
    
            //选择合适的分辨率
            Camera.Size size = calculateCameraFrameSize(mPreviewSizes, previewSize, 0);
            Log.i(TAG, "Camera.Size:" + size.width + "x" + size.height);
            //设置预览 与 照片
            setParameters(previewSize, size.width, size.height);
            addCameraCallBack();
        }
    
        private void addCameraCallBack() {
            ....
            返回相机
            if (mListener != null)
                mListener.onCamera(mCamera);
        }
    
        private void setParameters(int pictureSize, int width, int height) {
            float rate = (float) width / height;//比例
            rate = Float.valueOf(String.format(Locale.getDefault(), "%.2f", rate));
            Log.i(TAG, "相机预览:" + width + "x" + height + "--" + pictureSize + " dpi----rate:" + rate + "---");
            Camera.Size size;
    
            .....
            设置预览大小
            size = calculateCameraFrameSize(mPreviewSizes, pictureSize, rate);
            mParameters.setPreviewSize(size.width, size.height);
            Log.i(TAG, "设置预览:w = " + size.width + "x" + size.height + "--rate:" + (float) size.width / size.height);
            mParameters.setPreviewFormat(ImageFormat.NV21);
            .....
        }
    
         protected Camera.Size calculateCameraFrameSize(List<Camera.Size> supportedSizes, int previewSize, float rate) {
            int k = 0;
            int calcWidth = 0;
            int calcHeight = 0;
            for (int i = 0; i < supportedSizes.size(); i++) {
                Camera.Size size = supportedSizes.get(i);
                int width = size.width;
                int height = size.height;
                if (equalRate(size, rate)) {
                    Log.i(TAG, "CameraSize:" + width + "x" + height + "--rate:" + (float) width / height);
                    //1088 这个像素容易出错
                    if (width >= calcWidth && height >= calcHeight && height <= previewSize && height != 1088) {//960
                        calcWidth = width;
                        calcHeight = height;
                        k = i;
                    }
                }
            }
            return supportedSizes.get(k);
        }
    }
    

    完整的 CameraManager 代码

    import android.graphics.ImageFormat;
    import android.hardware.Camera;
    import android.os.Build;
    import android.util.Log;
    import android.util.Size;
    import android.view.SurfaceHolder;
    
    import com.android.opencvapplication.util.L;
    
    import java.io.IOException;
    import java.util.Collections;
    import java.util.List;
    import java.util.Locale;
    
    /**
     * Created by My on 2017/12/13.
     * 相机管理
     */
    
    public class CameraManager implements Camera.PreviewCallback {
        private String TAG = CameraManager.class.getSimpleName();
    
        private int previewSize = PREVIEW_SIZE_720P;
        public static final int PREVIEW_SIZE_1080P = 1080;
        public static final int PREVIEW_SIZE_960P = 960;
        public static final int PREVIEW_SIZE_720P = 720;
        public static final int PREVIEW_SIZE_480P = 480;
    
        private int numCameras = Camera.getNumberOfCameras(); // 初始化摄像头数量
        private Camera mCamera;
        private Camera.Parameters mParameters;
        private List<Camera.Size> mPictureSizes;
        private List<Camera.Size> mPreviewSizes;
        private Camera.Parameters parameters;
        private byte[] mBuffer;
        private boolean previewing;
        private OnCameraManagerListener mListener;
    
        public void setListener(OnCameraManagerListener listener) {
            mListener = listener;
        }
    
        public boolean isPreviewing() {
            return previewing;
        }
    
        public void openCamera(int cameraId) {
            openCamera(cameraId, PREVIEW_SIZE_720P);
        }
    
        /**
         * @param cameraId    前后摄像头Id
         * @param previewSize def PREVIEW_SIZE_720P
         */
        public void openCamera(int cameraId, int previewSize) {
            this.previewSize = previewSize;
            if (mCamera != null) {
                mCamera.stopPreview();
                mCamera.release();
                mCamera = null;
            }
            //有效的 cameraId 时,打开当前摄像头,否则打开后置摄像头
            cameraId = cameraId >= 0 && cameraId < numCameras ? cameraId : Camera.CameraInfo.CAMERA_FACING_BACK;
            mCamera = Camera.open(cameraId);
    
            mCamera.setDisplayOrientation(90);//设置旋转90度
    
            mParameters = mCamera.getParameters();
            mPictureSizes = mParameters.getSupportedPictureSizes();
            mPreviewSizes = mParameters.getSupportedPreviewSizes();
            Collections.reverse(mPictureSizes);
            Collections.reverse(mPreviewSizes);
    
            //选择合适的分辨率
            Camera.Size size = calculateCameraFrameSize(mPreviewSizes, previewSize, 0);
            Log.i(TAG, "Camera.Size:" + size.width + "x" + size.height);
            //设置预览 与 照片
            setParameters(previewSize, size.width, size.height);
            addCameraCallBack();
        }
    
        public void startPreview(SurfaceHolder surfaceHolder) {
            if (previewing)
                stopPreview();
            try {
                mCamera.setPreviewCallback(this);
                mCamera.setPreviewDisplay(surfaceHolder);
                mCamera.startPreview();
                previewing = true;
                Log.d(TAG, "startPreview");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public void stopPreview() {
            if (mCamera != null && previewing) {
                mCamera.stopPreview();
                mCamera.setPreviewCallback(null);  // Camera is being used after Camera.release() was called
                previewing = false;
                Log.d(TAG, "stopPreview");
            }
        }
    
        private void setParameters(int pictureSize, int width, int height) {
            float rate = (float) width / height;//比例
            rate = Float.valueOf(String.format(Locale.getDefault(), "%.2f", rate));
            Log.i(TAG, "相机预览:" + width + "x" + height + "--" + pictureSize + " dpi----rate:" + rate + "---");
            Camera.Size size;
            if (pictureSize > 0) {
                size = calculateCameraFrameSize(mPictureSizes, pictureSize, rate);
            } else {
                size = mPictureSizes.get(mPictureSizes.size() - 1);
            }
            mParameters.setPictureSize(size.width, size.height);
            Log.i(TAG, "设置图片:w = " + size.width + "x" + size.height + "--rate:" + (float) size.width / size.height);
    
            size = calculateCameraFrameSize(mPreviewSizes, pictureSize, rate);
            mParameters.setPreviewSize(size.width, size.height);
            Log.i(TAG, "设置预览:w = " + size.width + "x" + size.height + "--rate:" + (float) size.width / size.height);
    
            mParameters.setPreviewFormat(ImageFormat.NV21);
    
            List<String> FocusModes = mParameters.getSupportedFocusModes();
            if (FocusModes != null && FocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
                mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
            }
            //mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);//连续对焦
    
            //以下两句 影响 小米5 自动对焦
    //        mParameters.setSceneMode(Camera.Parameters.SCENE_MODE_STEADYPHOTO);
    //        mParameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
    
            try {
                mCamera.setParameters(mParameters);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        private void addCameraCallBack() {
            Camera.Parameters params = mCamera.getParameters();
            int mFrameWidth = params.getPreviewSize().width;
            int mFrameHeight = params.getPreviewSize().height;
    
            int pxSize = mFrameWidth * mFrameHeight;
            pxSize = pxSize * ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8;
            mBuffer = new byte[pxSize];
    
            mCamera.addCallbackBuffer(mBuffer);
            mCamera.setPreviewCallbackWithBuffer(this);
    
            if (mListener != null)
                mListener.onCamera(mCamera);
        }
    
        protected Camera.Size calculateCameraFrameSize(List<Camera.Size> supportedSizes, int previewSize, float rate) {
            int k = 0;
            int calcWidth = 0;
            int calcHeight = 0;
            for (int i = 0; i < supportedSizes.size(); i++) {
                Camera.Size size = supportedSizes.get(i);
                int width = size.width;
                int height = size.height;
                if (equalRate(size, rate)) {
                    Log.i(TAG, "CameraSize:" + width + "x" + height + "--rate:" + (float) width / height);
                    //1088 这个像素容易出错
                    if (width >= calcWidth && height >= calcHeight && height <= previewSize && height != 1088) {//960
                        calcWidth = width;
                        calcHeight = height;
                        k = i;
                    }
                }
            }
            return supportedSizes.get(k);
        }
    
        /**
         * 比例
         *
         * @param size
         * @param rate 16:9 1.777777
         * @return
         */
        private boolean equalRate(Camera.Size size, float rate) {
            if (rate <= 0)
                return true;
            return (double) Math.abs((float) size.width / (float) size.height - rate) <= 0.2D;
        }
    
        public void releaseCamera() {
            synchronized (this) {
                if (mCamera != null) {
                    mCamera.stopPreview();
                    mCamera.setPreviewCallback(null);
                    mCamera.release();
                }
                mCamera = null;
                if (mListener != null)
                    mListener.onReleaseCamera();
            }
        }
    
        /**
         * 聚焦
         */
        public void doAutoFocus() {
            try {
                mCamera.cancelAutoFocus();
                parameters = mCamera.getParameters();
                parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
                mCamera.setParameters(parameters);
                mCamera.autoFocus(new Camera.AutoFocusCallback() {
                    @Override
                    public void onAutoFocus(boolean success, Camera camera) {
                        if (success) {
                            camera.cancelAutoFocus();// 只有加上了这一句,才会自动对焦。
                            if (!Build.MODEL.equals("KORIDY H30")) {
                                parameters = camera.getParameters();
                                parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);// 1连续对焦
    //                            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 1连续对焦
                                camera.setParameters(parameters);
                            } else {
                                parameters = camera.getParameters();
                                parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
                                camera.setParameters(parameters);
                            }
                        }
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public synchronized boolean isOpen() {
            return mCamera != null;
        }
    
        @Override
        public void onPreviewFrame(byte[] bytes, Camera camera) {
            if (mListener != null)
                mListener.onPreviewFrame(bytes, camera);
            if (mCamera != null)
                mCamera.addCallbackBuffer(mBuffer);
        }
    
        public interface OnCameraManagerListener {
            void onCamera(Camera camera);
    
            void onReleaseCamera();
    
            void onPreviewFrame(byte[] bytes, Camera camera);
        }
    
    }
    
    

    相关文章

      网友评论

          本文标题:android 相机预览拉伸问题

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