OpenCV相机帧率低以及花屏问题

使用OpenCV原生的JavaCamera2View打开相机,发现相机帧率非常的低,只有3-4帧,而且色彩也不对。

1.帧率低的解决方案:
这个问题的原因在于OpenCV在设置预览长宽的时候,首先是获取相机支持的最大尺寸,以这个尺寸作为基准和connect_camera的API传进来的View的长宽做条件匹配,如果View的长宽不满足OpenCV的要求,那么会直接使用相机的最大输出尺寸进行预览,而这个就是预览帧率低的根本原因。

一般市面上的所有相机都会支持到640*480的尺寸,因此我们就用这个尺寸,改下源码即可

org\opencv\android\CameraBridgeViewBase.java

    private void onEnterStartedState() {
        Log.d(TAG, "call onEnterStartedState");
        /* Connect camera */
        if (!connectCamera(640, 480)) {

org\opencv\android\JavaCamera2View.java

    boolean calcPreviewSize(final int width, final int height) {
        Log.i(LOGTAG, "calcPreviewSize: " + width + "x" + height);
        if (mCameraID == null) {
            Log.e(LOGTAG, "Camera isn't initialized!");
            return false;
        }
        CameraManager manager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
        try {
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(mCameraID);
            StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            int bestWidth = 0, bestHeight = 0;
            float aspect = (float) width / height;
            android.util.Size[] sizes = map.getOutputSizes(ImageReader.class);
            bestWidth = width;
            bestHeight = height;
//            for (android.util.Size sz : sizes) {
//                int w = sz.getWidth(), h = sz.getHeight();
//                Log.d(LOGTAG, "trying size: " + w + "x" + h);
//                if (width >= w && height >= h && bestWidth <= w && bestHeight <= h
//                        && Math.abs(aspect - (float) w / h) < 0.2) {
//                    bestWidth = w;
//                    bestHeight = h;
//                }
//            }
            Log.i(LOGTAG, "best size: " + bestWidth + "x" + bestHeight);
            assert(!(bestWidth == 0 || bestHeight == 0));
            if (mPreviewSize.getWidth() == bestWidth && mPreviewSize.getHeight() == bestHeight)
                return false;
            else {
                mPreviewSize = new android.util.Size(bestWidth, bestHeight);
                return true;
            }
        } catch (CameraAccessException e) {
            Log.e(LOGTAG, "calcPreviewSize - Camera Access Exception", e);
        } catch (IllegalArgumentException e) {
            Log.e(LOGTAG, "calcPreviewSize - Illegal Argument Exception", e);
        } catch (SecurityException e) {
            Log.e(LOGTAG, "calcPreviewSize - Security Exception", e);
        }
        return false;
    }

重新build下apk,你会发现帧率能够达到25fps左右了。其实还有改善空间的,OpenCV的相机是使用的SurfaceView进行的渲染,我们知道SurfaceView是通过CPU去渲染的,同时OpenCV对CPU的算力占用也是比较大的,因此可以尝试将预览图像的渲染交给GPU去完成,这样能够提升预览的帧率。

BTW,之前写过一个GPU渲染的demo,帧率可以达到基本30fps,Anyway,对于Camera的图像处理的操作,我始终认为最好的方案还是在HAL去完成,因为预览数据从HAL通过CallBack的机制传递到APP非常耗时,以前也看过Camera在Android的数据流,这个过程中预览数据至少要发生2次拷贝。

2.图像色彩不对的解决方案
这问题也是比较坑爹的,就直接上代码吧。

org\opencv\android\JavaCamera2View.java

        @Override
        public Mat rgba() {
            if (mPreviewFormat == ImageFormat.NV21)
                Imgproc.cvtColor(mYuvFrameData, mRgba, Imgproc.COLOR_YUV2RGBA_NV21, 4);
            else if (mPreviewFormat == ImageFormat.YV12)
                Imgproc.cvtColor(mYuvFrameData, mRgba, Imgproc.COLOR_YUV2RGB_I420, 4); // COLOR_YUV2RGBA_YV12 produces inverted colors
            else if (mPreviewFormat == ImageFormat.YUV_420_888) {
                assert (mUVFrameData != null);
                //Imgproc.cvtColorTwoPlane(mYuvFrameData, mUVFrameData, mRgba, Imgproc.COLOR_YUV2RGBA_NV21);
                Imgproc.cvtColorTwoPlane(mYuvFrameData, mUVFrameData, mRgba, Imgproc.COLOR_YUV2BGRA_NV21);
            } else
                throw new IllegalArgumentException("Preview Format can be NV21 or YV12");

            return mRgba;
        }

也就是Mat和Bitmap对于图像处理的差异性导致的

你可能感兴趣的:(OpenCV)