【Android App】人脸识别中借助摄像头和OpenCV实时检测人脸讲解及实战(附源码和演示 超详细)
需要全部代碼請點贊關注收藏后評論區留言私信~~~
一、借助攝像頭實時檢測人臉
與Android自帶的人臉檢測器相比,OpenCV具備更強勁的人臉識別功能,它可以通過攝像頭實時檢測人臉,實時檢測的預覽空間是JavaCameraView 常用方法說明如下
setCvCameraViewListener:設置OpenCV的相機視圖監聽器。監聽器需要寫下列三個狀態變更方法:
onCameraViewStarted:相機視圖開始預覽時回調。
onCameraViewStopped:相機視圖停止預覽時回調。
onCameraFrame:相機視圖預覽變更時回調。
enableView:啟用OpenCV的相機視圖。
?disableView:禁用OpenCV的相機視圖。
接下來把JavaCameraView加入App工程,走一遍它的詳細使用過程,首先修改AndroidManifest.xml補充一行相機權限配置
<uses-permission android:name="android.permission.CAMERA"/>實時檢測人臉有如下四個步驟
(1)從布局文件中獲得相機視圖對象后,調用它的setCvCameraViewListener方法,設置OpenCV的相機視圖監聽器。
(2)OpenCV初始化與資源加載完成后,調用enableView方法開啟相機視圖。
(3)活動類由繼承AppCompatActivity改為繼承CameraActivity類,并重寫getCameraViewList方法,返回相機視圖的單例列表。
(4)第一步重寫監聽器接口的onCameraFrame方法時,補充人臉識別等處理邏輯,也就是先檢測人臉,再給人臉標上相框。
二、效果展示
運行測試App 會自動打開手機攝像機 然后檢測攝像機內的人臉
由頂部狀態欄可以看到打開了相機功能 此處用了博主小時候的照片~~~
三、代碼?
部分代碼如下 需要全部源碼請點贊關注收藏后評論區留言~~~
package com.example.face;import android.content.Context; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.widget.TextView;import com.example.face.util.DateUtil;import org.opencv.android.CameraActivity;import org.opencv.android.BaseLoaderCallback; import org.opencv.android.CameraBridgeViewBase; import org.opencv.android.LoaderCallbackInterface; import org.opencv.android.OpenCVLoader; import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.core.MatOfRect; import org.opencv.core.Rect; import org.opencv.core.Scalar; import org.opencv.core.Size; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc; import org.opencv.objdetect.CascadeClassifier;import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.util.Collections; import java.util.List;//OpenCV的實時掃描頁面必須繼承CameraActivity public class DetectRealtimeActivity extends CameraActivity implements CameraBridgeViewBase.CvCameraViewListener2 {private static final String TAG = "DetectRealtimeActivity";private static final Scalar FACE_RECT_COLOR = new Scalar(0, 255, 0, 255);private Mat mRgba, mGray; // 全彩矩陣,灰度矩陣private CascadeClassifier mJavaDetector; // OpenCV的人臉檢測器private int mAbsoluteFaceSize = 0; // 絕對人臉大小// OpenCV默認橫屏掃描,需要旋轉90度改成豎屏預覽,詳細改動見CameraBridgeViewBase.java的deliverAndDrawFrame方法private CameraBridgeViewBase jcv_detect; // 聲明一個OpenCV的相機視圖對象@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_detect_realtime);findViewById(R.id.iv_back).setOnClickListener(v -> finish());TextView tv_title = findViewById(R.id.tv_title);tv_title.setText("實時檢測人臉");jcv_detect = findViewById(R.id.jcv_detect);jcv_detect.setVisibility(CameraBridgeViewBase.VISIBLE);jcv_detect.setCvCameraViewListener(this); // 設置OpenCV的相機視圖監聽器}@Overridepublic void onPause() {super.onPause();if (jcv_detect != null) {jcv_detect.disableView(); // 禁用OpenCV的相機視圖}}@Overridepublic void onResume() {super.onResume();if (!OpenCVLoader.initDebug()) {Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);} else {Log.d(TAG, "OpenCV library found inside package. Using it!");mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);}}@Overrideprotected List<? extends CameraBridgeViewBase> getCameraViewList() {return Collections.singletonList(jcv_detect);}@Overridepublic void onDestroy() {super.onDestroy();jcv_detect.disableView(); // 禁用OpenCV的相機視圖}@Overridepublic void onCameraViewStarted(int width, int height) {mGray = new Mat();mRgba = new Mat();}@Overridepublic void onCameraViewStopped() {mGray.release();mRgba.release();}// 相機預覽回調@Overridepublic Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {mRgba = inputFrame.rgba();mGray = inputFrame.gray();Core.rotate(mRgba, mRgba, Core.ROTATE_90_CLOCKWISE); // 適配豎屏,順時針旋轉90度Core.rotate(mGray, mGray, Core.ROTATE_90_CLOCKWISE); // 適配豎屏,順時針旋轉90度if (mAbsoluteFaceSize == 0) {Log.d(TAG, "width="+mGray.width()+", height="+mGray.height()+", cols="+mGray.cols()+", rows="+mGray.rows());int height = mGray.rows();if (Math.round(height * 0.2f) > 0) {mAbsoluteFaceSize = Math.round(height * 0.2f);} // String filePath = String.format("%s/%s.jpg", // getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(), // DateUtil.getNowDateTime()); // Imgcodecs.imwrite(filePath, mRgba); // Log.d(TAG, "filePath="+filePath);}MatOfRect faces = new MatOfRect();if (mJavaDetector != null) { // 檢測器開始識別人臉mJavaDetector.detectMultiScale(mGray, faces, 1.1, 2, 2,new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());}Rect[] faceArray = faces.toArray();for (Rect rect : faceArray) { // 給找到的人臉標上相框Imgproc.rectangle(mRgba, rect.tl(), rect.br(), FACE_RECT_COLOR, 3);Log.d(TAG, rect.toString());}Core.rotate(mRgba, mRgba, Core.ROTATE_90_COUNTERCLOCKWISE); // 恢復原狀,逆時針旋轉90度return mRgba;}private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {@Overridepublic void onManagerConnected(int status) {if (status == LoaderCallbackInterface.SUCCESS) {Log.d(TAG, "OpenCV loaded successfully");// 在OpenCV初始化完成后加載so庫System.loadLibrary("detection_based_tracker");File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);File cascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");// 從應用程序資源加載級聯文件try (InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);FileOutputStream os = new FileOutputStream(cascadeFile)) {byte[] buffer = new byte[4096];int bytesRead;while ((bytesRead = is.read(buffer)) != -1) {os.write(buffer, 0, bytesRead);}} catch (Exception e) {e.printStackTrace();}// 根據級聯文件創建OpenCV的人臉檢測器mJavaDetector = new CascadeClassifier(cascadeFile.getAbsolutePath());if (mJavaDetector.empty()) {Log.d(TAG, "Failed to load cascade classifier");mJavaDetector = null;} else {Log.d(TAG, "Loaded cascade classifier from " + cascadeFile.getAbsolutePath());}cascadeDir.delete();jcv_detect.enableView(); // 啟用OpenCV的相機視圖} else {super.onManagerConnected(status);}}};}創作不易? 覺得有幫助請點贊關注收藏~~~
總結
以上是生活随笔為你收集整理的【Android App】人脸识别中借助摄像头和OpenCV实时检测人脸讲解及实战(附源码和演示 超详细)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Bioinformatics】背曲拇指
- 下一篇: 软件接口设计中的版本兼容问题处理