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
动态检测截图: