Skip to content

Instantly share code, notes, and snippets.

@welchi
Created December 16, 2020 13:10
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 welchi/bf23f2e0bbf4c2db4793e6bfd2fdac3e to your computer and use it in GitHub Desktop.
Save welchi/bf23f2e0bbf4c2db4793e6bfd2fdac3e to your computer and use it in GitHub Desktop.
import 'dart:io';
import 'package:camera/camera.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_object_detection_example/data/entity/recognition.dart';
import 'package:flutter_object_detection_example/data/model/classifier.dart';
import 'package:flutter_object_detection_example/util/image_utils.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:image/image.dart' as image_lib;
import 'package:tflite_flutter/tflite_flutter.dart';
final mlCameraProvider =
FutureProvider.autoDispose.family<MLCamera, Size>((ref, size) async {
final cameras = await availableCameras();
final cameraController = CameraController(
cameras[0],
ResolutionPreset.low,
enableAudio: false,
);
await cameraController.initialize();
final mlCamera = MLCamera(
ref.read,
cameraController,
size,
);
return mlCamera;
});
class MLCamera {
MLCamera(
this._read,
this.cameraController,
this.cameraViewSize,
) {
Future(() async {
classifier = Classifier();
ratio = Platform.isAndroid
? cameraViewSize.width / cameraController.value.previewSize.height
: cameraViewSize.width / cameraController.value.previewSize.width;
actualPreviewSize = Size(
cameraViewSize.width,
cameraViewSize.width * ratio,
);
await cameraController.startImageStream(onLatestImageAvailable);
});
}
final Reader _read;
final CameraController cameraController;
/// スクリーンのサイズ
Size cameraViewSize;
/// アスペクト比
double ratio;
/// 識別器
Classifier classifier;
/// 現在推論中か否か
bool isPredicting = false;
/// カメラプレビューの表示サイズ
Size actualPreviewSize;
/// 画像ストリーミングに対する処理
Future<void> onLatestImageAvailable(CameraImage cameraImage) async {
if (classifier.interpreter == null || classifier.labels == null) {
return;
}
if (isPredicting) {
return;
}
isPredicting = true;
final isolateCamImgData = IsolateData(
cameraImage: cameraImage,
interpreterAddress: classifier.interpreter.address,
labels: classifier.labels,
);
// 推論処理は重く、Isolateを使わないと画面が固まる
_read(recognitionsProvider).state =
await compute(inference, isolateCamImgData);
isPredicting = false;
}
/// Isolateへ渡す推論関数
/// Isolateには、static関数か、クラスに属さないトップレベル関数しか渡せないため、staticに
static Future<List<Recognition>> inference(
IsolateData isolateCamImgData) async {
var image = ImageUtils.convertYUV420ToImage(
isolateCamImgData.cameraImage,
);
if (Platform.isAndroid) {
image = image_lib.copyRotate(image, 90);
}
final classifier = Classifier(
interpreter: Interpreter.fromAddress(
isolateCamImgData.interpreterAddress,
),
labels: isolateCamImgData.labels,
);
return classifier.predict(image);
}
}
class IsolateData {
IsolateData({
this.cameraImage,
this.interpreterAddress,
this.labels,
});
final CameraImage cameraImage;
final int interpreterAddress;
final List<String> labels;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment