
最近项目需求是统计当前摄像头中的人脸个数,安卓有提供现成的Api,最终实现效果如上图。
分析思路和步奏:
主要使用到的类:SurfaceView、CameraManager、CameraDevice.StateCallback、CameraCaptureSession.StateCallback。
1.通过SurfaceView展示预览区。
2.在SurfaceView创建成功后通过CameraManager获取当前设备可用的摄像头。
3.检测摄像头权限。
4.通过CameraManager打开摄像头。
5.在打开成功的回调中通过CameraDevice创建会话。
6.在会话创建成功的回调方法中创建预览请求。
7.在预览请求的回调方法onCaptureCompleted()方法中获取预览界面中返回的人脸数。
以下是实现步奏:
1.
xml
1 2 3 4 5 6 7 8 9 10 11 | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <SurfaceView android:id="@+id/sv" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> </LinearLayout> |
java
1 2 3 | cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); surfaceHolder = sv.getHolder(); surface = surfaceHolder.getSurface(); |
1 2 | //获取可用的相机列表 String[] cameraIdList = cameraManager.getCameraIdList(); |
1 2 3 4 5 6 7 8 9 10 | if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // Activity#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for Activity#requestPermissions for more details. return; } |
1 2 3 4 5 | //获取开启相机的相关参数 CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraIdList[1]); //可用于判断是否支持人脸检测,以及支持到哪种程度 faceDetectModes = characteristics.get(CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES);//支持的人脸检测模式 cameraManager.openCamera(cameraIdList[1], mStateCallback, null); |
1 2 3 4 5 6 7 8 9 10 11 | camera.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { } }, new Handler()); |
1 2 3 4 5 | CaptureRequest.Builder captureRequest = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); captureRequest.addTarget(surface); captureRequest.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); captureRequest.set(CaptureRequest.STATISTICS_FACE_DETECT_MODE, getFaceDetectMode()); session.setRepeatingRequest(captureRequest.build(),captureCallback,new Handler()); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | /** * 预览回调 */ private CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureStarted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, long timestamp, long frameNumber) { super.onCaptureStarted(session, request, timestamp, frameNumber); } @Override public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) { super.onCaptureProgressed(session, request, partialResult); } @Override public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { super.onCaptureCompleted(session, request, result); Face faces[] = result.get(CaptureResult.STATISTICS_FACES); if (faces.length != face) { Log.e("lee", faces.length + "张脸"); } } @Override public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) { super.onCaptureFailed(session, request, failure); } @Override public void onCaptureSequenceCompleted(@NonNull CameraCaptureSession session, int sequenceId, long frameNumber) { super.onCaptureSequenceCompleted(session, sequenceId, frameNumber); } @Override public void onCaptureSequenceAborted(@NonNull CameraCaptureSession session, int sequenceId) { super.onCaptureSequenceAborted(session, sequenceId); } @Override public void onCaptureBufferLost(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull Surface target, long frameNumber) { super.onCaptureBufferLost(session, request, target, frameNumber); } }; |
以下就是所有代码:
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | package com.zg.lcddemo; import android.Manifest; import android.content.ContentValues; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.ImageFormat; import android.graphics.Rect; import android.graphics.SurfaceTexture; import android.hardware.Camera; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.CaptureFailure; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.TotalCaptureResult; import android.hardware.camera2.params.Face; import android.hardware.camera2.params.SessionConfiguration; import android.hardware.camera2.params.StreamConfigurationMap; import android.media.FaceDetector; import android.media.ImageReader; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.provider.MediaStore; import android.util.Log; import android.util.Size; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.concurrent.Semaphore; public class MainActivity extends AppCompatActivity { private SurfaceView sv; private SurfaceHolder surfaceHolder; private CameraManager cameraManager; private Surface surface; int[] faceDetectModes; int face; List<Bitmap> bitmaps = new ArrayList<>(); /** * 获取支持的最高人脸检测级别 * * @return */ private int getFaceDetectMode() { if (faceDetectModes == null) { return CaptureRequest.STATISTICS_FACE_DETECT_MODE_FULL; } else { return faceDetectModes[faceDetectModes.length - 1]; } } @RequiresApi(api = Build.VERSION_CODES.M) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sv = findViewById(R.id.sv); cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); surfaceHolder = sv.getHolder(); surface = surfaceHolder.getSurface(); surfaceHolder.addCallback(new SurfaceHolder.Callback() { @RequiresApi(api = Build.VERSION_CODES.M) @Override public void surfaceCreated(SurfaceHolder holder) { try { //获取可用的相机列表 String[] cameraIdList = cameraManager.getCameraIdList(); if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // Activity#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for Activity#requestPermissions for more details. return; } //获取开启相机的相关参数 CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraIdList[1]); //可用于判断是否支持人脸检测,以及支持到哪种程度 faceDetectModes = characteristics.get(CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES);//支持的人脸检测模式 cameraManager.openCamera(cameraIdList[1], mStateCallback, null); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { } }); } /** * 相机状态回调 */ private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(@NonNull final CameraDevice camera) { //打开成功,可以获取CameraDevice对象 try { camera.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { try { CaptureRequest.Builder captureRequest = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); captureRequest.addTarget(surface); captureRequest.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); captureRequest.set(CaptureRequest.STATISTICS_FACE_DETECT_MODE, getFaceDetectMode()); session.setRepeatingRequest(captureRequest.build(),captureCallback,new Handler()); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { } }, new Handler()); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onDisconnected(@NonNull CameraDevice camera) { //断开连接 Toast.makeText(MainActivity.this, "onDisconnected", Toast.LENGTH_SHORT).show(); } @Override public void onError(@NonNull CameraDevice camera, final int error) { //发生异常 Toast.makeText(MainActivity.this, "onError", Toast.LENGTH_SHORT).show(); } }; /** * 预览回调 */ private CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureStarted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, long timestamp, long frameNumber) { super.onCaptureStarted(session, request, timestamp, frameNumber); } @Override public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) { super.onCaptureProgressed(session, request, partialResult); } @Override public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { super.onCaptureCompleted(session, request, result); Face faces[] = result.get(CaptureResult.STATISTICS_FACES); if (faces.length != face) { Log.e("lee", faces.length + "张脸"); face = faces.length; } } @Override public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) { super.onCaptureFailed(session, request, failure); } @Override public void onCaptureSequenceCompleted(@NonNull CameraCaptureSession session, int sequenceId, long frameNumber) { super.onCaptureSequenceCompleted(session, sequenceId, frameNumber); } @Override public void onCaptureSequenceAborted(@NonNull CameraCaptureSession session, int sequenceId) { super.onCaptureSequenceAborted(session, sequenceId); } @Override public void onCaptureBufferLost(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull Surface target, long frameNumber) { super.onCaptureBufferLost(session, request, target, frameNumber); } }; } |
xml
1 2 3 4 5 6 7 8 9 10 11 12 | <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <SurfaceView android:id="@+id/sv" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> </LinearLayout> |
以上就能实现统计当前摄像头下有多少个人脸。