Pārlūkot izejas kodu

1.mlkit人脸识别

JaycePC 7 mēneši atpakaļ
vecāks
revīzija
25bcbbf8c6

+ 232 - 0
app/src/main/java/com/example/chemical/ui/verify/fragment/FaceDetectFragment.java

@@ -0,0 +1,232 @@
+package com.example.chemical.ui.verify.fragment;
+
+import android.annotation.SuppressLint;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Matrix;
+import android.os.Bundle;
+import android.util.Log;
+import android.util.Size;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.core.CameraSelector;
+import androidx.camera.core.ImageAnalysis;
+import androidx.camera.core.ImageCapture;
+import androidx.camera.core.ImageCaptureException;
+import androidx.camera.core.ImageProxy;
+import androidx.camera.core.Preview;
+import androidx.camera.lifecycle.ProcessCameraProvider;
+import androidx.core.content.ContextCompat;
+import androidx.fragment.app.Fragment;
+
+import com.blankj.utilcode.util.LogUtils;
+import com.blankj.utilcode.util.ThreadUtils;
+import com.example.chemical.databinding.FragmentFaceDetectBinding;
+import com.example.chemical.ui.verify.DoubleVerifyActivity;
+import com.google.android.gms.tasks.OnSuccessListener;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.mlkit.vision.common.InputImage;
+import com.google.mlkit.vision.face.Face;
+import com.google.mlkit.vision.face.FaceDetection;
+import com.google.mlkit.vision.face.FaceDetector;
+import com.google.mlkit.vision.face.FaceDetectorOptions;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class FaceDetectFragment extends Fragment {
+    private static FaceDetectFragment instance; // 静态实例
+    private FragmentFaceDetectBinding binding;
+    private FaceDetector faceDetector;
+    private ExecutorService cameraExecutor;
+
+    private ProcessCameraProvider cameraProvider;
+
+    private ImageAnalysis imageAnalyzer;
+
+    private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
+
+    private int lastSize = 0;
+
+    private boolean isPause = false;
+
+    private DoubleVerifyActivity.DoubleVerifyListener doubleVerifyListener;
+
+    private Runnable providerFutureRunnable;
+    private Preview preview;
+
+    private FaceDetectFragment() {
+    }
+
+    // 静态方法,获取实例
+    public static FaceDetectFragment getInstance() {
+        if (instance == null) {
+            instance = new FaceDetectFragment();
+        }
+        return instance;
+    }
+
+    @Nullable
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+        binding = FragmentFaceDetectBinding.inflate(inflater, container, false);
+        return binding.getRoot();
+    }
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (instance != null && instance != this) {
+            getParentFragmentManager().beginTransaction()
+                    .replace(getId(), instance)
+                    .commit();
+        } else {
+            instance = this;
+        }
+    }
+
+    public void startFaceDetect() {
+        cameraExecutor = Executors.newSingleThreadExecutor();
+        FaceDetectorOptions options = new FaceDetectorOptions.Builder()
+                .setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_FAST)
+                .setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL)
+                .setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL)
+                .build();
+        faceDetector = FaceDetection.getClient(options);
+        startCamera();
+        isPause = false;
+    }
+
+    public void stopFaceDetect() {
+        isPause = true;
+        recycleFaceDetect();
+    }
+
+    @SuppressLint("RestrictedApi")
+    private void recycleFaceDetect() {
+        // 释放相机资源
+        if (cameraProvider != null) {
+            cameraProvider.unbindAll();
+            cameraProvider = null;
+
+            // 释放 FaceAnalyzer
+            if (imageAnalyzer != null) {
+                imageAnalyzer.clearAnalyzer(); // 清除 Analyzer
+            }
+        }
+        if (null != cameraExecutor) {
+            // 关闭线程池
+            cameraExecutor.shutdown();
+        }
+        if (null != faceDetector) {
+            // 释放人脸检测器
+            faceDetector.close();
+        }
+        if (null != providerFutureRunnable) {
+            preview.onDetached();
+            cameraProviderFuture.cancel(true);
+            providerFutureRunnable = null;
+        }
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        recycleFaceDetect();
+    }
+
+    private void startCamera() {
+        cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext());
+        if (null == providerFutureRunnable) {
+            providerFutureRunnable = new Runnable() {
+
+                @Override
+                public void run() {
+                    try {
+                        cameraProvider = cameraProviderFuture.get();
+                        // 预览用例
+                        preview = new Preview.Builder().build();
+                        preview.setSurfaceProvider(binding.previewView.getSurfaceProvider());
+                        // 图像分析用例
+                        imageAnalyzer =
+                                new ImageAnalysis.Builder()
+                                        .setTargetResolution(new Size(640, 480))
+                                        .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
+                                        .build();
+                        imageAnalyzer.setAnalyzer(cameraExecutor, new ImageAnalysis.Analyzer() {
+                            @Override
+                            public void analyze(@NonNull ImageProxy imageProxy) {
+                                ImageProxy.PlaneProxy[] planes = imageProxy.getPlanes();
+                                int rotationDegrees = imageProxy.getImageInfo().getRotationDegrees();
+                                if (planes.length == 0 || planes[0] == null) {
+                                    return;
+                                }
+                                InputImage image = InputImage.fromByteBuffer(
+                                        planes[0].getBuffer(),
+                                        imageProxy.getWidth(),
+                                        imageProxy.getHeight(),
+                                        rotationDegrees,
+                                        InputImage.IMAGE_FORMAT_NV21 // 或其他格式
+                                );
+                                if (isPause) {
+                                    imageProxy.close();
+                                    if (binding.hintTV.getVisibility() == View.VISIBLE) {
+                                        ThreadUtils.runOnUiThread(() -> binding.hintTV.setVisibility(View.GONE));
+                                    }
+                                } else {
+                                    faceDetector.process(image)
+                                            .addOnSuccessListener(
+                                                    new OnSuccessListener<List<Face>>() {
+                                                        @Override
+                                                        public void onSuccess(List<Face> faces) {
+
+                                                            if (binding.hintTV.getVisibility() == View.GONE) {
+                                                                binding.hintTV.setVisibility(View.VISIBLE);
+                                                            }
+                                                            if (null == faces || faces.isEmpty() || lastSize == faces.size()) {
+                                                                binding.hintTV.setText("未检测到人脸");
+                                                                return;
+                                                            }
+                                                            lastSize = faces.size();
+                                                            if (faces.size() > 1) {
+                                                                binding.hintTV.setText("请确保相机区域内只有一个人脸");
+                                                                return;
+                                                            }
+                                                            isPause = true;
+                                                            if (null != doubleVerifyListener) {
+                                                                doubleVerifyListener.detect(DetectType.FACE_DETECT, null, false);
+                                                            }
+                                                        }
+                                                    })
+                                            .addOnFailureListener(
+                                                    e -> LogUtils.e("人脸检测失败", Log.getStackTraceString(e)))
+                                            .addOnCompleteListener(task -> imageProxy.close());
+                                }
+                            }
+                        });
+                        // 选择摄像头
+                        CameraSelector cameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA;
+                        // 解绑之前的用例
+                        cameraProvider.unbindAll();
+                        // 绑定用例到相机
+                        cameraProvider.bindToLifecycle(getViewLifecycleOwner(), cameraSelector, preview, imageAnalyzer);
+                    } catch (Exception e) {
+                        LogUtils.e(Log.getStackTraceString(e));
+                    }
+                }
+            };
+        }
+        cameraProviderFuture.addListener(providerFutureRunnable, ContextCompat.getMainExecutor(requireContext()));
+    }
+
+    public void setActivityListener(DoubleVerifyActivity.DoubleVerifyListener doubleVerifyListener) {
+        this.doubleVerifyListener = doubleVerifyListener;
+    }
+}