Android(安卓)实现人脸检测
16lz
2021-01-26
添加权限
逻辑实现
import android.Manifest;import android.annotation.SuppressLint;import android.app.Activity;import android.content.Context;import android.content.pm.PackageManager;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.ImageFormat;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.PorterDuff;import android.graphics.Rect;import android.graphics.SurfaceTexture;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.CaptureRequest;import android.hardware.camera2.CaptureResult;import android.hardware.camera2.TotalCaptureResult;import android.hardware.camera2.params.Face;import android.hardware.camera2.params.StreamConfigurationMap;import android.media.Image;import android.media.ImageReader;import android.os.Bundle;import android.os.Handler;import android.os.HandlerThread;import android.support.annotation.NonNull;import android.support.v4.app.ActivityCompat;import android.util.Log;import android.util.Size;import android.util.SparseIntArray;import android.view.Surface;import android.view.TextureView;import android.view.View;import android.widget.Button;import android.widget.ImageView;import android.widget.TextView;import android.widget.Toast;import com.yl.fecedetectdemo.R;import java.nio.ByteBuffer;import java.util.Arrays;public class MainActivity extends Activity { private static void Log(String message) { Log.i(MainActivity.class.getName(), message); } //为了使照片竖直显示 private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 90); ORIENTATIONS.append(Surface.ROTATION_90, 0); ORIENTATIONS.append(Surface.ROTATION_180, 270); ORIENTATIONS.append(Surface.ROTATION_270, 180); } private TextureView cView;//用于相机预览 private TextureView rView;//用于标注人脸 private ImageView imageView;//拍照照片显示 private TextView textView; private Button btnFront; private Button btnBack; private Button btnClose; private Button btnCapture; private Surface previewSurface;//预览Surface private ImageReader cImageReader; private Surface captureSurface;//拍照Surface HandlerThread cHandlerThread;//相机处理线程 Handler cHandler;//相机处理 CameraDevice cDevice; CameraCaptureSession cSession; CameraDevice.StateCallback cDeviceOpenCallback = null;//相机开启回调 CaptureRequest.Builder previewRequestBuilder;//预览请求构建 CaptureRequest previewRequest;//预览请求 CameraCaptureSession.CaptureCallback previewCallback;//预览回调 CaptureRequest.Builder captureRequestBuilder; CaptureRequest captureRequest; CameraCaptureSession.CaptureCallback captureCallback; int[] faceDetectModes; // Rect rRect;//相机成像矩形 Size cPixelSize;//相机成像尺寸 int cOrientation; Size captureSize; boolean isFront; Paint pb; Bitmap bitmap; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_face); //GlobalExceptionHandler catchHandler = GlobalExceptionHandler.getInstance(); //catchHandler.init(this.getApplication()); initVIew(); } /** * 初始化界面 */ private void initVIew() { cView = (TextureView) findViewById(R.id.cView); rView = (TextureView) findViewById(R.id.rView); imageView = (ImageView) findViewById(R.id.imageView); textView = (TextView) findViewById(R.id.textView); btnFront = (Button) findViewById(R.id.btnFront); btnBack = (Button) findViewById(R.id.btnBack); btnClose = (Button) findViewById(R.id.btnClose); btnCapture = (Button) findViewById(R.id.btnCapture); //隐藏背景色,以免标注人脸时挡住预览画面 rView.setAlpha(0.9f); btnFront.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { openCamera(true); } }); btnBack.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { openCamera(false); } }); btnClose.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { closeCamera(); } }); btnCapture.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { executeCapture(); } }); //TODO 摄像头静音尝试// try {// Class<?> cClass = Class.forName("android.hardware.Camera");// Method mOpen = cClass.getDeclaredMethod("open");// Object nCamera = mOpen.invoke(null);// Method mDisableShutterSound = cClass.getDeclaredMethod("disableShutterSound");// mDisableShutterSound.invoke(nCamera);// Method mRelease = cClass.getDeclaredMethod("release");// mRelease.invoke(nCamera);// } catch (ClassNotFoundException e) {// Log(Log.getStackTraceString(e));// } catch (NoSuchMethodException e) {// Log(Log.getStackTraceString(e));// } catch (IllegalAccessException e) {// Log(Log.getStackTraceString(e));// } catch (InvocationTargetException e) {// Log(Log.getStackTraceString(e));// } } @SuppressLint("NewApi") private void openCamera(boolean isFront) { closeCamera(); this.isFront = isFront; String cId = null; if (isFront) { cId = CameraCharacteristics.LENS_FACING_BACK + ""; } else { cId = CameraCharacteristics.LENS_FACING_FRONT + ""; } CameraManager cManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try { //获取开启相机的相关参数 CameraCharacteristics characteristics = cManager.getCameraCharacteristics(cId); StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); Size[] previewSizes = map.getOutputSizes(SurfaceTexture.class);//获取预览尺寸 Size[] captureSizes = map.getOutputSizes(ImageFormat.JPEG);//获取拍照尺寸 cOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);//获取相机角度 Rect cRect = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);//获取成像区域 cPixelSize = characteristics.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE);//获取成像尺寸,同上 //可用于判断是否支持人脸检测,以及支持到哪种程度 faceDetectModes = characteristics.get(CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES);//支持的人脸检测模式 int maxFaceCount = characteristics.get(CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT);//支持的最大检测人脸数量 //此处写死640*480,实际从预览尺寸列表选择 Size sSize = new Size(640,480);//previewSizes[0]; //设置预览尺寸(避免控件尺寸与预览画面尺寸不一致时画面变形) cView.getSurfaceTexture().setDefaultBufferSize(sSize.getWidth(),sSize.getHeight()); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // ActivityCompat#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 ActivityCompat#requestPermissions for more details. Toast.makeText(this,"请授予摄像头权限",Toast.LENGTH_LONG).show(); ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA}, 0); return; } //根据摄像头ID,开启摄像头 try { cManager.openCamera(cId, getCDeviceOpenCallback(), getCHandler()); } catch (CameraAccessException e) { Log(Log.getStackTraceString(e)); } } catch (CameraAccessException e) { Log(Log.getStackTraceString(e)); } } @SuppressLint("NewApi") private void closeCamera(){ if (cSession != null){ cSession.close(); cSession = null; } if (cDevice!=null){ cDevice.close(); cDevice = null; } if (cImageReader != null) { cImageReader.close(); cImageReader = null; captureRequestBuilder = null; } if(cHandlerThread!=null){ cHandlerThread.quitSafely(); try { cHandlerThread.join(); cHandlerThread = null; cHandler = null; } catch (InterruptedException e) { Log(Log.getStackTraceString(e)); } } } /** * 初始化并获取相机开启回调对象。当准备就绪后,发起预览请求 */ @SuppressLint("NewApi") private CameraDevice.StateCallback getCDeviceOpenCallback(){ if(cDeviceOpenCallback == null){ cDeviceOpenCallback = new CameraDevice.StateCallback() { @Override public void onOpened(@NonNull CameraDevice camera) { cDevice = camera; try { //创建Session,需先完成画面呈现目标(此处为预览和拍照Surface)的初始化 camera.createCaptureSession(Arrays.asList(getPreviewSurface(), getCaptureSurface()), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { cSession = session; //构建预览请求,并发起请求 Log("[发出预览请求]"); try { session.setRepeatingRequest(getPreviewRequest(), getPreviewCallback(), getCHandler()); } catch (CameraAccessException e) { Log(Log.getStackTraceString(e)); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { session.close(); } }, getCHandler()); } catch (CameraAccessException e) { Log(Log.getStackTraceString(e)); } } @Override public void onDisconnected(@NonNull CameraDevice camera) { camera.close(); } @Override public void onError(@NonNull CameraDevice camera, int error) { camera.close(); } }; } return cDeviceOpenCallback; } /** * 初始化并获取相机线程处理 * @return */ private Handler getCHandler(){ if(cHandler==null){ //单独开一个线程给相机使用 cHandlerThread = new HandlerThread("cHandlerThread"); cHandlerThread.start(); cHandler = new Handler(cHandlerThread.getLooper()); } return cHandler; } /** * 获取支持的最高人脸检测级别 * @return */ private int getFaceDetectMode(){ if(faceDetectModes == null){ return CaptureRequest.STATISTICS_FACE_DETECT_MODE_FULL; }else{ return faceDetectModes[faceDetectModes.length-1]; } }/*---------------------------------预览相关---------------------------------*/ /** * 初始化并获取预览回调对象 * @return */ @SuppressLint("NewApi") private CameraCaptureSession.CaptureCallback getPreviewCallback (){ if(previewCallback == null){ previewCallback = new CameraCaptureSession.CaptureCallback(){ public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { MainActivity.this.onCameraImagePreviewed(result); } }; } return previewCallback; } /** * 生成并获取预览请求 * @return */ @SuppressLint("NewApi") private CaptureRequest getPreviewRequest(){ previewRequest = getPreviewRequestBuilder().build(); return previewRequest; } /** * 初始化并获取预览请求构建对象,进行通用配置,并每次获取时进行人脸检测级别配置 * @return */ @SuppressLint("NewApi") private CaptureRequest.Builder getPreviewRequestBuilder(){ if(previewRequestBuilder == null){ try { previewRequestBuilder = cSession.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); previewRequestBuilder.addTarget(getPreviewSurface()); previewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);//自动曝光、白平衡、对焦 } catch (CameraAccessException e) { Log(Log.getStackTraceString(e)); } } previewRequestBuilder.set(CaptureRequest.STATISTICS_FACE_DETECT_MODE,getFaceDetectMode());//设置人脸检测级别 return previewRequestBuilder; } /** * 获取预览Surface * @return */ private Surface getPreviewSurface(){ if(previewSurface == null){ previewSurface = new Surface(cView.getSurfaceTexture()); } return previewSurface; } /** * 处理相机画面处理完成事件,获取检测到的人脸坐标,换算并绘制方框 * @param result */ @SuppressLint({"NewApi", "LocalSuppress"}) private void onCameraImagePreviewed(CaptureResult result){ Face faces[]=result.get(CaptureResult.STATISTICS_FACES); showMessage(false,"人脸个数:["+faces.length+"]"); Canvas canvas = rView.lockCanvas(); canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);//旧画面清理覆盖 if(faces.length>0){ for(int i=0;i
界面代码 <?xml version="1.0" encoding="utf-8"?>
更多相关文章
- Android--多媒体
- Writing code that captures videos on Android(录制视频,带相机
- android相机开发setParameters failed错误
- 【Android】Eclipse报This version of the rendering library is
- Android(安卓)Camera(五)
- Android实时监控项目第四篇:后台线程发送预览帧视频数据
- 已解决:Android向SD卡存储数据时出现java.io.FileNotFoundExcepti
- Android简单实现仿微信选择图片以及拍照(PhotoPicker)
- Android(安卓)Studio 视图预览不显示了,