-
Notifications
You must be signed in to change notification settings - Fork 724
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into feature/rot_comp
- Loading branch information
Showing
29 changed files
with
969 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
84 changes: 84 additions & 0 deletions
84
packages/example/lib/vision_detector_views/face_mesh_detector_view.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import 'dart:io'; | ||
|
||
import 'package:camera/camera.dart'; | ||
import 'package:flutter/material.dart'; | ||
import 'package:google_mlkit_face_mesh_detection/google_mlkit_face_mesh_detection.dart'; | ||
|
||
import 'detector_view.dart'; | ||
import 'painters/face_mesh_detector_painter.dart'; | ||
|
||
class FaceMeshDetectorView extends StatefulWidget { | ||
@override | ||
State<FaceMeshDetectorView> createState() => _FaceMeshDetectorViewState(); | ||
} | ||
|
||
class _FaceMeshDetectorViewState extends State<FaceMeshDetectorView> { | ||
final FaceMeshDetector _meshDetector = | ||
FaceMeshDetector(option: FaceMeshDetectorOptions.faceMesh); | ||
bool _canProcess = true; | ||
bool _isBusy = false; | ||
CustomPaint? _customPaint; | ||
String? _text; | ||
var _cameraLensDirection = CameraLensDirection.front; | ||
|
||
@override | ||
void dispose() { | ||
_canProcess = false; | ||
_meshDetector.close(); | ||
super.dispose(); | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
if (Platform.isIOS) { | ||
return Scaffold( | ||
appBar: AppBar(title: Text('Under construction')), | ||
body: Center( | ||
child: Text( | ||
'Not implemented yet for iOS :(\nTry Android', | ||
textAlign: TextAlign.center, | ||
)), | ||
); | ||
} | ||
return DetectorView( | ||
title: 'Face Mesh Detector', | ||
customPaint: _customPaint, | ||
text: _text, | ||
onImage: _processImage, | ||
initialCameraLensDirection: _cameraLensDirection, | ||
onCameraLensDirectionChanged: (value) => _cameraLensDirection = value, | ||
); | ||
} | ||
|
||
Future<void> _processImage(InputImage inputImage) async { | ||
if (!_canProcess) return; | ||
if (_isBusy) return; | ||
_isBusy = true; | ||
setState(() { | ||
_text = ''; | ||
}); | ||
final meshes = await _meshDetector.processImage(inputImage); | ||
if (inputImage.metadata?.size != null && | ||
inputImage.metadata?.rotation != null) { | ||
final painter = FaceMeshDetectorPainter( | ||
meshes, | ||
inputImage.metadata!.size, | ||
inputImage.metadata!.rotation, | ||
_cameraLensDirection, | ||
); | ||
_customPaint = CustomPaint(painter: painter); | ||
} else { | ||
String text = 'Face meshes found: ${meshes.length}\n\n'; | ||
for (final mesh in meshes) { | ||
text += 'face: ${mesh.boundingBox}\n\n'; | ||
} | ||
_text = text; | ||
// TODO: set _customPaint to draw boundingRect on top of image | ||
_customPaint = null; | ||
} | ||
_isBusy = false; | ||
if (mounted) { | ||
setState(() {}); | ||
} | ||
} | ||
} |
103 changes: 103 additions & 0 deletions
103
packages/example/lib/vision_detector_views/painters/face_mesh_detector_painter.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import 'dart:ui'; | ||
|
||
import 'package:camera/camera.dart'; | ||
import 'package:flutter/material.dart'; | ||
import 'package:google_mlkit_face_mesh_detection/google_mlkit_face_mesh_detection.dart'; | ||
|
||
import 'coordinates_translator.dart'; | ||
|
||
class FaceMeshDetectorPainter extends CustomPainter { | ||
FaceMeshDetectorPainter( | ||
this.meshes, | ||
this.imageSize, | ||
this.rotation, | ||
this.cameraLensDirection, | ||
); | ||
|
||
final List<FaceMesh> meshes; | ||
final Size imageSize; | ||
final InputImageRotation rotation; | ||
final CameraLensDirection cameraLensDirection; | ||
|
||
@override | ||
void paint(Canvas canvas, Size size) { | ||
final Paint paint1 = Paint() | ||
..style = PaintingStyle.stroke | ||
..strokeWidth = 1.0 | ||
..color = Colors.red; | ||
final Paint paint2 = Paint() | ||
..style = PaintingStyle.fill | ||
..strokeWidth = 1.0 | ||
..color = Colors.white; | ||
|
||
for (final FaceMesh mesh in meshes) { | ||
final left = translateX( | ||
mesh.boundingBox.left, | ||
size, | ||
imageSize, | ||
rotation, | ||
cameraLensDirection, | ||
); | ||
final top = translateY( | ||
mesh.boundingBox.top, | ||
size, | ||
imageSize, | ||
rotation, | ||
cameraLensDirection, | ||
); | ||
final right = translateX( | ||
mesh.boundingBox.right, | ||
size, | ||
imageSize, | ||
rotation, | ||
cameraLensDirection, | ||
); | ||
final bottom = translateY( | ||
mesh.boundingBox.bottom, | ||
size, | ||
imageSize, | ||
rotation, | ||
cameraLensDirection, | ||
); | ||
|
||
canvas.drawRect( | ||
Rect.fromLTRB(left, top, right, bottom), | ||
paint1, | ||
); | ||
|
||
void paintTriangle(FaceMeshTriangle triangle) { | ||
final List<Offset> cornerPoints = <Offset>[]; | ||
for (final point in triangle.points) { | ||
final double x = translateX( | ||
point.x.toDouble(), | ||
size, | ||
imageSize, | ||
rotation, | ||
cameraLensDirection, | ||
); | ||
final double y = translateY( | ||
point.y.toDouble(), | ||
size, | ||
imageSize, | ||
rotation, | ||
cameraLensDirection, | ||
); | ||
|
||
cornerPoints.add(Offset(x, y)); | ||
} | ||
// Add the first point to close the polygon | ||
cornerPoints.add(cornerPoints.first); | ||
canvas.drawPoints(PointMode.polygon, cornerPoints, paint2); | ||
} | ||
|
||
for (final triangle in mesh.triangles) { | ||
paintTriangle(triangle); | ||
} | ||
} | ||
} | ||
|
||
@override | ||
bool shouldRepaint(FaceMeshDetectorPainter oldDelegate) { | ||
return oldDelegate.imageSize != imageSize || oldDelegate.meshes != meshes; | ||
} | ||
} |
Oops, something went wrong.