Skip to content

Commit

Permalink
Face SDK v3.24.2
Browse files Browse the repository at this point in the history
  • Loading branch information
nk2033 committed Dec 20, 2024
1 parent 15e57d2 commit c301c68
Show file tree
Hide file tree
Showing 14 changed files with 139 additions and 151 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
android:id="@+id/aboutText1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Video recognition with depth and IR liveness demo for Telpo (v 0.2)\n\nFace SDK version 3.24.1\n"
android:text="Video recognition with depth and IR liveness demo for Telpo (v 0.2)\n\nFace SDK version 3.24.2\n"
android:layout_below="@+id/aboutLogo"
/>

Expand Down
2 changes: 1 addition & 1 deletion examples/flutter/demo/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ plugins {
android {
namespace = "com.example.face_sdk_3divi_demo"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
ndkVersion = "27.0.12077973"

compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
Expand Down
2 changes: 1 addition & 1 deletion examples/flutter/demo/android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pluginManagement {

plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.1.0" apply false
id "com.android.application" version "8.7.2" apply false
id "org.jetbrains.kotlin.android" version "2.0.20" apply false
}

Expand Down
3 changes: 1 addition & 2 deletions examples/flutter/demo/lib/photo.dart
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,9 @@ class _DetectPictureState extends State<DetectPicture> {
"widget": {"w": widthPreviewImage, "h": heightPreviewImage},
"picture": {"w": img.width, "h": img.height}
});
_cropImg = await cutFaceFromImageBytes(img_bytes, rect);
if (rss.length == 1) {
templs.add(widget._recognizer.processing(rss[i]));
widget.callback(templs[0], _cropImg);
widget.callback(templs[0], Image.memory(rss[i].cutFaceImage(ImageFormatCode.IMAGE_FORMAT_PNG, FaceCutType.FACE_CUT_BASE)));
controller.dispose();
}
rss[i].dispose();
Expand Down
119 changes: 68 additions & 51 deletions examples/flutter/demo/lib/video.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import 'dart:ui';
import 'dart:ffi';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'dart:async';
import 'dart:io' show Platform;
import 'package:flutter/cupertino.dart';
Expand All @@ -7,6 +9,7 @@ import 'package:camera/camera.dart';
import 'package:percent_indicator/linear_percent_indicator.dart';
import 'package:face_sdk_3divi/face_sdk_3divi.dart';
import 'package:face_sdk_3divi/utils.dart';
import 'package:image/image.dart' as image_lib;

typedef void setLivenssStatus(bool isPassed, Template templ, Image? img, double mirror);

Expand All @@ -25,19 +28,16 @@ class VideoProcessing extends StatefulWidget {

class _VideoProcessingState extends State<VideoProcessing> {
late CameraController controller;
NativeDataStruct _data = NativeDataStruct();
RawImageF? _ri;

late VideoWorker _videoWorker;
Offset? widgetPosition;
Size? widgetSize;
ui.Size? widgetSize;
GlobalKey _pictureKey = GlobalKey();
int _lastImgTimestamp = 0;
CameraImage? _lastImg;
CameraImage? bestImage;
int livenessProgress = 0;
String activeLivenessAction = " ";
List<dynamic> _recognitions = [];
Template? templ;
bool _isLivenessSet = false;
int baseAngle = 0;
Expand All @@ -48,6 +48,11 @@ class _VideoProcessingState extends State<VideoProcessing> {
double best_quality = -100000000;
bool livenessPassed = false;
bool livenessFailed = false;
RawSample? bestSample;
Uint8List? bestImage;
int trackId = -1;
late Stream<void> streamAddVW;
late Stream<void> streamPoolVW;

void _processStream(CameraImage img) async {
if (!mounted) return;
Expand All @@ -69,10 +74,7 @@ class _VideoProcessingState extends State<VideoProcessing> {
print("No camera is found");
} else {
final camera = widget.cameras[1];
controller = CameraController(
camera,
ResolutionPreset.high,
);
controller = CameraController(camera, ResolutionPreset.high, enableAudio: false);
controller.initialize().then((_) {
if (!mounted) {
return;
Expand Down Expand Up @@ -105,58 +107,63 @@ class _VideoProcessingState extends State<VideoProcessing> {
.recognizer_ini_file("method12v30_recognizer.xml")
.video_worker_config(Config("video_worker_fdatracker_blf_fda_front.xml")
.overrideParameter("enable_active_liveness", 1)
.overrideParameter("base_angle", baseAngle.toDouble())
.overrideParameter("active_liveness.apply_horizontal_flip", apply_horizontal_flip))
.streams_count(1)
.processing_threads_count(0)
.matching_threads_count(0)
.emotions_estimation_threads_count(1)
.active_liveness_checks_order(checks));

Duration interval = Duration(milliseconds: 50);
streamAddVW = Stream<void>.periodic(interval, addVF);
streamPoolVW = Stream<void>.periodic(interval, pool);
}

Stream<List<dynamic>> addVF(int prev_time) async* {
final time = _lastImgTimestamp;
var img = _lastImg;
if (!mounted || img == null) {
await Future.delayed(const Duration(milliseconds: 50));
yield* addVF(time);
void addVF(int value)
{
if (!mounted) {
return;
}
img = img!;
if (prev_time != _lastImgTimestamp) {
_ri = widget._facerecService.createRawImageFromCameraImage(img, 0, reusableData: _data);

var img = _lastImg;
final time = _lastImgTimestamp;

if (img != null) {

_ri = widget._facerecService.createRawImageFromCameraImage(img, baseAngle);

_videoWorker.addVideoFrame(_ri!, time);
}

await Future.delayed(const Duration(milliseconds: 50));
yield* addVF(time);
_ri?.dispose();
}
}

Stream<String> pool() async* {
void pool(int value) {
if (!mounted) {
await Future.delayed(const Duration(milliseconds: 50));
yield* pool();
return;
}
final callbackData = _videoWorker.poolTrackResults();
final rawSamples = callbackData.tracking_callback_data.samples;
List<dynamic> detections = [];
bool updated = false;

var angles;
if (callbackData.tracking_callback_data.samples.length > 0) {
for (var i = 0; i < rawSamples.length; i += 1) {
for (var i = 0; i < rawSamples.length; i++) {
rect = rawSamples[i].getRectangle();
angles = rawSamples[i].getAngles();
detections.add({
"rect": {"x": rect.x, "y": rect.y, "w": rect.width, "h": rect.height},
"widget": {"w": widgetSize!.height, "h": widgetSize!.width},
"picture": {"w": _ri!.width, "h": _ri!.height},
"offset": {"x": widgetPosition!.dx, "y": widgetPosition!.dy}
});
}

if (best_quality < callbackData.tracking_callback_data.samples_quality[0]) {
if (best_quality < callbackData.tracking_callback_data.samples_quality[0] ||
trackId != rawSamples.first.getID()) {
best_quality = callbackData.tracking_callback_data.samples_quality[0];
bestImage = _lastImg;
bestRect = rect;
trackId = rawSamples.first.getID();
bestImage = rawSamples.first.cutFaceImage(ImageFormatCode.IMAGE_FORMAT_PNG, FaceCutType.FACE_CUT_BASE);

bestSample?.dispose();

bestSample = rawSamples.first;

updated = true;
}
}
int progress = livenessProgress;
Expand Down Expand Up @@ -211,22 +218,33 @@ class _VideoProcessingState extends State<VideoProcessing> {
templ = widget._recognizer.processing(callbackData.tracking_lost_callback_data.best_quality_sample!);
}

rawSamples.forEach((element) => element.dispose());
if (updated) {
for (int i = 1; i < rawSamples.length; i++) {
rawSamples[i].dispose();
}
} else {
rawSamples.forEach((element) => element.dispose());
}

setState(() {
_recognitions = detections;
livenessProgress = progress;

if (templ != null && !_isLivenessSet) {
if (livenessPassed) widget.callback(true, templ!, cutFaceFromCameraImage(bestImage!, bestRect), mirror);
if (livenessFailed) widget.callback(false, templ!, cutFaceFromCameraImage(bestImage!, bestRect), mirror);

if (livenessFailed || livenessPassed) _isLivenessSet = true;
if (!_isLivenessSet && (livenessFailed || livenessPassed)) {
templ = widget._recognizer.processing(bestSample!);

if (livenessPassed) {
widget.callback(true, templ!, Image.memory(bestImage!), mirror);
}

if (livenessFailed) {
widget.callback(false, templ!, Image.memory(bestImage!), mirror);
}

_isLivenessSet = true;

bestSample!.dispose();
}
});

yield activeLivenessAction;
await Future.delayed(const Duration(milliseconds: 50));
yield* pool();
}

Widget bboxDrawer() {
Expand All @@ -249,15 +267,14 @@ class _VideoProcessingState extends State<VideoProcessing> {
padding: const EdgeInsets.all(1.0)),
),
StreamBuilder(
stream: pool(),
stream: streamPoolVW,
builder: (context, snapshot) {
return Transform.translate(
offset: Offset(0, 100),
child:
Text(activeLivenessAction, style: TextStyle(fontSize: 20, backgroundColor: Colors.black)));
child: Text(activeLivenessAction, style: TextStyle(fontSize: 20, backgroundColor: Colors.black)));
}),
StreamBuilder(
stream: addVF(0),
stream: streamAddVW,
builder: (context, snapshot) {
return Text("");
},
Expand Down
2 changes: 1 addition & 1 deletion examples/flutter/isolates_demo/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ plugins {
android {
namespace = "com.example.face_sdk_3divi_isolates_demo"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
ndkVersion = "27.0.12077973"

compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
Expand Down
2 changes: 1 addition & 1 deletion examples/flutter/isolates_demo/android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pluginManagement {

plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.1.0" apply false
id "com.android.application" version "8.7.2" apply false
id "org.jetbrains.kotlin.android" version "2.0.20" apply false
}

Expand Down
43 changes: 12 additions & 31 deletions examples/flutter/isolates_demo/lib/video.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ class _VideoProcessingState extends State<VideoProcessing> {
Offset? widgetPosition;
ui.Size? widgetSize;
NativeDataStruct data = NativeDataStruct();
NativeDataStruct reusableData = NativeDataStruct();
List<RawImageF> _targets = [];
Widget? bboxWidget;
Image? bboxImage;
bool flipX = true;
Expand Down Expand Up @@ -83,9 +81,9 @@ class _VideoProcessingState extends State<VideoProcessing> {
break;
}

Uint8List? bytes = await addVideoFrame(image);
RawImageF? frame = await addVideoFrame(image);

if (bytes == null) {
if (frame == null) {
bboxWidget = null;

isReady = true;
Expand All @@ -111,7 +109,7 @@ class _VideoProcessingState extends State<VideoProcessing> {
});
}

processFrame(width, height, bytes, sample);
await processFrame(width, height, frame, sample);
}

@override
Expand All @@ -122,7 +120,7 @@ class _VideoProcessingState extends State<VideoProcessing> {
} else {
final CameraDescription camera = widget.cameras[1];

controller = CameraController(camera, ResolutionPreset.high);
controller = CameraController(camera, ResolutionPreset.high, enableAudio: false);
controller.initialize().then((_) {
if (!mounted) {
return;
Expand Down Expand Up @@ -152,34 +150,20 @@ class _VideoProcessingState extends State<VideoProcessing> {
});
}

Future<Uint8List?> addVideoFrame(CameraImage cameraImage) async {
Future<RawImageF?> addVideoFrame(CameraImage cameraImage) async {
if (!mounted) {
await Future.delayed(const Duration(milliseconds: 10));

return null;
}

if (!data.isValid) {
reusableData.resize(cameraImage.width * cameraImage.height * 3);
}

RawImageF target = widget._service.createRawImageFromCameraImage(cameraImage, baseAngle);

if (_targets.length > 300) {
for (int i = 0; i < 150; i++) {
_targets[i].dispose();
}

_targets.removeRange(0, 150);
}

await _videoWorker!.addVideoFrame(target, DateTime.now().microsecondsSinceEpoch);

await Future.delayed(const Duration(milliseconds: 10));

_targets.add(target);

return target.data.cast<Uint8>().asTypedList(cameraImage.width * cameraImage.height * 3);
return target;
}

Future<RawSample?> pool() async {
Expand All @@ -199,7 +183,9 @@ class _VideoProcessingState extends State<VideoProcessing> {
return rawSamples.first;
}

Future<void> processFrame(int width, int height, Uint8List bytes, RawSample sample) async {
Future<void> processFrame(int width, int height, RawImageF? frame, RawSample sample) async {
final bytes = frame?.data.cast<Uint8>().asTypedList(width * height * 3);

if (!isProcessFrameReady) {
sample.dispose();

Expand Down Expand Up @@ -255,7 +241,7 @@ class _VideoProcessingState extends State<VideoProcessing> {
Context template = widget._service.createContext(data["objects"][0]["template"]);
Rectangle bbox = sample.getRectangle();
final image_lib.Image image = image_lib.Image.fromBytes(
width: width, height: height, bytes: bytes.buffer, numChannels: 3, order: image_lib.ChannelOrder.rgb);
width: width, height: height, bytes: bytes!.buffer, numChannels: 3, order: image_lib.ChannelOrder.rgb);

List<int> png =
pngEncoder.encode(image_lib.copyCrop(image, x: bbox.x, y: bbox.y, width: bbox.width, height: bbox.height));
Expand All @@ -265,6 +251,7 @@ class _VideoProcessingState extends State<VideoProcessing> {

data.dispose();
sample.dispose();
frame?.dispose();

isProcessFrameReady = true;
}
Expand Down Expand Up @@ -362,13 +349,7 @@ class _VideoProcessingState extends State<VideoProcessing> {
@override
void dispose() {
controller.dispose();
_videoWorker?.dispose().whenComplete(() {
for (RawImageF target in _targets) {
target.dispose();
}

_targets.clear();
});
_videoWorker?.dispose();
liveness?.dispose();

super.dispose();
Expand Down
Loading

0 comments on commit c301c68

Please sign in to comment.