動態人臉檢測前提是需要打開攝像頭。
網上看了很多教程,我知道的有兩種方式打開攝像頭:
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
動態檢測截圖: