home.dart 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  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/files/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); // ResolutionPreset.high 质量较高的预设,不录音
  46. _cameraController!.initialize().then((_) {
  47. _cameraController!.startImageStream((image) => processCameraImage(cameraDescription, image, onImage));
  48. setState(() {});
  49. });
  50. });
  51. }
  52. /// 回调函数,处理camera拍摄的图片
  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. /// 是否需要旋转图片
  62. /// [inputImage] 图片
  63. Future<bool> shouldTURNAROUND(InputImage inputImage) async {
  64. final list = await _textDetector.processImage(inputImage); // 识别文字
  65. Size? size = _cameraPreviewKey.currentContext?.size;
  66. if (size == null) {
  67. return false;
  68. }
  69. InputImageRotation? rotation = inputImage.inputImageData?.imageRotation;
  70. Size? absoluteSize = inputImage.inputImageData?.size;
  71. if (rotation == null || absoluteSize == null) {
  72. return false;
  73. }
  74. List<Rect> data = [];
  75. for (final item in list.blocks) {
  76. final left = translateX(item.boundingBox.left, rotation, size, absoluteSize);
  77. final top = translateY(item.boundingBox.top, rotation, size, absoluteSize);
  78. final right = translateX(item.boundingBox.right, rotation, size, absoluteSize);
  79. final bottom = translateY(item.boundingBox.bottom, rotation, size, absoluteSize);
  80. final rect = Rect.fromLTRB(left, top, right, bottom);
  81. if (item.text.endsWith("T")) {
  82. data.add(rect);
  83. message = "TURN AROUND";
  84. if (_canSpace) {
  85. _canSpace = false;
  86. // 语音播放:打开录音
  87. tts.speak("TURN AROUND").then((_) => _canSpace = true);
  88. }
  89. _data.addAll(data);
  90. setState(() {});
  91. return true;
  92. }
  93. }
  94. return false;
  95. }
  96. /// 是否需要引导
  97. Future<void> shouldGUIDELINE(InputImage inputImage) async {
  98. final list = await _objectDetector.processImage(inputImage); // 识别物体
  99. Size? size = _cameraPreviewKey.currentContext?.size;
  100. if (size == null) {
  101. return;
  102. }
  103. InputImageRotation? rotation = inputImage.inputImageData?.imageRotation;
  104. Size? absoluteSize = inputImage.inputImageData?.size;
  105. if (rotation == null || absoluteSize == null) {
  106. return;
  107. }
  108. List<Rect> data = [];
  109. for (final item in list) {
  110. final left = translateX(item.boundingBox.left, rotation, size, absoluteSize);
  111. final top = translateY(item.boundingBox.top, rotation, size, absoluteSize);
  112. final right = translateX(item.boundingBox.right, rotation, size, absoluteSize);
  113. final bottom = translateY(item.boundingBox.bottom, rotation, size, absoluteSize);
  114. final rect = Rect.fromLTRB(left, top, right, bottom);
  115. if (rect.height / rect.width >= 2) {
  116. data.add(rect);
  117. }
  118. break;
  119. }
  120. _data.addAll(data);
  121. execGUIDELINE(size);
  122. setState(() {});
  123. }
  124. /// 执行指示
  125. Future<void> execGUIDELINE(Size size) async {
  126. final Rect rect = _data[0];
  127. if (rect.center.dx < size.width / 2) {
  128. message = "LEFT";
  129. if (_canSpace) {
  130. _canSpace = false;
  131. tts.speak("LEFT").then((_) => _canSpace = true);
  132. }
  133. setState(() {});
  134. return;
  135. }
  136. if (rect.center.dx > size.width / 2) {
  137. message = "RIGHT";
  138. if (_canSpace) {
  139. _canSpace = false;
  140. tts.speak("RIGHT").then((_) => _canSpace = true);
  141. }
  142. setState(() {});
  143. return;
  144. }
  145. }
  146. @override
  147. Widget build(BuildContext context) {
  148. final xx = DateTime.now().millisecondsSinceEpoch;
  149. // if (xx >= 1676961078000) {
  150. // Navigator.of(context).pop();
  151. // }
  152. return Scaffold(
  153. appBar: AppBar(
  154. title: const Text("SWIM"),
  155. ),
  156. body: Column(
  157. children: [
  158. if (_cameraController != null) makeCameraPreview(),
  159. ],
  160. ),
  161. );
  162. }
  163. Widget makeCameraPreview() {
  164. Rect? rect;
  165. if (_data.isNotEmpty) {
  166. rect = _data[0];
  167. }
  168. return CameraPreview(
  169. _cameraController!,
  170. key: _cameraPreviewKey,
  171. child: Stack(
  172. children: [
  173. ..._data.map((rect) {
  174. return AnimatedPositioned.fromRect(
  175. rect: rect,
  176. duration: const Duration(milliseconds: 100),
  177. child: Container(
  178. clipBehavior: Clip.antiAlias,
  179. decoration: BoxDecoration(
  180. border: Border.all(color: const Color(0xfff0f0f0), width: 2),
  181. borderRadius: BorderRadius.circular(8),
  182. ),
  183. child: Align(
  184. alignment: Alignment.topLeft,
  185. child: Container(
  186. padding: const EdgeInsets.symmetric(horizontal: 4),
  187. decoration: const BoxDecoration(
  188. borderRadius: BorderRadius.only(bottomRight: Radius.circular(8)),
  189. color: Color(0x99ffffff),
  190. ),
  191. child: Text(
  192. "${rect.center.dx.toStringAsFixed(2)},${rect.center.dy.toStringAsFixed(2)}",
  193. style: const TextStyle(
  194. fontSize: 12,
  195. fontWeight: FontWeight.bold,
  196. color: Colors.indigo,
  197. ),
  198. ),
  199. ),
  200. ),
  201. ),
  202. );
  203. }).toList(),
  204. Align(
  205. alignment: Alignment.topLeft,
  206. child: Container(
  207. padding: const EdgeInsets.symmetric(horizontal: 4),
  208. decoration: const BoxDecoration(
  209. borderRadius: BorderRadius.only(bottomRight: Radius.circular(8)),
  210. color: Color(0x99ffffff),
  211. ),
  212. child: Text(
  213. message,
  214. style: const TextStyle(
  215. fontSize: 14,
  216. fontWeight: FontWeight.bold,
  217. color: Colors.pink,
  218. ),
  219. ),
  220. ),
  221. ),
  222. ],
  223. ),
  224. );
  225. }
  226. }