Created
August 6, 2021 13:28
-
-
Save RobertApikyan/4907a191d97ab923394e238ea01886d1 to your computer and use it in GitHub Desktop.
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
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