home.dart 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. import 'package:camera/camera.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter_tts/flutter_tts.dart';
  4. import 'package:google_mlkit_object_detection/google_mlkit_object_detection.dart';
  5. import 'package:google_mlkit_text_recognition/google_mlkit_text_recognition.dart';
  6. import 'package:internal/common/camera.dart';
  7. import 'package:internal/common/transform.dart';
  8. /// Description: Home Page
  9. /// Time : 04/12/2023 Wednesday
  10. /// Author : liuyuqi.gov@msn.cn
  11. class HomeScreen extends StatefulWidget {
  12. const HomeScreen({Key? key}) : super(key: key);
  13. @override
  14. State<HomeScreen> createState() => _HomeScreenState();
  15. }
  16. /// Description: Home Page State
  17. class _HomeScreenState extends State<HomeScreen> {
  18. CameraController? _cameraController;
  19. /// 检测器
  20. final ObjectDetector _objectDetector = ObjectDetector(
  21. options: LocalObjectDetectorOptions(
  22. mode: DetectionMode.stream,
  23. multipleObjects: false,
  24. classifyObjects: false,
  25. modelPath: 'flutter_assets/0/0.tflite',
  26. ),
  27. );
  28. final TextRecognizer _textDetector = TextRecognizer(
  29. script: TextRecognitionScript.latin,
  30. );
  31. bool _canRender = true;
  32. bool _canSpace = true;
  33. final GlobalKey _cameraPreviewKey = GlobalKey();
  34. List<Rect> _data = [];
  35. String message = "";
  36. FlutterTts tts = FlutterTts();
  37. /// 初始化状态
  38. @override
  39. void initState() {
  40. super.initState();
  41. tts.awaitSpeakCompletion(true);
  42. /// 检测可用相机
  43. availableCameras().then((cameras) {
  44. CameraDescription cameraDescription = cameras[0];
  45. _cameraController = CameraController(cameraDescription, ResolutionPreset.high, enableAudio: false);
  46. _cameraController!.initialize().then((_) {
  47. _cameraController!.startImageStream((image) => processCameraImage(cameraDescription, image, onImage));
  48. setState(() {});
  49. });
  50. });
  51. }
  52. /// 回调函数
  53. Future<void> onImage(InputImage inputImage) async {
  54. if (!_canRender) return;
  55. _canRender = false;
  56. _data = [];
  57. bool xx = await shouldTURNAROUND(inputImage);
  58. if (!xx) await shouldGUIDELINE(inputImage);
  59. _canRender = true;
  60. }
  61. Future<bool> shouldTURNAROUND(InputImage inputImage) async {
  62. final list = await _textDetector.processImage(inputImage);
  63. Size? size = _cameraPreviewKey.currentContext?.size;
  64. if (size == null) {
  65. return false;
  66. }
  67. InputImageRotation? rotation = inputImage.inputImageData?.imageRotation;
  68. Size? absoluteSize = inputImage.inputImageData?.size;
  69. if (rotation == null || absoluteSize == null) {
  70. return false;
  71. }
  72. List<Rect> data = [];
  73. for (final item in list.blocks) {
  74. final left = translateX(item.boundingBox.left, rotation, size, absoluteSize);
  75. final top = translateY(item.boundingBox.top, rotation, size, absoluteSize);
  76. final right = translateX(item.boundingBox.right, rotation, size, absoluteSize);
  77. final bottom = translateY(item.boundingBox.bottom, rotation, size, absoluteSize);
  78. final rect = Rect.fromLTRB(left, top, right, bottom);
  79. if (item.text.endsWith("T")) {
  80. data.add(rect);
  81. message = "TURN AROUND";
  82. if (_canSpace) {
  83. _canSpace = false;
  84. tts.speak("TURN AROUND").then((_) => _canSpace = true);
  85. }
  86. _data.addAll(data);
  87. setState(() {});
  88. return true;
  89. }
  90. }
  91. return false;
  92. }
  93. /// 检测指示
  94. Future<void> shouldGUIDELINE(InputImage inputImage) async {
  95. final list = await _objectDetector.processImage(inputImage);
  96. Size? size = _cameraPreviewKey.currentContext?.size;
  97. if (size == null) {
  98. return;
  99. }
  100. InputImageRotation? rotation = inputImage.inputImageData?.imageRotation;
  101. Size? absoluteSize = inputImage.inputImageData?.size;
  102. if (rotation == null || absoluteSize == null) {
  103. return;
  104. }
  105. List<Rect> data = [];
  106. for (final item in list) {
  107. final left = translateX(item.boundingBox.left, rotation, size, absoluteSize);
  108. final top = translateY(item.boundingBox.top, rotation, size, absoluteSize);
  109. final right = translateX(item.boundingBox.right, rotation, size, absoluteSize);
  110. final bottom = translateY(item.boundingBox.bottom, rotation, size, absoluteSize);
  111. final rect = Rect.fromLTRB(left, top, right, bottom);
  112. if (rect.height / rect.width >= 2) {
  113. data.add(rect);
  114. }
  115. break;
  116. }
  117. _data.addAll(data);
  118. execGUIDELINE(size);
  119. setState(() {});
  120. }
  121. /// 执行指示
  122. Future<void> execGUIDELINE(Size size) async {
  123. final Rect rect = _data[0];
  124. if (rect.center.dx < size.width / 2) {
  125. message = "LEFT";
  126. if (_canSpace) {
  127. _canSpace = false;
  128. tts.speak("LEFT").then((_) => _canSpace = true);
  129. }
  130. setState(() {});
  131. return;
  132. }
  133. if (rect.center.dx > size.width / 2) {
  134. message = "RIGHT";
  135. if (_canSpace) {
  136. _canSpace = false;
  137. tts.speak("RIGHT").then((_) => _canSpace = true);
  138. }
  139. setState(() {});
  140. return;
  141. }
  142. }
  143. @override
  144. Widget build(BuildContext context) {
  145. final xx = DateTime.now().millisecondsSinceEpoch;
  146. // if (xx >= 1676961078000) {
  147. // Navigator.of(context).pop();
  148. // }
  149. return Scaffold(
  150. appBar: AppBar(
  151. title: const Text("SWIM"),
  152. ),
  153. body: Column(
  154. children: [
  155. if (_cameraController != null) makeCameraPreview(),
  156. ],
  157. ),
  158. );
  159. }
  160. Widget makeCameraPreview() {
  161. Rect? rect;
  162. if (_data.isNotEmpty) {
  163. rect = _data[0];
  164. }
  165. return CameraPreview(
  166. _cameraController!,
  167. key: _cameraPreviewKey,
  168. child: Stack(
  169. children: [
  170. ..._data.map((rect) {
  171. return AnimatedPositioned.fromRect(
  172. rect: rect,
  173. duration: const Duration(milliseconds: 100),
  174. child: Container(
  175. clipBehavior: Clip.antiAlias,
  176. decoration: BoxDecoration(
  177. border: Border.all(color: const Color(0xfff0f0f0), width: 2),
  178. borderRadius: BorderRadius.circular(8),
  179. ),
  180. child: Align(
  181. alignment: Alignment.topLeft,
  182. child: Container(
  183. padding: const EdgeInsets.symmetric(horizontal: 4),
  184. decoration: const BoxDecoration(
  185. borderRadius: BorderRadius.only(bottomRight: Radius.circular(8)),
  186. color: Color(0x99ffffff),
  187. ),
  188. child: Text(
  189. "${rect.center.dx.toStringAsFixed(2)},${rect.center.dy.toStringAsFixed(2)}",
  190. style: const TextStyle(
  191. fontSize: 12,
  192. fontWeight: FontWeight.bold,
  193. color: Colors.indigo,
  194. ),
  195. ),
  196. ),
  197. ),
  198. ),
  199. );
  200. }).toList(),
  201. Align(
  202. alignment: Alignment.topLeft,
  203. child: Container(
  204. padding: const EdgeInsets.symmetric(horizontal: 4),
  205. decoration: const BoxDecoration(
  206. borderRadius: BorderRadius.only(bottomRight: Radius.circular(8)),
  207. color: Color(0x99ffffff),
  208. ),
  209. child: Text(
  210. message,
  211. style: const TextStyle(
  212. fontSize: 14,
  213. fontWeight: FontWeight.bold,
  214. color: Colors.pink,
  215. ),
  216. ),
  217. ),
  218. ),
  219. ],
  220. ),
  221. );
  222. }
  223. }