Show menu

main.dart

  void main() => runApp(DemoApp());

  class DemoApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
      return ChangeNotifierProvider<FaceProvider>(
        create: (_) => FaceProvider(),
        child: MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: const Text("Face detection"),
            ),
            body: const DetectionWidget(),
          ),
        ),
      );
    }
  }
  

face_provider.dart

  class FaceProvider with ChangeNotifier {
    bool _showDetector = false;

    bool get isDetectorVisible => _showDetector;

    void setDetectorVisible(bool isVisible) {
      _showDetector = isVisible;
      notifyListeners();
    }
  }
  

face_detector_data.dart

  class FaceDetectorData {
    final List<Face> faces;
    final ui.Image image;
    const FaceDetectorData(this.faces, this.image);
  }
  

face_detector_model.dart

  class FaceDetectorModel {
    const FaceDetectorModel();

    Future<FaceDetectorData> detectFaces() async {
      // Choose the image
      final picker = ImagePicker();
      final imageFile = await picker.getImage(
        source: ImageSource.gallery,
        maxWidth: 260,
        maxHeight: 250,
      );

      // Detect faces
      final file = File(imageFile.path);
      final image = FirebaseVisionImage.fromFile(file);
      final detector = FirebaseVision.instance.faceDetector();

      // Process data
      final faces = await detector.processImage(image);
      final canvasImage = await _decodeImage(file);
      return FaceDetectorData(faces, canvasImage);
    }

    Future<ui.Image> _decodeImage(File file) async {
      final rawFile = await file.readAsBytes();
      final codec = await instantiateImageCodec(rawFile);
      final frameInfo = await codec.getNextFrame();
      return frameInfo.image;
    }
  }
  

rectangle_painter.dart

  class RectanglePainter extends CustomPainter {
    final List<Face> facesPositions;
    final ui.Image selectedImage;

    static final Paint _painter = Paint()
      ..style = PaintingStyle.stroke  
      ..strokeWidth = 3.0
      ..color = Colors.redAccent;

    const RectanglePainter({
      this.facesPositions,
      this.selectedImage
    });

    @override
    void paint(Canvas canvas, Size size) {
      canvas.drawImage(selectedImage, Offset.zero, Paint());

      for(final face in facesPositions) {
        final coords = face.boundingBox;
        final rect = Rect.fromLTRB(
          coords.left,
          coords.top,
          coords.right,
          coords.bottom
        );

        canvas.drawRect(rect, _painter);
      }
    }

    @override
    bool shouldRepaint(RectanglePainter oldDelegate) =>
        selectedImage != oldDelegate.selectedImage ||
        facesPositions != oldDelegate.facesPositions;
    }
  

face_detector_widget.dart

  class DetectFacesFromImage extends StatefulWidget {
    const DetectFacesFromImage();

    @override
    _DetectFacesFromImageState createState() => _DetectFacesFromImageState();
  }

  class _DetectFacesFromImageState extends State<DetectFacesFromImage> {
    Future<FaceDetectorData> _faces;
    final _model = FaceDetectorModel();

    @override
    void initState() {
      super.initState();

      _faces = _model.detectFaces();
    }

    @override
    Widget build(BuildContext context) {
      return FutureBuilder<FaceDetectorData>(
        future: _faces,
        builder: (context, facesList) {
          if (facesList.hasData) {
            final data = facesList.data;

            if (data != null) {
              return Center(
                child: Wrap(
                  spacing: 10,
                  crossAxisAlignment: WrapCrossAlignment.center,
                  direction: Axis.vertical,
                  children: <Widget>[
                    SizedBox(
                      width: 260,
                      height: 250,
                      child: CustomPaint(
                        painter: RectanglePainter(
                            facesPositions: data.faces,
                            selectedImage: data.image
                        ),
                      ),
                    ),

                    Consumer<FaceProvider>(
                      builder: (context, detector, _) {
                        return RaisedButton(
                          child: const Text("New detection"),
                          onPressed: () => detector.setDetectorVisible(false),
                        );
                      },
                    ),
                  ],
                ),
              );
            } else {
              return const Center(
                child: Text("Error while processing data :("),
              );
            }
          }

          return const Center(
            child: CircularProgressIndicator(),
          );
        },
      );
    }
  }
  

detection_img_picker.dart

  class DetectionImgPicker extends StatelessWidget {
    const DetectionImgPicker();

    @override
    Widget build(BuildContext context) {
      return Center(
        child: Wrap(
          direction: Axis.vertical,
          spacing: 30,
          crossAxisAlignment: WrapCrossAlignment.center,
          children: <Widget>[
            Icon(Icons.tag_faces,
              size: 40,
              color: Colors.blueAccent,
            ),

            Consumer<FaceProvider>(
              builder: (context, faceDetector, _) {
                return RaisedButton(
                  color: Colors.green,
                  textColor: Colors.white,
                  child: const Text("Detect faces"),
                  onPressed: () => faceDetector.setDetectorVisible(true),
                );
              },
            ),
          ],
        ),
      );
    }

  }
  

detection_widget.dart

  class DetectionWidget extends StatelessWidget {
    const DetectionWidget();

    @override
    Widget build(BuildContext context) {
      return Consumer<FaceProvider>(
        builder: (context, faceDetector, _) {
          if (faceDetector.isDetectorVisible) {
            return const DetectFacesFromImage();
          }

          return const DetectionImgPicker();
        },
      );
    }
  }
  

This website and the book are not official Google products. No affiliations are involved. Built with Java 14 and Vert.X

"Flutter and the related logo are trademarks of Google LLC. We are not endorsed by or affiliated with Google LLC"