Created
December 16, 2020 13:14
-
-
Save welchi/4606515d6c87cdb4fa114bb8a7363f0a 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 'package:camera/camera.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter_hooks/flutter_hooks.dart'; | |
import 'package:flutter_object_detection_example/data/entity/recognition.dart'; | |
import 'package:flutter_object_detection_example/data/model/ml_camera.dart'; | |
import 'package:hooks_riverpod/hooks_riverpod.dart'; | |
class ObjectDetectionPage extends HookWidget { | |
static String routeName = '/object_detection'; | |
@override | |
Widget build(BuildContext context) { | |
final size = MediaQuery.of(context).size; | |
final mlCamera = useProvider(mlCameraProvider(size)); | |
final recognitions = useProvider(recognitionsProvider); | |
return Scaffold( | |
appBar: AppBar( | |
title: const Text('Object Detection'), | |
), | |
body: mlCamera.when( | |
// MLCameraセットアップ後の表示 | |
data: (mlCamera) => Stack( | |
children: [ | |
// カメラプレビューを表示 | |
CameraView( | |
mlCamera.cameraController, | |
), | |
// バウンディングボックスを表示 | |
buildBoxes( | |
recognitions.state, | |
mlCamera.actualPreviewSize, | |
mlCamera.ratio, | |
), | |
], | |
), | |
// MLCamera読み込み中の表示 | |
loading: () => const Center( | |
child: CircularProgressIndicator(), | |
), | |
// エラー時の表示 | |
error: (err, stack) => Center( | |
child: Text( | |
err.toString(), | |
), | |
), | |
), | |
); | |
} | |
/// バウンディングボックスを構築 | |
Widget buildBoxes( | |
List<Recognition> recognitions, | |
Size actualPreviewSize, | |
double ratio, | |
) { | |
if (recognitions == null || recognitions.isEmpty) { | |
return const SizedBox(); | |
} | |
return Stack( | |
children: recognitions.map((result) { | |
return BoundingBox( | |
result, | |
actualPreviewSize, | |
ratio, | |
); | |
}).toList(), | |
); | |
} | |
} | |
class CameraView extends StatelessWidget { | |
const CameraView( | |
this.cameraController, | |
); | |
final CameraController cameraController; | |
@override | |
Widget build(BuildContext context) { | |
return AspectRatio( | |
aspectRatio: cameraController.value.aspectRatio, | |
child: CameraPreview(cameraController), | |
); | |
} | |
} | |
class BoundingBox extends HookWidget { | |
const BoundingBox( | |
this.result, | |
this.actualPreviewSize, | |
this.ratio, | |
); | |
final Recognition result; | |
final Size actualPreviewSize; | |
final double ratio; | |
@override | |
Widget build(BuildContext context) { | |
final renderLocation = result.getRenderLocation( | |
actualPreviewSize, | |
ratio, | |
); | |
return Positioned( | |
left: renderLocation.left, | |
top: renderLocation.top, | |
width: renderLocation.width, | |
height: renderLocation.height, | |
child: Container( | |
width: renderLocation.width, | |
height: renderLocation.height, | |
decoration: BoxDecoration( | |
border: Border.all( | |
color: Theme.of(context).accentColor, | |
width: 3, | |
), | |
borderRadius: const BorderRadius.all( | |
Radius.circular(2), | |
), | |
), | |
child: buildBoxLabel(result, context), | |
), | |
); | |
} | |
Align buildBoxLabel(Recognition result, BuildContext context) { | |
return Align( | |
alignment: Alignment.topLeft, | |
child: FittedBox( | |
child: ColoredBox( | |
color: Theme.of(context).accentColor, | |
child: Row( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
Text( | |
result.label, | |
), | |
Text( | |
' ${result.score.toStringAsFixed(2)}', | |
), | |
], | |
), | |
), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment