ai_patint_controller.dart 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. import 'dart:convert';
  2. import 'package:fis_measure/interfaces/process/player/play_controller.dart';
  3. import 'package:fis_measure/interfaces/process/workspace/application.dart';
  4. import 'package:fis_measure/process/workspace/measure_data_controller.dart';
  5. import 'package:fis_measure/view/paint/ai_patint_state.dart';
  6. import 'package:fis_measure/view/paint/date_structure.dart';
  7. import 'package:fis_measure/view/player/controller.dart';
  8. import 'package:fis_measure/view/player/enums.dart';
  9. import 'package:flutter/material.dart';
  10. import 'package:get/get.dart';
  11. class AiPatintController extends GetxController {
  12. static const _HAS_VIEW_STATUS_ARR = [VidPlayStatus.play, VidPlayStatus.pause];
  13. /// 播放器控制器
  14. final VidPlayerController controller;
  15. final state = AiPatintState();
  16. late final application = Get.find<IApplication>();
  17. /// 测量AI数据
  18. final measureData = Get.find<MeasureDataController>();
  19. /// 播放控制器
  20. final playerController = Get.find<IPlayerController>();
  21. /// ai结果图展示
  22. late List<Offset> aiResultsList = [];
  23. /// 获取病灶大小
  24. late String lesionSize;
  25. /// ai结果点集
  26. late AiDotsResults aiDotsResults;
  27. /// ai结果点集List
  28. late List<AiDotsResults> aiDotsResultsList;
  29. /// ai结果数据
  30. late List<AIDetectedObject> aiDetectedObject = [];
  31. /// ai部位
  32. late DiagnosisOrganEnum diagnosisOrgan = DiagnosisOrganEnum.Null;
  33. // late double unitsPhysicalPixels =
  34. // application.currentViewPort.region.width / application.frameData!.width;
  35. /// 是否是播放状态
  36. get isPlay => playerController.status == VidPlayStatus.play;
  37. /// ai json 数据
  38. late String? aiResults = '';
  39. /// ai的横纵坐标 四个点
  40. late Offset p1 = Offset.zero;
  41. late Offset p2 = Offset.zero;
  42. late Offset p3 = Offset.zero;
  43. late Offset p4 = Offset.zero;
  44. /// 视频时的画面
  45. double left = -1;
  46. double top = -1;
  47. double width = -1;
  48. double height = -1;
  49. /// 当前帧数
  50. int? frameIndex;
  51. AiPatintController(this.controller);
  52. @override
  53. void onInit() {
  54. _addListenrs();
  55. super.onInit();
  56. }
  57. @override
  58. void dispose() {
  59. super.dispose();
  60. _removeListenrs();
  61. }
  62. void onMeasuredAIResultsInfoChanged(Object sender, String e) {
  63. try {
  64. if (e.isNotEmpty && e != "[]") {
  65. aiResults = e;
  66. final measureDataAIResults = jsonDecode(
  67. aiResults ?? '',
  68. );
  69. state.aiResult.clear();
  70. for (var element in (measureDataAIResults as List)) {
  71. if (element != null) {
  72. try {
  73. state.aiResult.add(
  74. AIDiagnosisPerImageDTO.fromJson(
  75. element,
  76. ),
  77. );
  78. } catch (e) {
  79. state.aiResult.add(AIDiagnosisPerImageDTO());
  80. print("AIDiagnosisPerImageDTO.fromJson Failed");
  81. print(e);
  82. }
  83. } else {
  84. state.aiResult.add(AIDiagnosisPerImageDTO());
  85. }
  86. }
  87. } else {
  88. aiResults = '';
  89. state.aiResult.clear();
  90. }
  91. } catch (e) {
  92. print(e);
  93. }
  94. }
  95. /// 单帧图处理
  96. void onSingleFrameImage(
  97. List<AIDetectedObject>? detectedObjects,
  98. ) {
  99. aiDetectedObject = detectedObjects ?? [];
  100. final widthScale = Get.find<IApplication>().displayScaleRatio;
  101. for (int m = 0; m < detectedObjects!.length; m++) {
  102. final List<AIDiagnosisPoint2D>? contours =
  103. detectedObjects[m].contours ?? [];
  104. if ((contours?.isNotEmpty ?? false) &&
  105. (detectedObjects[m].descriptions?.isNotEmpty ?? false)) {
  106. var lesionSizeDescription = detectedObjects[m].descriptions?.firstWhere(
  107. (element) => element.type == DiagnosisDescriptionEnum.LesionSize);
  108. lesionSize = lesionSizeDescription?.value ?? '';
  109. final lesionSizeMap = jsonDecode(lesionSize);
  110. // var carotidInnerDiameterDescription = detectedObjects[m]
  111. // .descriptions
  112. // ?.firstWhere((element) =>
  113. // element.type == DiagnosisDescriptionEnum.CarotidInnerDiameter);
  114. // final carotidInnerDiameterMap =
  115. // jsonDecode(carotidInnerDiameterDescription?.value ?? '');
  116. if (_HAS_VIEW_STATUS_ARR.contains(state.vidStatus)) {
  117. aiResultsList = [];
  118. p1 = Offset(lesionSizeMap['HorizontalPoint1']['X'] * widthScale,
  119. lesionSizeMap['HorizontalPoint1']['Y'] * widthScale);
  120. p2 = Offset(lesionSizeMap['HorizontalPoint2']['X'] * widthScale,
  121. lesionSizeMap['HorizontalPoint2']['Y'] * widthScale);
  122. p3 = Offset(lesionSizeMap['VerticalPoint1']['X'] * widthScale,
  123. lesionSizeMap['VerticalPoint1']['Y'] * widthScale);
  124. p4 = Offset(lesionSizeMap['VerticalPoint2']['X'] * widthScale,
  125. lesionSizeMap['VerticalPoint2']['Y'] * widthScale);
  126. for (int i = 0; i < contours!.length; i++) {
  127. aiResultsList.add(Offset(
  128. contours[i].x * widthScale,
  129. contours[i].y * widthScale,
  130. ));
  131. }
  132. aiDotsResults = AiDotsResults(
  133. aiResultsIndex: m,
  134. aiResultsList: aiResultsList,
  135. p1: p1,
  136. p2: p2,
  137. p3: p3,
  138. p4: p4,
  139. );
  140. aiDotsResultsList.add(aiDotsResults);
  141. }
  142. }
  143. }
  144. }
  145. /// ai处理图片结果
  146. bool onGetAIResultsInfo() {
  147. double widthScale = Get.find<IApplication>().displayScaleRatio;
  148. if (state.aiResult.isEmpty) {
  149. return false;
  150. } else if (state.aiResult.length == 1) {
  151. updateFeatures();
  152. final diagResultsForEachOrgan =
  153. state.aiResult[0].diagResultsForEachOrgan?[state.aiResultIndex];
  154. final detectedObjects = diagResultsForEachOrgan!.detectedObjects;
  155. diagnosisOrgan = diagResultsForEachOrgan.organ;
  156. if (detectedObjects!.isNotEmpty) {
  157. onSingleFrameImage(
  158. detectedObjects,
  159. );
  160. return true;
  161. } else {
  162. return false;
  163. }
  164. } else {
  165. updateFeatures();
  166. var diagResultsForEachOrgans =
  167. state.aiResult[state.frameIndex].diagResultsForEachOrgan ?? [];
  168. if (diagResultsForEachOrgans.isEmpty) {
  169. return false;
  170. }
  171. final diagResultsForEachOrgan =
  172. diagResultsForEachOrgans[state.aiResultIndex];
  173. diagnosisOrgan = diagResultsForEachOrgan.organ;
  174. final detectedObjects = diagResultsForEachOrgan.detectedObjects;
  175. if (state.vidStatus == VidPlayStatus.pause) {
  176. if (detectedObjects == null) {
  177. return false;
  178. }
  179. if (detectedObjects.isNotEmpty) {
  180. onSingleFrameImage(
  181. detectedObjects,
  182. );
  183. }
  184. return true;
  185. } else if (state.vidStatus == VidPlayStatus.play) {
  186. if (detectedObjects?.isNotEmpty ?? false) {
  187. for (int m = 0; m < detectedObjects!.length; m++) {
  188. final organBoundBox =
  189. detectedObjects[m].boundingBox ?? AIDiagnosisRect();
  190. bool isLiver = diagnosisOrgan == DiagnosisOrganEnum.Liver;
  191. bool isThyroid = diagnosisOrgan == DiagnosisOrganEnum.Thyroid;
  192. // 判断病灶是否是弥漫性
  193. if (detectedObjects[m].label != 0) {
  194. if (isLiver) {
  195. if (detectedObjects[m].label < 5) {
  196. _horizontalVerticalLine(organBoundBox, widthScale);
  197. }
  198. } else if (isThyroid) {
  199. if (detectedObjects[m].label < 7) {
  200. _horizontalVerticalLine(organBoundBox, widthScale);
  201. }
  202. } else {
  203. _horizontalVerticalLine(organBoundBox, widthScale);
  204. }
  205. }
  206. }
  207. return true;
  208. } else {
  209. return false;
  210. }
  211. }
  212. return false;
  213. }
  214. }
  215. void updateFeatures() {
  216. aiDotsResults = AiDotsResults(
  217. aiResultsIndex: 0,
  218. aiResultsList: [],
  219. p1: Offset.zero,
  220. p2: Offset.zero,
  221. p3: Offset.zero,
  222. p4: Offset.zero,
  223. );
  224. state.aiResultIndex = 0;
  225. aiDotsResultsList = [];
  226. left = 0;
  227. top = 0;
  228. width = 0;
  229. height = 0;
  230. }
  231. void _horizontalVerticalLine(
  232. AIDiagnosisRect organBoundBox,
  233. double widthScale,
  234. ) {
  235. left = organBoundBox.left * widthScale;
  236. top = organBoundBox.top * widthScale;
  237. width = organBoundBox.width * widthScale;
  238. height = organBoundBox.height * widthScale;
  239. }
  240. void _addListenrs() async {
  241. measureData.aiResultsInfoChanged
  242. .addListener(onMeasuredAIResultsInfoChanged);
  243. if (measureData.aiResults.isNotEmpty) {
  244. onMeasuredAIResultsInfoChanged(this, measureData.aiResults);
  245. }
  246. }
  247. void _removeListenrs() {
  248. measureData.aiResultsInfoChanged
  249. .removeListener(onMeasuredAIResultsInfoChanged);
  250. }
  251. }