Skip to content

Commit a8b4da8

Browse files
authored
feat: Subject Segmentation (#666)
1 parent 004cb41 commit a8b4da8

File tree

45 files changed

+803
-22
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+803
-22
lines changed

.github/workflows/code-analysis.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ jobs:
9191
working-directory: ./packages/google_mlkit_selfie_segmentation
9292
run: flutter pub get
9393

94+
- name: Install dependencies for google_mlkit_subject_segmentation
95+
working-directory: ./packages/google_mlkit_subject_segmentation
96+
run: flutter pub get
97+
9498
- name: Install dependencies for example
9599
working-directory: ./packages/example
96100
run: flutter pub get

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Google's ML Kit for Flutter is a set of [Flutter plugins](https://flutter.io/pla
1717
| [Digital Ink Recognition](https://developers.google.com/ml-kit/vision/digital-ink-recognition) | [google\_mlkit\_digital\_ink\_recognition](https://pub.dev/packages/google_mlkit_digital_ink_recognition) [![Pub Version](https://img.shields.io/pub/v/google_mlkit_digital_ink_recognition)](https://pub.dev/packages/google_mlkit_digital_ink_recognition) | [![GitHub](https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge&logo=github&logoColor=white)](https://github.com/flutter-ml/google_ml_kit_flutter/tree/master/packages/google_mlkit_digital_ink_recognition) |||
1818
| [Pose Detection](https://developers.google.com/ml-kit/vision/pose-detection) | [google\_mlkit\_pose\_detection](https://pub.dev/packages/google_mlkit_pose_detection) [![Pub Version](https://img.shields.io/pub/v/google_mlkit_pose_detection)](https://pub.dev/packages/google_mlkit_pose_detection) | [![GitHub](https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge&logo=github&logoColor=white)](https://github.com/flutter-ml/google_ml_kit_flutter/tree/master/packages/google_mlkit_pose_detection) |||
1919
| [Selfie Segmentation](https://developers.google.com/ml-kit/vision/selfie-segmentation) | [google\_mlkit\_selfie\_segmentation](https://pub.dev/packages/google_mlkit_selfie_segmentation) [![Pub Version](https://img.shields.io/pub/v/google_mlkit_selfie_segmentation)](https://pub.dev/packages/google_mlkit_selfie_segmentation) | [![GitHub](https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge&logo=github&logoColor=white)](https://github.com/flutter-ml/google_ml_kit_flutter/tree/master/packages/google_mlkit_selfie_segmentation) |||
20-
| [Subject Segmentation](https://developers.google.com/ml-kit/vision/subject-segmentation) | [google\_mlkit\_subject\_segemtation](https://pub.dev/packages/google_mlkit_subject_segemtation) [![Pub Version](https://img.shields.io/pub/v/google_mlkit_subject_segemtation)](https://pub.dev/packages/google_mlkit_subject_segemtation) | [![GitHub](https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge&logo=github&logoColor=white)](https://github.com/flutter-ml/google_ml_kit_flutter/tree/master/packages/google_mlkit_subject_segemtation) | ||
20+
| [Subject Segmentation](https://developers.google.com/ml-kit/vision/subject-segmentation) | [google\_mlkit\_subject\_segemtation](https://pub.dev/packages/google_mlkit_subject_segemtation) [![Pub Version](https://img.shields.io/pub/v/google_mlkit_subject_segemtation)](https://pub.dev/packages/google_mlkit_subject_segemtation) | [![GitHub](https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge&logo=github&logoColor=white)](https://github.com/flutter-ml/google_ml_kit_flutter/tree/master/packages/google_mlkit_subject_segemtation) | ||
2121
| [Document Scanner](https://developers.google.com/ml-kit/vision/doc-scanner) | [google\_mlkit\_document\_scanner](https://pub.dev/packages/google_mlkit_document_scanner) [![Pub Version](https://img.shields.io/pub/v/google_mlkit_document_scanner)](https://pub.dev/packages/google_mlkit_document_scanner) | [![GitHub](https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge&logo=github&logoColor=white)](https://github.com/flutter-ml/google_ml_kit_flutter/tree/master/packages/google_mlkit_document_scanner) |||
2222

2323
### Natural Language APIs

packages/example/android/app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ android {
4242

4343
defaultConfig {
4444
applicationId "com.google.ml.kit.flutter.example"
45-
minSdkVersion 21
45+
minSdkVersion 24
4646
targetSdkVersion 34
4747
versionCode flutterVersionCode.toInteger()
4848
versionName flutterVersionName

packages/example/android/app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
</activity>
3131
<meta-data
3232
android:name="com.google.mlkit.vision.DEPENDENCIES"
33-
android:value="ica,ocr,face" />
33+
android:value="ica,ocr,face,subject_segment" />
3434
<!-- Don't delete the meta-data below.
3535
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
3636
<meta-data
658 KB
Loading
1.01 MB
Loading

packages/example/lib/main.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import 'dart:io';
22

33
import 'package:flutter/material.dart';
4-
54
import 'nlp_detector_views/entity_extraction_view.dart';
65
import 'nlp_detector_views/language_identifier_view.dart';
76
import 'nlp_detector_views/language_translator_view.dart';
@@ -15,6 +14,7 @@ import 'vision_detector_views/label_detector_view.dart';
1514
import 'vision_detector_views/object_detector_view.dart';
1615
import 'vision_detector_views/pose_detector_view.dart';
1716
import 'vision_detector_views/selfie_segmenter_view.dart';
17+
import 'vision_detector_views/subject_segmenter_view.dart';
1818
import 'vision_detector_views/text_detector_view.dart';
1919

2020
Future<void> main() async {
@@ -54,7 +54,9 @@ class Home extends StatelessWidget {
5454
children: [
5555
CustomCard('Barcode Scanning', BarcodeScannerView()),
5656
CustomCard('Face Detection', FaceDetectorView()),
57-
CustomCard('Face Mesh Detection', FaceMeshDetectorView()),
57+
if (Platform.isAndroid)
58+
CustomCard(
59+
'Face Mesh Detection', FaceMeshDetectorView()),
5860
CustomCard('Image Labeling', ImageLabelView()),
5961
CustomCard('Object Detection', ObjectDetectorView()),
6062
CustomCard('Text Recognition', TextRecognizerView()),
@@ -63,6 +65,9 @@ class Home extends StatelessWidget {
6365
CustomCard('Selfie Segmentation', SelfieSegmenterView()),
6466
if (Platform.isAndroid)
6567
CustomCard('Document Scanner', DocumentScannerView()),
68+
if (Platform.isAndroid)
69+
CustomCard(
70+
'Subject Segmentation', SubjectSegmenterView())
6671
],
6772
),
6873
SizedBox(
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import 'package:camera/camera.dart';
2+
import 'package:flutter/material.dart';
3+
import 'package:google_mlkit_subject_segmentation/google_mlkit_subject_segmentation.dart';
4+
import 'coordinates_translator.dart';
5+
6+
class SubjectSegmentationPainter extends CustomPainter {
7+
final SubjectSegmenterMask mask;
8+
final Size imageSize;
9+
final Color color = Colors.red;
10+
final InputImageRotation rotation;
11+
final CameraLensDirection cameraLensDirection;
12+
13+
SubjectSegmentationPainter(
14+
this.mask,
15+
this.imageSize,
16+
this.rotation,
17+
this.cameraLensDirection,
18+
);
19+
20+
@override
21+
void paint(Canvas canvas, Size size) {
22+
final int width = mask.width;
23+
final int height = mask.height;
24+
final List<Subject> subjects = mask.subjects;
25+
26+
final paint = Paint()..style = PaintingStyle.fill;
27+
28+
for (final Subject subject in subjects) {
29+
final int startX = subject.startX;
30+
final int startY = subject.startY;
31+
final int subjectWidth = subject.subjectWidth;
32+
final int subjectHeight = subject.subjectHeight;
33+
final List<double> confidences = subject.confidences;
34+
35+
for (int y = 0; y < subjectHeight; y++) {
36+
for (int x = 0; y < subjectWidth; x++) {
37+
final int absoluteX = startX;
38+
final int absoluteY = startY;
39+
40+
final int tx = translateX(
41+
absoluteX.toDouble(),
42+
size,
43+
Size(width.toDouble(), height.toDouble()),
44+
rotation,
45+
cameraLensDirection)
46+
.round();
47+
48+
final int ty = translateY(
49+
absoluteY.toDouble(),
50+
size,
51+
Size(width.toDouble(), height.toDouble()),
52+
rotation,
53+
cameraLensDirection)
54+
.round();
55+
56+
final double opacity = confidences[(y * subjectWidth) + x] * 0.5;
57+
paint.color = color.withOpacity(opacity);
58+
canvas.drawCircle(Offset(tx.toDouble(), ty.toDouble()), 2, paint);
59+
}
60+
}
61+
}
62+
}
63+
64+
@override
65+
bool shouldRepaint(SubjectSegmentationPainter oldDelegate) {
66+
return oldDelegate.mask != mask;
67+
}
68+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import 'package:camera/camera.dart';
2+
import 'package:flutter/material.dart';
3+
import 'package:google_mlkit_subject_segmentation/google_mlkit_subject_segmentation.dart';
4+
5+
import 'detector_view.dart';
6+
import 'painters/subject_segmentation_painter.dart';
7+
8+
class SubjectSegmenterView extends StatefulWidget {
9+
@override
10+
State<SubjectSegmenterView> createState() => _SubjectSegmenterViewState();
11+
}
12+
13+
class _SubjectSegmenterViewState extends State<SubjectSegmenterView> {
14+
final SubjectSegmenter _segmenter = SubjectSegmenter();
15+
bool _canProcess = true;
16+
bool _isBusy = false;
17+
CustomPaint? _customPaint;
18+
String? _text;
19+
var _cameraLensDirection = CameraLensDirection.back;
20+
21+
@override
22+
void dispose() async {
23+
_canProcess = false;
24+
_segmenter.close();
25+
super.dispose();
26+
}
27+
28+
@override
29+
Widget build(BuildContext context) {
30+
return DetectorView(
31+
title: 'Subject Segmenter',
32+
customPaint: _customPaint,
33+
text: _text,
34+
onImage: _processImage,
35+
initialCameraLensDirection: _cameraLensDirection,
36+
onCameraLensDirectionChanged: (value) => _cameraLensDirection = value,
37+
);
38+
}
39+
40+
Future<void> _processImage(InputImage inputImage) async {
41+
if (!_canProcess) return;
42+
if (_isBusy) return;
43+
_isBusy = true;
44+
setState(() {
45+
_text = '';
46+
});
47+
final SubjectSegmenterMask mask = await _segmenter.processImage(inputImage);
48+
if (inputImage.metadata?.size != null &&
49+
inputImage.metadata?.rotation != null) {
50+
final painter = SubjectSegmentationPainter(
51+
mask,
52+
inputImage.metadata!.size,
53+
inputImage.metadata!.rotation,
54+
_cameraLensDirection,
55+
);
56+
_customPaint = CustomPaint(painter: painter);
57+
} else {
58+
// TODO: set _customPaint to draw on top of image
59+
_text = 'There is a mask with ${mask.subjects.length} subjects';
60+
61+
_customPaint = null;
62+
}
63+
_isBusy = false;
64+
if (mounted) {
65+
setState(() {});
66+
}
67+
}
68+
}

packages/example/pubspec.lock

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,13 @@ packages:
267267
relative: true
268268
source: path
269269
version: "0.11.0"
270+
google_mlkit_subject_segmentation:
271+
dependency: "direct main"
272+
description:
273+
path: "../google_mlkit_subject_segmentation"
274+
relative: true
275+
source: path
276+
version: "0.0.1"
270277
google_mlkit_text_recognition:
271278
dependency: "direct main"
272279
description:

0 commit comments

Comments
 (0)