Android+openCV 動態人臉檢測


動態人臉檢測前提是需要打開攝像頭。

網上看了很多教程,我知道的有兩種方式打開攝像頭:

JavaCameraView mCameraView = new JavaCameraView(this, -1);
setContentView(mCameraView);
mCameraView.setCvCameraViewListener(this);

mCameraView.enableView();

第2種:在布局文件中添加 CameraBridgeViewBase

mCameraView = (CameraBridgeViewBase) findViewById(R.id.java_surface_view);
mCameraView.setCvCameraViewListener(this);
mCameraView.enableView();

以上兩種獲取攝像頭實時視頻流方式需要 implements  CameraBridgeViewBase.CvCameraViewListener

public class FaceTrackingActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener {
  @Overrid
  protected void onCreate(Bundle savedInstanceState) { ... } @Override public void onCameraViewStarted(int width, int height) { } @Override public void onCameraViewStopped() { } @Override public Mat onCameraFrame(Mat inputFrame) { return null; } }
onCameraFrame 函數中將捕獲視頻每一幀。
這樣我在預覽視頻的時候,發現很難控制大小,以及攝像頭的方向。
后來我直接采用以往的camera類去操作視頻流。
以上參考:http://blog.csdn.net/tobacco5648/article/details/51615632

實時處理攝像頭預覽幀視頻參考:http://blog.csdn.net/yanzi1225627/article/details/8605061

定義 SurfaceView

    <SurfaceView
        android:id="@+id/java_surface_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
        mSurfaceView = (SurfaceView) findViewById(R.id.java_surface_view);
        mSurfaceHolder = mSurfaceView.getHolder();

        // mSurfaceView 不需要自己的緩沖區
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        // mSurfaceView添加回調
        mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) { //SurfaceView創建
                try {
                    cameraManager = new CameraManager(FaceTrackingActivity.this, mObjectDetects, cimbt, mSurfaceHolder);
                    cameraManager.openDriver();
                    cameraManager.startPreview();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) { //SurfaceView銷毀
                holder.removeCallback(this); // Camera is being used after Camera.release() was called
                cameraManager.stopPreview();
                cameraManager.closeDriver();

            }
        });

我這里獨立出來了一個 CameraManager 類,本來我想把檢測的代碼寫在 CameraManager 類之外,然而並沒有實現:

 CameraManager 類中  implements Camera.PreviewCallback 可以實現 onPreviewFrame 對實時數據處理:

    @Override
    public void onPreviewFrame(byte[] bytes, Camera camera) {
        Camera.Size previewSize = camera.getParameters().getPreviewSize();

        Bitmap bitmap = ByteToBitmap(bytes, previewSize);
        //Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);//將data byte型數組轉換成bitmap文件

        final Matrix matrix = new Matrix();//轉換成矩陣旋轉90度
        if (cameraPosition == 1) {
            matrix.setRotate(90);
        } else {
            matrix.setRotate(-90);
        }
        bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);//旋轉圖片


        Mat grayscaleImage = new Mat(previewSize.height, previewSize.width, CvType.CV_8UC4);
        int absoluteFaceSize = (int) (previewSize.height * 0.2);

        if (bitmap != null) {
            Mat inputFrame = new Mat();
            Utils.bitmapToMat(bitmap, inputFrame);

            if (!bitmap.isRecycled()) {
                bitmap.recycle();
            }

            // Create a grayscale image
            Imgproc.cvtColor(inputFrame, grayscaleImage, Imgproc.COLOR_RGBA2RGB);

            MatOfRect mRect = new MatOfRect();


            int maxRectArea = 0 * 0;
            Rect maxRect = null;

            int facenum = 0;

            for (ObjectDetector detector : mObjectDetects) {
                // 檢測目標
                Rect[] object = detector.detectObjectImage(inputFrame, mRect);
                Log.e(TAG, object.length + "");

                for (Rect rect : object) {
                    ++facenum;
                    // 找出最大的面積
                    int tmp = rect.width * rect.height;
                    if (tmp >= maxRectArea) {
                        maxRectArea = tmp;
                        maxRect = rect;
                    }
                }
            }

            Bitmap rectBitmap = null;
            if (facenum != 0) {
                // 剪切最大的頭像
                //Log.e("剪切的長寬", String.format("高:%s,寬:%s", maxRect.width, maxRect.height));
                Rect rect = new Rect(maxRect.x, maxRect.y, maxRect.width, maxRect.height);
                Mat rectMat = new Mat(inputFrame, rect);  // 從原始圖像拿
                rectBitmap = Bitmap.createBitmap(rectMat.cols(), rectMat.rows(), Bitmap.Config.ARGB_8888);
                Utils.matToBitmap(rectMat, rectBitmap);

                Bitmap resizeBmp = cimbt.resizeBitmap(rectBitmap, cimbt.getWidth(), cimbt.getHeight());
                cimbt.setBitmap(resizeBmp);
            } else {
                cimbt.clearnImage();
                cimbt.setText("沒有檢測到人臉");
            }
        }

    }

補充:在初始化相機時激活onPreviewFrame

camera.setPreviewCallback(this);
//camera.setOneShotPreviewCallback(this); // 激活 onPreviewFrame 執行一次

 

整個人臉靜態動態檢測源代碼: https://github.com/haoxr/faceDetection

 

動態檢測截圖:

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM