Forráskód Böngészése

优化生物识别实时识别

gavin.chen 1 éve
szülő
commit
7f12150260

+ 26 - 11
lib/pages/facial_recognition/controller.dart

@@ -44,7 +44,11 @@ class FacialRecognitionController extends GetxController
     _baseScale = _currentScale;
   }
 
-  List<Face> facesResult = [];
+  /// 当前捕获帧的人脸列表
+  List<Face> kFrameFacesResult = [];
+
+  /// 当前捕获帧大小
+  Size kFrameImageSize = Size.zero;
 
   /// 缩放更新
   Future<void> handleScaleUpdate(ScaleUpdateDetails details) async {
@@ -314,9 +318,10 @@ class FacialRecognitionController extends GetxController
     var pictureRecorder = ui.PictureRecorder();
     Canvas canvas = Canvas(pictureRecorder);
     canvas.drawImageRect(image, src, dst, Paint());
-    return pictureRecorder
-        .endRecording()
-        .toImage(dst.width.floor(), dst.height.floor());
+    return pictureRecorder.endRecording().toImage(
+          dst.width.floor(),
+          dst.height.floor(),
+        );
   }
 
   /// 发生拍摄身份证事件
@@ -339,6 +344,7 @@ class FacialRecognitionController extends GetxController
           state.isShowIdCardInfoSwitch = true;
           state.isIdCardInfoShow = true;
           state.isInFaceRecognition = true;
+          openFrontCamera();
         }
 
         debugShowCache();
@@ -483,7 +489,7 @@ class FacialRecognitionController extends GetxController
   void onReady() async {
     super.onReady();
     await initAvailableCameras();
-    openFrontCamera();
+    openBackCamera();
   }
 
   /// 在 [onDelete] 方法之前调用。
@@ -532,8 +538,17 @@ class FacialRecognitionController extends GetxController
       FaceDetector faceDetector, String imageFilePath) async {
     inputImage = InputImage.fromFilePath(imageFilePath);
     final List<Face> faces = await faceDetector.processImage(inputImage);
-    facesResult = [];
-    facesResult.addAll(faces);
+    kFrameFacesResult = [];
+    kFrameFacesResult.addAll(faces);
+    if (inputImage.metadata != null) {
+      kFrameImageSize = inputImage.metadata!.size;
+    } else {
+      if (kCameraController != null) {
+        final CameraController cameraController = kCameraController!;
+        // kFrameImageSize = cameraController.value.previewSize ?? Size.zero;
+        kFrameImageSize = const Size(1920, 1080);
+      }
+    }
     for (Face face in faces) {
       final Rect boundingBox = face.boundingBox;
 
@@ -565,26 +580,26 @@ class FacialRecognitionController extends GetxController
 
   void runDetectionTimer() {
     if (_detectionTimer != null) {
-      state.isShowFaceRecognitionResult = false;
       _detectionTimer!.cancel();
       _detectionTimer = null;
       faceDetector.close();
+      state.isShowFaceRecognitionResult = false;
       return;
     }
     final options = FaceDetectorOptions();
     faceDetector =
         FaceDetector(options: FaceDetectorOptions(enableContours: true));
+    state.isShowFaceRecognitionResult = true;
     _detectionTimer = Timer.periodic(
-      const Duration(milliseconds: 1000),
+      const Duration(milliseconds: 200),
       (timer) async {
         if (kCameraController == null) {
           return;
         }
         final XFile? file = await takePicture();
         if (file != null) {
-          state.isShowFaceRecognitionResult = false;
           await doDetection(faceDetector, file.path);
-          state.isShowFaceRecognitionResult = true;
+          update(['face_bounding_box']);
         }
       },
     );

+ 6 - 5
lib/pages/facial_recognition/view.dart

@@ -43,7 +43,7 @@ class FacialRecognitionPage extends GetView<FacialRecognitionController> {
               return Stack(
                 children: <Widget>[
                   OverflowBox(
-                    maxHeight: constraints.maxHeight + 10,
+                    maxHeight: constraints.maxHeight,
                     maxWidth: 2000,
                     child: Container(
                       color: Colors.black,
@@ -55,10 +55,10 @@ class FacialRecognitionPage extends GetView<FacialRecognitionController> {
                   Center(
                     child: Stack(
                       children: [
-                        const Align(
-                          alignment: Alignment.center,
-                          child: FaceBoundingBox(),
-                        ),
+                        // const Align(
+                        //   alignment: Alignment.center,
+                        //   child: FaceBoundingBox(),
+                        // ),
                         Align(
                           alignment: Alignment.centerLeft,
                           child: _idCardInfoSwitch(),
@@ -101,6 +101,7 @@ class FacialRecognitionPage extends GetView<FacialRecognitionController> {
                 onScaleUpdate: controller.handleScaleUpdate,
                 onTapDown: (TapDownDetails details) =>
                     controller.onViewFinderTap(details, constraints),
+                child: const FaceBoundingBox(),
               );
             },
           ),

+ 32 - 32
lib/pages/facial_recognition/widgets/camera_for_face.dart

@@ -9,38 +9,38 @@ class CameraForFace extends GetView<FacialRecognitionController> {
   Widget build(BuildContext context) {
     return Stack(
       children: <Widget>[
-        Align(
-          alignment: Alignment.center,
-          child: OverflowBox(
-            maxHeight: 2000,
-            maxWidth: 2000,
-            child: Container(
-              decoration: BoxDecoration(
-                border: Border.all(
-                  color: const Color.fromARGB(80, 0, 0, 0),
-                  width: 500,
-                  strokeAlign: BorderSide.strokeAlignOutside,
-                ),
-                borderRadius: BorderRadius.circular(50),
-              ),
-              margin: const EdgeInsets.only(bottom: 110),
-              child: const SizedBox(
-                width: 465,
-                height: 430,
-              ),
-            ),
-          ),
-        ),
-        Align(
-          alignment: Alignment.center,
-          child: Container(
-            margin: const EdgeInsets.only(top: 80),
-            child: const Image(
-              image: AssetImage('assets/images/face_rec.png'),
-              width: 800,
-            ),
-          ),
-        ),
+        // Align(
+        //   alignment: Alignment.center,
+        //   child: OverflowBox(
+        //     maxHeight: 2000,
+        //     maxWidth: 2000,
+        //     child: Container(
+        //       decoration: BoxDecoration(
+        //         border: Border.all(
+        //           color: const Color.fromARGB(80, 0, 0, 0),
+        //           width: 500,
+        //           strokeAlign: BorderSide.strokeAlignOutside,
+        //         ),
+        //         borderRadius: BorderRadius.circular(50),
+        //       ),
+        //       margin: const EdgeInsets.only(bottom: 110),
+        //       child: const SizedBox(
+        //         width: 465,
+        //         height: 430,
+        //       ),
+        //     ),
+        //   ),
+        // ),
+        // Align(
+        //   alignment: Alignment.center,
+        //   child: Container(
+        //     margin: const EdgeInsets.only(top: 80),
+        //     child: const Image(
+        //       image: AssetImage('assets/images/face_rec.png'),
+        //       width: 800,
+        //     ),
+        //   ),
+        // ),
         Align(
           alignment: Alignment.centerRight,
           child: Container(

+ 50 - 30
lib/pages/facial_recognition/widgets/face_bounding_box.dart

@@ -16,12 +16,18 @@ class FaceBoundingBox extends GetView<FacialRecognitionController> {
       }
       return Container(
         padding: const EdgeInsets.all(10),
-        child: CustomPaint(
-          size: Size.infinite,
-          painter: _FaceBoundingBoxPainter(
-            faces: controller.facesResult,
-          ),
-        ),
+        child: GetBuilder<FacialRecognitionController>(
+            id: 'face_bounding_box',
+            builder: (context) {
+              return CustomPaint(
+                size: Size.infinite,
+                painter: _FaceBoundingBoxPainter(
+                  faces: controller.kFrameFacesResult,
+                  sourceImageSize: controller.kFrameImageSize,
+                  isMirror: true,
+                ),
+              );
+            }),
       );
     });
   }
@@ -30,30 +36,31 @@ class FaceBoundingBox extends GetView<FacialRecognitionController> {
 class _FaceBoundingBoxPainter extends CustomPainter {
   final List<Face> faces;
 
-  _FaceBoundingBoxPainter({required this.faces});
+  /// 是否镜像
+  final bool isMirror;
+
+  /// 原始图片大小
+  final Size sourceImageSize;
+
+  _FaceBoundingBoxPainter(
+      {required this.faces,
+      required this.isMirror,
+      required this.sourceImageSize});
 
   @override
   void paint(Canvas canvas, Size size) {
-    final paint = Paint()
-      ..color = Colors.red
-      ..strokeWidth = 3
-      ..style = PaintingStyle.stroke;
-
-    final contourPaint = Paint()
-      ..color = Colors.red
-      ..strokeWidth = 2
-      ..style = PaintingStyle.stroke;
+    // 根据原始图片大小和当前画布大小,计算缩放比例
+    final scaleX = size.width / sourceImageSize.width;
+    final scaleY = size.height / sourceImageSize.height;
+    if (isMirror) {
+      canvas.scale(-scaleX, scaleY);
+      canvas.translate(-sourceImageSize.width, 0);
+    } else {
+      canvas.scale(scaleX, scaleY);
+      canvas.translate(0, 0);
+    }
 
     for (final face in faces) {
-      // 将 rect 内参数左右镜像翻转
-      // final newRect = Rect.fromLTWH(
-      //   size.width - face.boundingBox.right,
-      //   face.boundingBox.top,
-      //   face.boundingBox.width,
-      //   face.boundingBox.height,
-      // );
-      // canvas.drawRect(newRect, paint);
-
       /// 绘制关键点
       for (final FaceContour? contour in face.contours.values) {
         if (contour == null) continue;
@@ -64,6 +71,9 @@ class _FaceBoundingBoxPainter extends CustomPainter {
           _drawContourPoints(canvas, size, contour.points);
         }
       }
+
+      /// 绘制人脸框
+      _drawFaceRect(canvas, size, face.boundingBox);
     }
 
     /// 全屏画绿色
@@ -73,7 +83,7 @@ class _FaceBoundingBoxPainter extends CustomPainter {
       ..style = PaintingStyle.stroke;
 
     canvas.drawRect(
-      Rect.fromLTWH(0, 0, size.width, size.height),
+      Rect.fromLTWH(0, 0, sourceImageSize.width, sourceImageSize.height),
       paint2,
     );
   }
@@ -91,13 +101,13 @@ class _FaceBoundingBoxPainter extends CustomPainter {
       final point = points[i];
       if (i == 0) {
         path.moveTo(
-          size.width - point.x,
+          point.x.toDouble(),
           point.y.toDouble(),
         );
         continue;
       }
       path.lineTo(
-        size.width - point.x,
+        point.x.toDouble(),
         point.y.toDouble(),
       );
     }
@@ -115,7 +125,7 @@ class _FaceBoundingBoxPainter extends CustomPainter {
     for (final point in points) {
       canvas.drawCircle(
         Offset(
-          size.width - point.x.toDouble(),
+          point.x.toDouble(),
           point.y.toDouble(),
         ),
         2,
@@ -124,6 +134,16 @@ class _FaceBoundingBoxPainter extends CustomPainter {
     }
   }
 
+  /// 绘制人脸框
+  void _drawFaceRect(Canvas canvas, Size size, Rect rect) {
+    final paint = Paint()
+      ..color = Colors.green
+      ..strokeWidth = 2
+      ..style = PaintingStyle.stroke;
+
+    canvas.drawRect(rect, paint);
+  }
+
   @override
-  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
+  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
 }

+ 2 - 2
pubspec.lock

@@ -932,8 +932,8 @@ packages:
     dependency: "direct main"
     description:
       path: "."
-      ref: "05786f1c82"
-      resolved-ref: "05786f1c827c45dc994793cdff329a8fdc347c8e"
+      ref: "6262d75192"
+      resolved-ref: "6262d751921c7e82bec36c95abf06e269b0b3d32"
       url: "http://git.ius.plus/Project-Vital/FlutterDevicePlugin.git"
     source: git
     version: "0.0.1"