OpenCV on Android 開發(fā) (4)豎屏預(yù)覽圖像問題解決方法-續(xù)

前一篇文章通過使用opencv官方例程的思路隶债,初步解決了豎屏預(yù)覽自動(dòng)旋轉(zhuǎn)的問題,但是因?yàn)橐獙pp的方向固定為landscape仔夺,即橫屏模式,這在實(shí)際的相機(jī)應(yīng)用里會(huì)很奇怪攒砖,所以作為強(qiáng)迫癥患者缸兔,我想在豎屏模式下實(shí)現(xiàn)正常的預(yù)覽檢測,花了我2天的時(shí)間吹艇,在外網(wǎng)扒代碼惰蜜,終于找到了靠譜解決的方法,但是并不完美受神,還是存在一些小bug

解決方法的連接https://github.com/opencv/opencv/issues/4704
https://stackoverflow.com/questions/16669779/opencv-camera-orientation-issue
老外也遇到了同樣的問題http://answers.opencv.org/question/20325/how-can-i-change-orientation-without-ruin-camera-settings/但是還沒有人給出正確的解決辦法

經(jīng)過我的測試有兩個(gè)方法的表現(xiàn)還不錯(cuò)

方法一

需要改opencv的庫文件

首先

CameraBridgeViewBase.java 中的deliverAndDrawFrame(CVCameraViewFrame frame)方法全部替換成

protected void deliverAndDrawFrame(CvCameraViewFrame frame) {
        Mat modified;

        if (mListener != null) {
            modified = mListener.onCameraFrame(frame);
        } else {
            modified = frame.rgba();
        }

        boolean bmpValid = true;
        if (modified != null) {
            try {
                Utils.matToBitmap(modified, mCacheBitmap);
            } catch(Exception e) {
                Log.e(TAG, "Mat type: " + modified);
                Log.e(TAG, "Bitmap type: " + mCacheBitmap.getWidth() + "*" + mCacheBitmap.getHeight());
                Log.e(TAG, "Utils.matToBitmap() throws an exception: " + e.getMessage());
                bmpValid = false;
            }
        }

        mFpsMeter.measure();
    }
然后是

JavaCameraView.java 中的initializeCamera(int width, int height)方法抛猖,并且需要增加兩個(gè)函數(shù)private void setDisplayOrientation(Camera camera, int angle)和private String getOrientation(),通過mCamera.setPreviewDisplay(getHolder());來實(shí)現(xiàn)豎屏全屏顯示

protected boolean initializeCamera(int width, int height) {
        Log.d(TAG, "Initialize java camera");
        boolean result = true;
        synchronized (this) {
            mCamera = null;

            if (mCameraIndex == CAMERA_ID_ANY) {
                Log.d(TAG, "Trying to open camera with old open()");
                try {
                    mCamera = Camera.open();
                }
                catch (Exception e){
                    Log.e(TAG, "Camera is not available (in use or does not exist): " + e.getLocalizedMessage());
                }

                if(mCamera == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
                    boolean connected = false;
                    for (int camIdx = 0; camIdx < Camera.getNumberOfCameras(); ++camIdx) {
                        Log.d(TAG, "Trying to open camera with new open(" + Integer.valueOf(camIdx) + ")");
                        try {
                            mCamera = Camera.open(camIdx);
                            connected = true;
                        } catch (RuntimeException e) {
                            Log.e(TAG, "Camera #" + camIdx + "failed to open: " + e.getLocalizedMessage());
                        }
                        if (connected) break;
                    }
                }
            } else {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
                    int localCameraIndex = mCameraIndex;
                    if (mCameraIndex == CAMERA_ID_BACK) {
                        Log.i(TAG, "Trying to open back camera");
                        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
                        for (int camIdx = 0; camIdx < Camera.getNumberOfCameras(); ++camIdx) {
                            Camera.getCameraInfo( camIdx, cameraInfo );
                            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                                localCameraIndex = camIdx;
                                break;
                            }
                        }
                    } else if (mCameraIndex == CAMERA_ID_FRONT) {
                        Log.i(TAG, "Trying to open front camera");
                        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
                        for (int camIdx = 0; camIdx < Camera.getNumberOfCameras(); ++camIdx) {
                            Camera.getCameraInfo( camIdx, cameraInfo );
                            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                                localCameraIndex = camIdx;
                                break;
                            }
                        }
                    }
                    if (localCameraIndex == CAMERA_ID_BACK) {
                        Log.e(TAG, "Back camera not found!");
                    } else if (localCameraIndex == CAMERA_ID_FRONT) {
                        Log.e(TAG, "Front camera not found!");
                    } else {
                        Log.d(TAG, "Trying to open camera with new open(" + Integer.valueOf(localCameraIndex) + ")");
                        try {
                            mCamera = Camera.open(localCameraIndex);
                        } catch (RuntimeException e) {
                            Log.e(TAG, "Camera #" + localCameraIndex + "failed to open: " + e.getLocalizedMessage());
                        }
                    }
                }
            }

            if (mCamera == null)
                return false;

            /* Now set camera parameters */
            try {
                Camera.Parameters params = mCamera.getParameters();
                Log.d(TAG, "getSupportedPreviewSizes()");
                List<android.hardware.Camera.Size> sizes = params.getSupportedPreviewSizes();

                if (sizes != null) {
                    /* Image format NV21 causes issues in the Android emulators */
                    if (Build.FINGERPRINT.startsWith("generic")
                            || Build.FINGERPRINT.startsWith("unknown")
                            || Build.MODEL.contains("google_sdk")
                            || Build.MODEL.contains("Emulator")
                            || Build.MODEL.contains("Android SDK built for x86")
                            || Build.MANUFACTURER.contains("Genymotion")
                            || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
                            || "google_sdk".equals(Build.PRODUCT))
                        params.setPreviewFormat(ImageFormat.YV12);  // "generic" or "android" = android emulator
                    else
                        params.setPreviewFormat(ImageFormat.NV21);

                    mPreviewFormat = params.getPreviewFormat();
                    //從這里開始不同
                    if (!Build.MODEL.equals("GT-I9100")) params.setRecordingHint(true);
                    params.setPreviewSize(1920, 1080);
                    mCamera.setParameters(params);

                    mFrameWidth = 1920;
                    mFrameHeight = 1080;

                    if (mFpsMeter != null) {
                        mFpsMeter.setResolution(mFrameWidth, mFrameHeight);
                    }

                    int size = mFrameWidth * mFrameHeight;
                    size  = size * ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8;
                    mBuffer = new byte[size];

                    mCamera.addCallbackBuffer(mBuffer);
                    mCamera.setPreviewCallbackWithBuffer(this);

                    mFrameChain = new Mat[2];
                    mFrameChain[0] = new Mat(mFrameHeight + (mFrameHeight/2), mFrameWidth, CvType.CV_8UC1);
                    mFrameChain[1] = new Mat(mFrameHeight + (mFrameHeight/2), mFrameWidth, CvType.CV_8UC1);

                    AllocateCache();

                    mCameraFrame = new JavaCameraFrame[2];
                    mCameraFrame[0] = new JavaCameraFrame(mFrameChain[0], mFrameWidth, mFrameHeight);
                    mCameraFrame[1] = new JavaCameraFrame(mFrameChain[1], mFrameWidth, mFrameHeight);
                    
                    //different

                    mSurfaceTexture = new SurfaceTexture(MAGIC_TEXTURE_ID);
                    mCamera.setPreviewTexture(mSurfaceTexture);
                    
                    //主要修改

                    if (getOrientation().equals("portrait")) {
                        setDisplayOrientation(mCamera, 90);
                    } else if (getOrientation().equals("reverse landscape")){
                        setDisplayOrientation(mCamera, 180);
                    } else if (getOrientation().equals("reverse portrait")) {
                        setDisplayOrientation(mCamera, 270);
                    }
                    mCamera.setPreviewDisplay(getHolder());
                    
                    //end

                    mCamera.startPreview();
                }
                else
                    result = false;
            } catch (Exception e) {
                result = false;
                e.printStackTrace();
            }
        }

        return result;
    }
    //add two function
     
    private void setDisplayOrientation(Camera camera, int angle){
        Method downPolymorphic;
        try {
            downPolymorphic = camera.getClass().getMethod("setDisplayOrientation", int.class);
            if (downPolymorphic != null) {
                downPolymorphic.invoke(camera, angle);
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String getOrientation(){
        int orientation = Surface.ROTATION_0;

        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        if (wm != null) {
            Display display = wm.getDefaultDisplay();
            orientation = display.getOrientation();
        }

        if (orientation == Surface.ROTATION_0) {
        return "portrait";
        }else if (orientation == Surface.ROTATION_90) {
        return "landscape";
        } else if (orientation == Surface.ROTATION_180) {
        return "reverse portrait";
        } else return "reverse landscape";
    }
    //end

該方法顯示的十分完美,但是存在一個(gè)無法接受的缺點(diǎn)
我們的onCameraFrame()方法失效了财著,因?yàn)槲覀冋{(diào)用了mCamera.setPreviewDisplay(getHolder());這個(gè)方法導(dǎo)致opencv對(duì)相機(jī)每一幀的處理無法顯示出來联四。。撑教。但是具體怎么解決朝墩??伟姐?我也不知道收苏,期望能有大神把解決方法分享出來23333

方法二

該方法只需要修改opencv的一個(gè)庫文件CameraBridgeViewBase.java,相機(jī)預(yù)覽的顯示效果還不錯(cuò)愤兵,但是還是還是有問題.鹿霸。。秆乳。2333懦鼠。。屹堰。經(jīng)我測試發(fā)現(xiàn)橫屏?xí)r存在顯示圖像放大的問題葛闷,但是豎屏倒是蠻完美的,就是fps會(huì)比較顯著的降低双藕,但還在能接受的范圍內(nèi)淑趾。

修改如下
protected void deliverAndDrawFrame(CvCameraViewFrame frame) {
        Mat modified;

        if (mListener != null) {
            modified = mListener.onCameraFrame(frame);
        } else {
            modified = frame.rgba();
        }

        boolean bmpValid = true;
        if (modified != null) {
            try {
                Utils.matToBitmap(modified, mCacheBitmap);
            } catch(Exception e) {
                Log.e(TAG, "Mat type: " + modified);
                Log.e(TAG, "Bitmap type: " + mCacheBitmap.getWidth() + "*" + mCacheBitmap.getHeight());
                Log.e(TAG, "Utils.matToBitmap() throws an exception: " + e.getMessage());
                bmpValid = false;
            }
        }

        if (bmpValid && mCacheBitmap != null) {
            Canvas canvas = getHolder().lockCanvas();
            if (canvas != null) {
                canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
/*
                //原來的方法
                if (BuildConfig.DEBUG)
                    Log.d(TAG, "mStretch value: " + mScale);

                if (mScale != 0) {
                    canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
                         new Rect((int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2),
                         (int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2),
                         (int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2 + mScale*mCacheBitmap.getWidth()),
                         (int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2 + mScale*mCacheBitmap.getHeight())), null);
                } else {
                     canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
                         new Rect((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,
                         (canvas.getHeight() - mCacheBitmap.getHeight()) / 2,
                         (canvas.getWidth() - mCacheBitmap.getWidth()) / 2 + mCacheBitmap.getWidth(),
                         (canvas.getHeight() - mCacheBitmap.getHeight()) / 2 + mCacheBitmap.getHeight()), null);
                }
*/


    
//method4
                Matrix matrix = new Matrix(); // I rotate it with minimal process
                //matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,(canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
                //matrix.postRotate(90f,(canvas.getWidth()) / 2,(canvas.getHeight()) / 2);
                //float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
                //matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
                //canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
//end

                if (getDisplay().getRotation() == Surface.ROTATION_0) {
                    matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,(canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
                    matrix.postRotate(90f,(canvas.getWidth()) / 2,(canvas.getHeight()) / 2);
                    float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
                    matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
                    canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
                } else if (getDisplay().getRotation() == Surface.ROTATION_90) {
                    float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
                    matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
                    canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
                } else if (getDisplay().getRotation() == Surface.ROTATION_180) {
                    matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,(canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
                    matrix.postRotate(270f,(canvas.getWidth()) / 2,(canvas.getHeight()) / 2);
                    float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
                    matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
                    canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
                } else if (getDisplay().getRotation() == Surface.ROTATION_270) {
                    matrix.postRotate(180f,(canvas.getWidth()) / 2,(canvas.getHeight()) / 2);
                    float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
                    matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
                    canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
                }


                if (mFpsMeter != null) {
                    mFpsMeter.measure();
                    mFpsMeter.draw(canvas, 20, 30);
                }
                getHolder().unlockCanvasAndPost(canvas);
            }
        }
    }

其實(shí)主要的修改只是
在protected void deliverAndDrawFrame(CvCameraViewFrame frame) 函數(shù)里

 if (bmpValid && mCacheBitmap != null) {
            Canvas canvas = getHolder().lockCanvas();
            if (canvas != null) {
                canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);

函數(shù)段后面把原方法替換成

Matrix matrix = new Matrix(); // I rotate it with minimal process
matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,(canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
matrix.postRotate(90f,(canvas.getWidth()) / 2,(canvas.getHeight()) / 2);
float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
canvas.drawBitmap(mCacheBitmap, matrix, new Paint());

即可
作為個(gè)強(qiáng)迫癥患者,我增加了個(gè)判斷語句來實(shí)現(xiàn)橫豎屏都能正常的顯示忧陪。但是就是這個(gè)原因發(fā)現(xiàn)了這個(gè)方法的bug扣泊,橫屏?xí)r顯示的圖像是放大的。嘶摊。延蟹。2333

看來我還需要再研究下,看看能不能修復(fù)橫屏?xí)糯蟮腷ug

但是要是在AndroidManifest.xml里鎖定豎屏的話

<activity android:name=".MainActivity"
            android:screenOrientation="portrait">

就不出現(xiàn)橫屏?xí)r的bug了叶堆,但是該方法fps降低的很明顯阱飘,不過顯示效果還是在可以接受的范圍內(nèi)的。虱颗。沥匈。
方法二效果圖



不過仍然還是只有在把屏幕橫著時(shí)人臉檢測才能得到較好的結(jié)果,豎屏?xí)r雖然也能檢測到忘渔,但是很不穩(wěn)定23333

總的來說高帖,我還是決定采用方法二的方法,來實(shí)現(xiàn)我下一步的目標(biāo)畦粮。ヾ(o?ω?)?
留給我的時(shí)間不多了╮(╯﹏╰)╭

更新更新

作為強(qiáng)迫癥患者散址,睡覺時(shí)想到了一個(gè)解決豎屏?xí)r不能人臉檢測的方法乖阵,因?yàn)閛pencv要在橫屏?xí)r才能得到較好的結(jié)果,那么我可以先把豎屏?xí)r得到的圖像順時(shí)針旋轉(zhuǎn)90度预麸,這樣就和橫屏?xí)r一樣了瞪浸,然后我在把得到識(shí)別綠框的圖像逆時(shí)針旋轉(zhuǎn)90度,再輸出這樣就能做到豎屏?xí)r實(shí)現(xiàn)人臉檢測了吏祸。
所以我將MainActicity.java中的onCameraViewStarted和onCameraFrame()函數(shù)修改如下

@Override
    public void onCameraViewStarted(int width, int height){
        rgbaImage = new Mat(width, height, CvType.CV_8UC4);
        grayscaleImage = new Mat(height, width, CvType.CV_8UC4);
        Matlin = new Mat(width, height, CvType.CV_8UC4);
        gMatlin = new Mat(width, height, CvType.CV_8UC4);

        absoluteFaceSize = (int)(height * 0.2);

    }

    @Override
    public void onCameraViewStopped(){

    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
    @Override
    public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame InputFrame) {       
        grayscaleImage = InputFrame.gray();
        rgbaImage = InputFrame.rgba();
        int rotation = openCvCameraView.getDisplay().getRotation();

        //使前置的圖像也是正的
        if (camera_scene == CAMERA_FRONT) {
            Core.flip(rgbaImage, rgbaImage, 1);
            Core.flip(grayscaleImage, grayscaleImage, 1);
        }

        //MatOfRect faces = new MatOfRect();

        if (rotation == Surface.ROTATION_0) {
            MatOfRect faces = new MatOfRect();
            Core.rotate(grayscaleImage, gMatlin, Core.ROTATE_90_CLOCKWISE);
            Core.rotate(rgbaImage, Matlin, Core.ROTATE_90_CLOCKWISE);
            if (cascadeClassifier != null) {
                cascadeClassifier.detectMultiScale(gMatlin, faces, 1.1, 2, 2, new Size(absoluteFaceSize, absoluteFaceSize), new Size());
            }

            Rect[] faceArray = faces.toArray();
            for (int i = 0; i < faceArray.length; i++)

                Imgproc.rectangle(Matlin, faceArray[i].tl(), faceArray[i].br(), new Scalar(0, 255, 0, 255), 2);
            Core.rotate(Matlin, rgbaImage, Core.ROTATE_90_COUNTERCLOCKWISE);

        } else {
            MatOfRect faces = new MatOfRect();
            if (cascadeClassifier != null) {
                cascadeClassifier.detectMultiScale(grayscaleImage, faces, 1.1, 2, 2, new Size(absoluteFaceSize, absoluteFaceSize), new Size());
            }

            Rect[] faceArray = faces.toArray();
            for (int i = 0; i < faceArray.length; i++)

                Imgproc.rectangle(rgbaImage, faceArray[i].tl(), faceArray[i].br(), new Scalar(0, 255, 0, 255), 2);
        }

        return rgbaImage;
    }

最后对蒲,經(jīng)過我的修改顯示效果如下:
豎屏后置



豎屏前置


識(shí)別效果還不錯(cuò),就是側(cè)臉的話犁罩,識(shí)別不出來齐蔽。還有一個(gè)問題就是現(xiàn)在橫屏?xí)r無法檢測人臉了两疚,我想可能是因?yàn)槲益i定為了豎屏模式床估,導(dǎo)致int rotation = openCvCameraView.getDisplay().getRotation()放回的一致都是Surface.ROTATION_0使得我的其他方法不能實(shí)現(xiàn)。
為此诱渤,我不鎖定豎屏丐巫,對(duì)AndroidManifest.xml修改

<activity android:name=".MainActivity"
            android:screenOrientation="fullSensor">

修改MainActivity.java,加入完整的if判斷語句勺美,我試過使用switch來判斷但是fps會(huì)降的很低递胧,有很明顯的卡頓感

MatOfRect faces = new MatOfRect();
if (rotation == Surface.ROTATION_0) {
            Core.rotate(grayscaleImage, gMatlin, Core.ROTATE_90_CLOCKWISE);
            Core.rotate(rgbaImage, Matlin, Core.ROTATE_90_CLOCKWISE);
            if (cascadeClassifier != null) {
                cascadeClassifier.detectMultiScale(gMatlin, faces, 1.1, 2, 2, new Size(absoluteFaceSize, absoluteFaceSize), new Size());
            }

            Rect[] faceArray = faces.toArray();
            for (int i = 0; i < faceArray.length; i++)

                Imgproc.rectangle(Matlin, faceArray[i].tl(), faceArray[i].br(), new Scalar(0, 255, 0, 255), 2);
            Core.rotate(Matlin, rgbaImage, Core.ROTATE_90_COUNTERCLOCKWISE);

        } else if (rotation == Surface.ROTATION_90) {
            if (cascadeClassifier != null) {
                cascadeClassifier.detectMultiScale(grayscaleImage, faces, 1.1, 2, 2, new Size(absoluteFaceSize, absoluteFaceSize), new Size());
            }

            Rect[] faceArray = faces.toArray();
            for (int i = 0; i < faceArray.length; i++)

                Imgproc.rectangle(rgbaImage, faceArray[i].tl(), faceArray[i].br(), new Scalar(0, 255, 0, 255), 2);
        } else if (rotation == Surface.ROTATION_180) {
            Core.rotate(grayscaleImage, gMatlin, Core.ROTATE_90_COUNTERCLOCKWISE);
            Core.rotate(rgbaImage, Matlin, Core.ROTATE_90_COUNTERCLOCKWISE);
            if (cascadeClassifier != null) {
                cascadeClassifier.detectMultiScale(gMatlin, faces, 1.1, 2, 2, new Size(absoluteFaceSize, absoluteFaceSize), new Size());
            }

            Rect[] faceArray = faces.toArray();
            for (int i = 0; i < faceArray.length; i++)

                Imgproc.rectangle(Matlin, faceArray[i].tl(), faceArray[i].br(), new Scalar(0, 255, 0, 255), 2);
            Core.rotate(Matlin, rgbaImage, Core.ROTATE_90_CLOCKWISE);
        } else if (rotation == Surface.ROTATION_270) {
            Core.rotate(grayscaleImage, gMatlin, Core.ROTATE_180);
            Core.rotate(rgbaImage, Matlin, Core.ROTATE_180);
            if (cascadeClassifier != null) {
                cascadeClassifier.detectMultiScale(gMatlin, faces, 1.1, 2, 2, new Size(absoluteFaceSize, absoluteFaceSize), new Size());
            }

            Rect[] faceArray = faces.toArray();
            for (int i = 0; i < faceArray.length; i++)

                Imgproc.rectangle(Matlin, faceArray[i].tl(), faceArray[i].br(), new Scalar(0, 255, 0, 255), 2);
            Core.rotate(Matlin, rgbaImage, Core.ROTATE_180);
        }

在CameraBridgeViewBase.java里的deliverAndDrawFrame()

if (bmpValid && mCacheBitmap != null) {
            Canvas canvas = getHolder().lockCanvas();
            if (canvas != null) {
                canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);

后面的片段修改為

Matrix matrix = new Matrix(); // I rotate it with minimal process
                float portraitscale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
                float landscapscale = 1f;

                if (getDisplay().getRotation() == Surface.ROTATION_0) {
                    matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,(canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
                    matrix.postRotate(90f,(canvas.getWidth()) / 2,(canvas.getHeight()) / 2);
                    //float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
                    //matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
                    matrix.postScale(portraitscale, portraitscale, canvas.getWidth()/2 , canvas.getHeight()/2 );
                    canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
                } else if (getDisplay().getRotation() == Surface.ROTATION_90) {
                    matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,(canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
                    //float scale = 1f;
                    //matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
                    matrix.postScale(landscapscale, landscapscale, canvas.getWidth()/2 , canvas.getHeight()/2 );
                    canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
                } else if (getDisplay().getRotation() == Surface.ROTATION_180) {
                    matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,(canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
                    matrix.postRotate(270f,(canvas.getWidth()) / 2,(canvas.getHeight()) / 2);
                    //float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
                    //matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
                    matrix.postScale(portraitscale, portraitscale, canvas.getWidth()/2 , canvas.getHeight()/2 );
                    canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
                } else if (getDisplay().getRotation() == Surface.ROTATION_270) {
                    matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,(canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
                    matrix.postRotate(180f,(canvas.getWidth()) / 2,(canvas.getHeight()) / 2);
                    //float scale = 1f;
                    //matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
                    matrix.postScale(landscapscale, landscapscale, canvas.getWidth()/2 , canvas.getHeight()/2 );
                    canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
                }

將橫屏?xí)r的float scale 設(shè)置為1就能解決前面出現(xiàn)的橫屏放大的比例不對(duì)的問題,該段我也嘗試過換成switch語句但是同樣會(huì)有很卡頓的感覺赡茸,原因不明缎脾,可能這個(gè)是編譯switch時(shí)自身的問題?占卧?遗菠?
做完上述修改后,橫豎屏就都能進(jìn)行人臉檢測了华蜒,但是當(dāng)旋轉(zhuǎn)270度時(shí)辙纬,即倒著橫屏?xí)r會(huì)有很明顯的卡頓感。叭喜。贺拣。
不管了,反正一般鎖定豎屏模式使用就好了捂蕴。譬涡。。
剩下的工作就是提高檢測的準(zhǔn)確率啥辨,實(shí)現(xiàn)側(cè)臉檢測和人眼檢測了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末昂儒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子委可,更是在濱河造成了極大的恐慌渊跋,老刑警劉巖腊嗡,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異拾酝,居然都是意外死亡燕少,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門蒿囤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來客们,“玉大人,你說我怎么就攤上這事材诽〉状欤” “怎么了?”我有些...
    開封第一講書人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵脸侥,是天一觀的道長建邓。 經(jīng)常有香客問我,道長睁枕,這世上最難降的妖魔是什么官边? 我笑而不...
    開封第一講書人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮外遇,結(jié)果婚禮上注簿,老公的妹妹穿的比我還像新娘。我一直安慰自己跳仿,他們只是感情好诡渴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著菲语,像睡著了一般妄辩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上谨究,一...
    開封第一講書人閱讀 51,208評(píng)論 1 299
  • 那天恩袱,我揣著相機(jī)與錄音,去河邊找鬼胶哲。 笑死畔塔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鸯屿。 我是一名探鬼主播澈吨,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼寄摆!你這毒婦竟也來了谅辣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤婶恼,失蹤者是張志新(化名)和其女友劉穎桑阶,沒想到半個(gè)月后柏副,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蚣录,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年割择,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片萎河。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡荔泳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出虐杯,到底是詐尸還是另有隱情玛歌,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布擎椰,位于F島的核電站支子,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏确憨。R本人自食惡果不足惜译荞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一瓤的、第九天 我趴在偏房一處隱蔽的房頂上張望休弃。 院中可真熱鬧,春花似錦圈膏、人聲如沸塔猾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丈甸。三九已至,卻和暖如春尿褪,著一層夾襖步出監(jiān)牢的瞬間睦擂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來泰國打工杖玲, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留顿仇,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓摆马,卻偏偏與公主長得像臼闻,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子囤采,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容