Skip to content

Instantly share code, notes, and snippets.

@RobertApikyan
Created August 6, 2021 13:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RobertApikyan/4907a191d97ab923394e238ea01886d1 to your computer and use it in GitHub Desktop.
Save RobertApikyan/4907a191d97ab923394e238ea01886d1 to your computer and use it in GitHub Desktop.
import 'dart:async';
import 'dart:convert';
import 'dart:isolate';
import 'dart:typed_data';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:qundo/ffi/smart_capture.dart';
import 'package:qundo/utilities/image_converter.dart';
class SmartCaptureProcessor {
SmartCaptureProcessor(
{this.min_matches = 25.0,
this.card_nfeatures = 5000,
this.alignment_quality = 0.2,
this.ro = 0.8,
this.smartCaptureCheckStep = 30,
this.smartCaptureCallback});
static const type_id_front = 'id_front';
static const type_id_back = 'id_back';
VoidCallback smartCaptureCallback;
Isolate isolateSmartCapture;
ReceivePort receivePortSmartCapture;
SendPort m_t_i_sendPortSmartCapture;
Isolate isolateConvert;
ReceivePort receivePortConvert;
SendPort m_t_i_sendPortConvert;
CameraImage _cameraImage;
Uint8List _imageBytes;
Uint8List get imageBytes => _imageBytes;
String _imageBase64;
// Configurations
ByteData maskTemplateImageBytes;
ByteData templateImageBytes;
double min_matches;
double card_nfeatures;
double alignment_quality;
double ro;
String type;
int smartCaptureCheckStep;
int captureStep = 0;
bool _initialized = false;
Future<void> initialize() async {
m_t_i_sendPortSmartCapture = await spawnSmartCaptureIsolate();
m_t_i_sendPortConvert = await spawnConvertIsolate();
_initialized = true;
}
Future<void> setCardData(String type, String maskTemplateImageBytes,
String templateImageBytes) async {
this.type = type;
this.maskTemplateImageBytes = await rootBundle.load(maskTemplateImageBytes);
this.templateImageBytes = await rootBundle.load(templateImageBytes);
}
void processCameraImage(CameraImage image) {
_cameraImage = image;
var isSmartCaptureStep = ++captureStep % smartCaptureCheckStep == 0;
if (isSmartCaptureStep) {
convertCameraImage();
}
}
Future<SendPort> spawnSmartCaptureIsolate() async {
isolateSmartCapture?.kill();
Completer<SendPort> completer = Completer();
receivePortSmartCapture = ReceivePort();
receivePortSmartCapture.listen((data) async {
if (data is SendPort) {
var mainToIsolateStream = data;
completer.complete(mainToIsolateStream);
} else {
debugPrint('_imageBytes ' + (_imageBytes?.toString() ?? 'empty'));
if (data['valid'] == "valid" &&
_imageBytes?.isNotEmpty == true &&
_initialized) {
smartCaptureCallback();
} else {
debugPrint('_imageBytes invalid');
}
}
});
await Isolate.spawn(smartCaptureIsolate, receivePortSmartCapture.sendPort);
return completer.future;
}
Future<SendPort> spawnConvertIsolate() async {
isolateConvert?.kill();
Completer<SendPort> completer = Completer();
receivePortConvert = ReceivePort();
receivePortConvert.listen((data) async {
if (data is SendPort) {
var mainToIsolateStream = data;
completer.complete(mainToIsolateStream);
} else if (data is Uint8List) {
_imageBytes = data;
_imageBase64 = base64Encode(data);
_processSmartCapture();
}
});
await Isolate.spawn(convertIsolate, receivePortConvert.sendPort);
return completer.future;
}
void _processSmartCapture() async {
m_t_i_sendPortSmartCapture.send({
'lastImageBase64': _imageBase64,
'templateImageBase64': base64Encode(
templateImageBytes.buffer.asUint8List(),
),
'maskTemplateImageBase64': base64Encode(
maskTemplateImageBytes.buffer.asUint8List(),
),
'type': type,
"min_matches": min_matches.toString(),
"card_nfeatures": card_nfeatures.toString(),
"alignment_quality": alignment_quality.toString(),
"ro": ro.toString()
});
}
void convertCameraImage() {
m_t_i_sendPortConvert.send({
'convert': _cameraImage,
});
// _imageBytes = null;
// _imageBase64 = null;
}
void dispose() {
isolateConvert?.kill();
isolateSmartCapture?.kill();
isolateConvert = null;
isolateSmartCapture = null;
receivePortConvert.close();
receivePortSmartCapture.close();
_imageBase64 = null;
_imageBytes = null;
_initialized = false;
}
static void convertIsolate(SendPort isolateToMainStream) {
var mainToIsolateStream = ReceivePort();
isolateToMainStream.send(mainToIsolateStream.sendPort);
mainToIsolateStream.listen((data) async {
dynamic result = await convertImagetoPng(data['convert'] as CameraImage);
isolateToMainStream.send(result);
});
}
static void smartCaptureIsolate(SendPort isolateToMainStream) {
var mainToIsolateStream = ReceivePort();
isolateToMainStream.send(mainToIsolateStream.sendPort);
mainToIsolateStream.listen((data) async {
dynamic result = await SmartCapture.detect(
data['lastImageBase64'] as String,
data['templateImageBase64'] as String,
data['maskTemplateImageBase64'] as String,
data['type'] as String,
data['min_matches'] as String,
data['card_nfeatures'] as String,
data['alignment_quality'] as String,
data['ro'] as String,
);
isolateToMainStream.send(result);
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment