Skip to content
This repository was archived by the owner on Apr 4, 2023. It is now read-only.

Commit a3a3006

Browse files
#699 Add ML Kit support (ML Kit demo++, iOS rotation issues fixed, lower memory footprint)
1 parent 35c646d commit a3a3006

File tree

16 files changed

+116
-76
lines changed

16 files changed

+116
-76
lines changed

demo-ng/app/tabs/mlkit/barcodescanning/barcodescanning.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44

55
<GridLayout rows="auto, auto, *">
66

7-
<Label row="0" text="The scanner has been configured to detect QR codes, EAN 8 and EAN 13. It processes every 10th frame. These settings can be tweaked in your usage of the plugin." textWrap="true"></Label>
7+
<Label row="0" text="The scanner has been configured to detect QR codes, EAN 8 and EAN 13. It processes every 5th frame (default 10). These settings can be tweaked in your usage of the plugin." textWrap="true"></Label>
88

99
<MLKitBarcodeScanner
1010
row="1"
1111
width="300"
1212
height="340"
1313
formats="QR_CODE, EAN_8, EAN_13"
14-
processEveryNthFrame="10"
14+
processEveryNthFrame="5"
1515
(scanResult)="onBarcodeScanResult($event)">
1616
</MLKitBarcodeScanner>
1717

demo-ng/app/tabs/mlkit/facedetection/facedetection.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44

55
<GridLayout rows="auto, auto, auto, auto, *">
66

7-
<Label row="0" text="The scanner has been configured to detect faces every 5th frame. You can tweak this in your usage of the plugin." textWrap="true"></Label>
7+
<Label row="0" text="The scanner has been configured to detect faces every 30th frame (default is 10). You can tweak this in your usage of the plugin." textWrap="true"></Label>
88

99
<MLKitFaceDetection
1010
row="1"
1111
width="300"
1212
height="340"
13-
processEveryNthFrame="5"
13+
processEveryNthFrame="30"
1414
(scanResult)="onFaceDetectionResult($event)">
1515
</MLKitFaceDetection>
1616

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
<StackLayout class="tab-content">
1+
<GridLayout rows="auto, auto, *" class="tab-content">
22

3-
<Label text="Pick the image processing source:" textWrap="true"></Label>
3+
<Label row="0" text="Pick the image processing source:" textWrap="true"></Label>
44

5-
<StackLayout orientation="horizontal" horizontalAlignment="center">
6-
<Button text="Cameraroll" (tap)="fromCameraroll()" class="button button-mlkit"></Button>
7-
<Button text="Cam picture" (tap)="fromCameraPicture()" class="button button-mlkit"></Button>
8-
<Button text="Cam feed" (tap)="fromCameraFeed()" class="button button-mlkit"></Button>
5+
<StackLayout row="1" orientation="horizontal" horizontalAlignment="center">
6+
<Button text="Cameraroll" (tap)="fromCameraroll()" class="button"></Button>
7+
<Button text="Cam picture" (tap)="fromCameraPicture()" class="button"></Button>
8+
<Button text="Cam feed" (tap)="fromCameraFeed()" class="button"></Button>
99
</StackLayout>
1010

11-
</StackLayout>
11+
<Image row="2" [src]="pickedImage" width="240" horizontalAlignment="center"></Image>
12+
</GridLayout>

demo-ng/app/tabs/mlkit/mlkit.component.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component } from "@angular/core";
1+
import { Component, NgZone } from "@angular/core";
22
import { ImageSource } from "tns-core-modules/image-source";
33

44
import { BarcodeFormat, MLKitScanBarcodesResult } from "nativescript-plugin-firebase/mlkit/barcodescanning";
@@ -22,6 +22,8 @@ const firebase = require("nativescript-plugin-firebase");
2222
})
2323
export class MLKitComponent {
2424

25+
pickedImage: ImageSource;
26+
2527
private mlkitFeatures: Array<string> = [
2628
"Text recognition",
2729
"Barcode scanning",
@@ -30,7 +32,8 @@ export class MLKitComponent {
3032
"Landmark recognition (cloud)"
3133
];
3234

33-
constructor(private routerExtensions: RouterExtensions) {
35+
constructor(private routerExtensions: RouterExtensions,
36+
private zone: NgZone) {
3437
}
3538

3639
fromCameraFeed(): void {
@@ -78,11 +81,13 @@ export class MLKitComponent {
7881
width: 800,
7982
height: 800,
8083
keepAspectRatio: true,
81-
saveToGallery: false,
84+
saveToGallery: true,
8285
cameraFacing: "rear"
8386
}).then(imageAsset => {
8487
new ImageSource().fromAsset(imageAsset).then(imageSource => {
85-
this.selectMLKitFeature(imageSource);
88+
this.pickedImage = imageSource;
89+
// give the user some to to see the picture
90+
setTimeout(() => this.selectMLKitFeature(imageSource), 500);
8691
});
8792
});
8893
}
@@ -96,24 +101,28 @@ export class MLKitComponent {
96101
.authorize()
97102
.then(() => imagePicker.present())
98103
.then((selection: Array<ImageAsset>) => {
99-
console.log(">>> selection: " + selection);
100104
if (selection.length === 0) return;
101105

102106
const selected = selection[0];
103-
console.log(">>> selected: " + selected);
104107
selected.options.height = 800;
105108
selected.options.width = 800;
106109
selected.options.keepAspectRatio = true;
107110
selected.getImageAsync((image: any, error: any) => {
108-
console.log(">>> error: " + error);
109-
console.log(">>> image: " + image);
110111
if (error) {
111-
console.log(`Error getting image source from pickerI: ${error}`);
112+
console.log(`Error getting image source from picker: ${error}`);
113+
return;
114+
}
115+
if (!image) {
116+
console.log(`This is probably an iCloud image - which won't work`);
112117
return;
113118
}
114119
const imageSource = new ImageSource();
115120
imageSource.setNativeSource(image);
116-
this.selectMLKitFeature(imageSource);
121+
this.zone.run(() => {
122+
this.pickedImage = imageSource;
123+
});
124+
// give the user some to to see the picture
125+
setTimeout(() => this.selectMLKitFeature(imageSource), 500);
117126
});
118127
})
119128
.catch(e => {

docs/ML_KIT.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@ Just dumping a few things I should not forget to add to the doc:
22

33
- see step 3 @ https://firebase.google.com/docs/ml-kit/android/recognize-text
44
- For Cloud processing, enable the Vision API and upgrade your Firebase project to "Blaze" (pay as you go)
5+
6+
Known issues:
7+
- Detecting faces from still images doesn't currently work on iOS (detection from the camera stream works though)

src/mlkit/barcodescanning/index.android.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ export class MLKitBarcodeScanner extends MLKitBarcodeScannerBase {
2525

2626
if (barcodes.size() === 0) return;
2727

28-
const imageSource = new ImageSource();
29-
imageSource.setNativeSource(this.lastVisionImage.getBitmapForDebugging());
28+
// const imageSource = new ImageSource();
29+
// imageSource.setNativeSource(this.lastVisionImage.getBitmapForDebugging());
3030

3131
const result = <MLKitScanBarcodesResult>{
32-
imageSource: imageSource,
32+
// imageSource: imageSource,
3333
barcodes: []
3434
};
3535

src/mlkit/facedetection/index.android.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ export class MLKitFaceDetection extends MLKitFaceDetectionBase {
1717

1818
if (faces.size() === 0) return;
1919

20-
const imageSource = new ImageSource();
21-
imageSource.setNativeSource(this.lastVisionImage.getBitmapForDebugging());
20+
// const imageSource = new ImageSource();
21+
// imageSource.setNativeSource(this.lastVisionImage.getBitmapForDebugging());
2222

2323
const result = <MLKitDetectFacesResult>{
24-
imageSource: imageSource,
24+
// imageSource: imageSource,
2525
faces: []
2626
};
2727

src/mlkit/facedetection/index.ios.ts

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import { MLKitOptions } from "../index";
44
import { MLKitFaceDetection as MLKitFaceDetectionBase } from "./facedetection-common";
55

66
export class MLKitFaceDetection extends MLKitFaceDetectionBase {
7+
78
protected createDetector(): any {
8-
const firVision: FIRVision = FIRVision.vision();
9-
return firVision.faceDetector();
9+
return getDetector();
1010
}
1111

1212
protected createSuccessListener(): any {
@@ -21,9 +21,9 @@ export class MLKitFaceDetection extends MLKitFaceDetectionBase {
2121

2222
for (let i = 0, l = faces.count; i < l; i++) {
2323
const face: FIRVisionFace = faces.objectAtIndex(i);
24+
console.log(">> face: " + face);
2425
result.faces.push({
25-
// smilingProbability: face.hasSmilingProbability ? face.smilingProbability : undefined,
26-
smilingProbability: face.smilingProbability,
26+
smilingProbability: face.hasSmilingProbability ? face.smilingProbability : undefined,
2727
leftEyeOpenProbability: face.hasLeftEyeOpenProbability ? face.leftEyeOpenProbability : undefined,
2828
rightEyeOpenProbability: face.hasRightEyeOpenProbability ? face.rightEyeOpenProbability : undefined
2929
});
@@ -39,18 +39,27 @@ export class MLKitFaceDetection extends MLKitFaceDetectionBase {
3939
};
4040
}
4141

42-
// TODO only seems to work in landscape
4342
protected rotateRecording(): boolean {
4443
return false;
4544
}
4645
}
4746

47+
function getDetector(): FIRVisionFaceDetector {
48+
// TODO make configurable
49+
const firVision: FIRVision = FIRVision.vision();
50+
const options = FIRVisionFaceDetectorOptions.new();
51+
options.modeType = FIRVisionFaceDetectorMode.Accurate;
52+
options.landmarkType = FIRVisionFaceDetectorLandmark.All;
53+
options.classificationType = FIRVisionFaceDetectorClassification.All;
54+
options.minFaceSize = 0.1;
55+
// options.isTrackingEnabled = true;
56+
return firVision.faceDetectorWithOptions(options);
57+
}
58+
4859
export function detectFaces(options: MLKitDetectFacesOptions): Promise<MLKitDetectFacesResult> {
4960
return new Promise((resolve, reject) => {
5061
try {
51-
const firVision: FIRVision = FIRVision.vision();
52-
const faceDetector: FIRVisionFaceDetector = firVision.faceDetector();
53-
62+
const faceDetector = getDetector();
5463
faceDetector.detectInImageCompletion(getImage(options), (faces: NSArray<FIRVisionFace>, error: NSError) => {
5564
if (error !== null) {
5665
reject(error.localizedDescription);
@@ -60,15 +69,16 @@ export function detectFaces(options: MLKitDetectFacesOptions): Promise<MLKitDete
6069
faces: []
6170
};
6271

72+
console.log(">>> faces.count: " + faces.count);
6373
for (let i = 0, l = faces.count; i < l; i++) {
6474
const face: FIRVisionFace = faces.objectAtIndex(i);
75+
console.log(">> face: " + face);
6576
result.faces.push({
6677
smilingProbability: face.hasSmilingProbability ? face.smilingProbability : undefined,
6778
leftEyeOpenProbability: face.hasLeftEyeOpenProbability ? face.leftEyeOpenProbability : undefined,
6879
rightEyeOpenProbability: face.hasRightEyeOpenProbability ? face.rightEyeOpenProbability : undefined
6980
});
7081
}
71-
console.log(">>> face result: " + JSON.stringify(result.faces));
7282
resolve(result);
7383
}
7484
});
@@ -79,8 +89,19 @@ export function detectFaces(options: MLKitDetectFacesOptions): Promise<MLKitDete
7989
});
8090
}
8191

82-
// TODO move
92+
// TODO resize the image (here), like the example app?
8393
function getImage(options: MLKitOptions): FIRVisionImage {
8494
const image: UIImage = options.image instanceof ImageSource ? options.image.ios : options.image.imageSource.ios;
85-
return FIRVisionImage.alloc().initWithImage(image);
95+
console.log(">> image.imageOrientation: " + image.imageOrientation);
96+
97+
const fIRVisionImageMetadata = FIRVisionImageMetadata.new();
98+
// fIRVisionImageMetadata.orientation = FIRVisionDetectorImageOrientation.TopLeft;
99+
100+
// const randomOrientation = Math.floor(Math.random() * 8) + 1;
101+
// console.log(">>> randomOrientation: " + randomOrientation);
102+
fIRVisionImageMetadata.orientation = 1;
103+
104+
const fIRVisionImage = FIRVisionImage.alloc().initWithImage(image);
105+
fIRVisionImage.metadata = fIRVisionImageMetadata;
106+
return fIRVisionImage;
86107
}

src/mlkit/imagelabeling/index.android.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ export class MLKitImageLabeling extends MLKitImageLabelingBase {
1717

1818
if (labels.size() === 0) return;
1919

20-
const imageSource = new ImageSource();
21-
imageSource.setNativeSource(this.lastVisionImage.getBitmapForDebugging());
20+
// const imageSource = new ImageSource();
21+
// imageSource.setNativeSource(this.lastVisionImage.getBitmapForDebugging());
2222

2323
const result = <MLKitImageLabelingResult>{
24-
imageSource: imageSource,
24+
// imageSource: imageSource,
2525
labels: []
2626
};
2727

src/mlkit/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export interface MLKitResult {
2020
* Only set when using a camera stream,
2121
* because when detecting from static images... you already have the image, right? :)
2222
*/
23-
imageSource?: ImageSource;
23+
// imageSource?: ImageSource;
2424
}
2525

2626
export declare class MLKitCameraView {

0 commit comments

Comments
 (0)