VetHeartDiagnosis.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. using AI.Common.Interface;
  2. using AI.Vet.Modules.VetHeartEndDiastoleEndSystole;
  3. using AI.Vet.Modules.VetHeartEPSS;
  4. using AI.Vet.Modules.VetHeartLVStudy;
  5. using AIDiagnosis.Common.Enums;
  6. using AIDiagnosis.Common.Helpers;
  7. using AIDiagnosis.Common.Interfaces;
  8. using AIDiagnosis.Common.Models;
  9. using System;
  10. using System.Collections.Generic;
  11. using System.Diagnostics;
  12. using System.Reflection;
  13. using System.Threading;
  14. using System.Threading.Tasks;
  15. using VetHeartDiagnosisSDK.Enums;
  16. namespace VetHeartDiagnosisSDK
  17. {
  18. public class VetHeartDiagnosis
  19. {
  20. private const string _vendor = "Vinno";
  21. private static readonly List<string> _relatedDllList = new List<string>()
  22. {
  23. "AI.Vet.Modules.VetHeartEndDiastoleEndSystole.dll",
  24. "AI.Vet.Modules.VetHeartEPSS.dll",
  25. "AI.Vet.Modules.VetHeartLVStudy.dll",
  26. "AI.Vet.InferNets.VetHeartLargerStructureSeg.dll",
  27. "AI.Vet.InferNets.VetHeartMModeLargerStructureSeg.dll",
  28. "AI.Vet.InferNets.VetHeartMModeSmallerStructureSeg.dll",
  29. "AI.Vet.InferNets.VetHeartSmallerStructureSeg.dll",
  30. "AI.Vet.Tasks.VetHeartBModeCalculation.dll",
  31. "AI.Vet.Tasks.VetHeartBModeEPSSCalculation.dll",
  32. "AI.Vet.Tasks.VetHeartBModeLVStudyCalculation.dll",
  33. "AI.Vet.Tasks.VetHeartEndDiastoleEndSystoleRecognition.dll",
  34. "AI.Vet.Tasks.VetHeartImageTypeSection.dll",
  35. "AI.Vet.Tasks.VetHeartLargerStructureContourSegmentation.dll",
  36. "AI.Vet.Tasks.VetHeartMModeEPSSCalculation.dll",
  37. "AI.Vet.Tasks.VetHeartMModeLargerStructureContourSegmentation.dll",
  38. "AI.Vet.Tasks.VetHeartMModeLVStudyCalculation.dll",
  39. "AI.Vet.Tasks.VetHeartMModeSmallerStructureContourSegmentation.dll",
  40. "AI.Vet.Tasks.VetHeartSmallerStructureContourSegmentation.dll",
  41. "AI.Vet.Tasks.VetHeartStandardSectionRecognition.dll",
  42. "VetHeartStructurePostProcess.dll",
  43. "Networks\\AI.Vet.InferNets.VetHeart.LargerStructureSeg.emd",
  44. "Networks\\AI.Vet.InferNets.VetHeart.MModeLargerStructureSeg2.emd",
  45. "Networks\\AI.Vet.InferNets.VetHeart.MModeSmallerStructureSeg1.emd",
  46. "Networks\\AI.Vet.InferNets.VetHeart.SmallerStructureSeg.emd"
  47. };
  48. private readonly static Dictionary<EnumVetHeartDiagnosisEngineType, string> _aiDllDict = new Dictionary<EnumVetHeartDiagnosisEngineType, string>
  49. {
  50. { EnumVetHeartDiagnosisEngineType.VetHeartLVStudy, "AI.Vet.Modules.VetHeartLVStudy.dll" },
  51. { EnumVetHeartDiagnosisEngineType.VetHeartEPSS, "AI.Vet.Modules.VetHeartEPSS.dll" },
  52. { EnumVetHeartDiagnosisEngineType.VetHeartEndDiastoleEndSystole, "AI.Vet.Modules.VetHeartEndDiastoleEndSystole.dll" },
  53. };
  54. private static Dictionary<EnumVetHeartDiagnosisEngineType, string> _aiVersionDict = new Dictionary<EnumVetHeartDiagnosisEngineType, string>();
  55. private Dictionary<EnumVetHeartDiagnosisEngineType, IModule> _moduleDict = new Dictionary<EnumVetHeartDiagnosisEngineType, IModule>();
  56. private IImageProviderV2 _usImageProvider;
  57. private Dictionary<EnumVetHeartDiagnosisEngineType, string> _processIdDict = new Dictionary<EnumVetHeartDiagnosisEngineType, string>();
  58. private readonly ManualResetEvent _handlingImageEvent = new ManualResetEvent(true);
  59. private readonly object _detectObject = new object();
  60. private static string _aiType => EnumVetHeartDiagnosisFunction.VetHeartDiagnosis.ToString();
  61. /// <summary>
  62. /// 所有可用的功能列表
  63. /// </summary>
  64. private static FunctionInfo _enabledFunction;
  65. /// <summary>
  66. /// 当前正在使用的功能列表
  67. /// </summary>
  68. private static FunctionInfo _currentUsedFunction;
  69. private EnumDetectMode _detectmode;
  70. /// <summary>
  71. /// 图片计数
  72. /// </summary>
  73. private int _imageCounter;
  74. /// <summary>
  75. /// 帧率
  76. /// </summary>
  77. private int _displayFps = -1;
  78. /// <summary>
  79. /// 每隔多少帧检测一次
  80. /// </summary>
  81. private int _detectInterval;
  82. /// <summary>
  83. /// 计时用
  84. /// </summary>
  85. private int _startTickCount = -1;
  86. /// <summary>
  87. /// 所有功能列表
  88. /// </summary>
  89. public static List<FunctionInfo> AllFunctions { get; }
  90. /// <summary>
  91. /// Raised when the image evaluation is started.
  92. /// </summary>
  93. public event EventHandler StartEvaluation;
  94. /// <summary>
  95. /// Raised when the image evaluation is finished.
  96. /// </summary>
  97. public event EventHandler<IReadOnlyDictionary<IDataId, IReadOnlyList<IResultData>>> FinishEvaluation;
  98. /// <summary>
  99. /// Raised when event NotifyLog raised from AI diag system
  100. /// </summary>
  101. public event EventHandler<LogEventArgs> NotifyLog;
  102. /// <summary>
  103. /// 检测模式
  104. /// </summary>
  105. public EnumDetectMode DetectMode
  106. {
  107. get
  108. {
  109. return _detectmode;
  110. }
  111. set
  112. {
  113. if (_detectmode != value)
  114. {
  115. _detectmode = value;
  116. ResetParameters();
  117. }
  118. }
  119. }
  120. /// <summary>
  121. /// 每秒检测次数
  122. /// </summary>
  123. public int DetectTps
  124. {
  125. get; set;
  126. }
  127. /// <summary>
  128. /// 每次检测间隔时间
  129. /// </summary>
  130. public int IntervalTime
  131. {
  132. get; set;
  133. }
  134. /// <summary>
  135. /// 是否将检测的图片保存下来
  136. /// </summary>
  137. public bool IsSaveDetectImage { get; private set; }
  138. /// <summary>
  139. /// 是否保存所有检测的图片,当为False时,则只保留最新的图像
  140. /// </summary>
  141. public bool IsSaveAllImage { get; private set; }
  142. /// <summary>
  143. /// Image Save Path
  144. /// </summary>
  145. public string ImageSavePath { get; private set; }
  146. static VetHeartDiagnosis()
  147. {
  148. try
  149. {
  150. foreach (var aiDll in _aiDllDict)
  151. {
  152. var version = FileVersionInfo.GetVersionInfo(aiDll.Value).FileVersion.ToString();
  153. _aiVersionDict.Add(aiDll.Key, version);
  154. }
  155. AllFunctions = new List<FunctionInfo>
  156. {
  157. new FunctionInfo(EnumVetHeartDiagnosisFunction.VetHeartDiagnosis,true,Assembly.GetExecutingAssembly().GetName().Version.ToString(),null,new List<EngineInfo>
  158. {
  159. new EngineInfo(EnumVetHeartDiagnosisEngineName.VetHeartLVStudy,EnumVetHeartDiagnosisEngineType.VetHeartLVStudy,true,_aiVersionDict[EnumVetHeartDiagnosisEngineType.VetHeartLVStudy],_vendor,null, _relatedDllList),
  160. new EngineInfo(EnumVetHeartDiagnosisEngineName.VetHeartEPSS,EnumVetHeartDiagnosisEngineType.VetHeartEPSS,true,_aiVersionDict[EnumVetHeartDiagnosisEngineType.VetHeartEPSS],_vendor,null, _relatedDllList),
  161. new EngineInfo(EnumVetHeartDiagnosisEngineName.VetHeartEndDiastoleEndSystole,EnumVetHeartDiagnosisEngineType.VetHeartEndDiastoleEndSystole,true,_aiVersionDict[EnumVetHeartDiagnosisEngineType.VetHeartEndDiastoleEndSystole],_vendor,null, _relatedDllList),
  162. }),
  163. };
  164. }
  165. catch
  166. {
  167. }
  168. }
  169. public static void Init(FunctionInfo enabledFunction, FunctionInfo currentUsedFunction)
  170. {
  171. _enabledFunction = enabledFunction;
  172. _currentUsedFunction = currentUsedFunction;
  173. }
  174. /// <summary>
  175. /// 当启用时切换使用的引擎(静态方法,当未启用时)
  176. /// </summary>
  177. /// <param name="functionInfo"></param>
  178. public static void SwitchAIEngines(FunctionInfo functionInfo)
  179. {
  180. //ToDoFelix
  181. }
  182. /// <summary>
  183. /// Initialize VetHeartDiagnosis
  184. /// </summary>
  185. /// <param name="cpuNumber">指定用于AI计算的cpu数.</param>
  186. /// <param name="modelFileFolder">模型文件路径.</param>
  187. /// <param name="detectMode">TimesPerSecond: 按每秒固定次数间隔,PeriodicIntervals:按固定时间间隔检测.</param>
  188. /// <param name="detectTps">检测帧频间隔,detectModel为TimesPerSecond时使用</param>
  189. /// <param name="intervalTime">检测间隔时间,detectModel为PeriodicIntervals时使用.</param>
  190. public void Init(bool isSaveDetectImage, bool isSaveAllImage, string imageSavePath, IImageProviderV2 usImageProvider, int cpuNumber, string modelFileFolder, EnumDetectMode detectMode, int detectTps, int intervalTime)
  191. {
  192. //Load VetHeartDiagnosis
  193. try
  194. {
  195. IsSaveDetectImage = isSaveDetectImage;
  196. IsSaveAllImage = isSaveAllImage;
  197. ImageSavePath = imageSavePath;
  198. DetectMode = detectMode;
  199. DetectTps = detectTps;
  200. IntervalTime = intervalTime;
  201. _usImageProvider = usImageProvider;
  202. var config = new InferenceConfig();
  203. config.SetConfig(EnumInferenceConfigKey.CPU_THREADS_NUM_PER_NET, cpuNumber.ToString(), EnumDeviceType.CPU);
  204. CloseDiagnosis();
  205. var task1 = Task.Run(() =>
  206. {
  207. LoadLVStudy(modelFileFolder, config);
  208. });
  209. var task2 = Task.Run(() =>
  210. {
  211. LoadEPSS(modelFileFolder, config);
  212. });
  213. var task3 = Task.Run(() =>
  214. {
  215. LoadEDES(modelFileFolder, config);
  216. });
  217. Task.WhenAll(task1, task2, task3).GetAwaiter().GetResult();
  218. }
  219. catch (Exception ex)
  220. {
  221. throw new Exception($"Load VetHeartDiagnosis Failed!:{ex}");
  222. }
  223. }
  224. private void LoadLVStudy(string modelFileFolder, InferenceConfig config)
  225. {
  226. try
  227. {
  228. var vetHeartLVStudy = new VetHeartLVStudy(modelFileFolder, config);
  229. vetHeartLVStudy.NotifyLog += OnNotifyLog;
  230. _moduleDict.Add(EnumVetHeartDiagnosisEngineType.VetHeartLVStudy, vetHeartLVStudy);
  231. }
  232. catch (Exception ex)
  233. {
  234. OnNotifyLog(this, new LogEventArgs(EnumLogType.ErrorLog, $"Load VetHeartLVStudy Failed!:{ex}"));
  235. }
  236. }
  237. private void LoadEPSS(string modelFileFolder, InferenceConfig config)
  238. {
  239. try
  240. {
  241. var vetHeartEPSS = new VetHeartEPSS(modelFileFolder, config);
  242. vetHeartEPSS.NotifyLog += OnNotifyLog;
  243. _moduleDict.Add(EnumVetHeartDiagnosisEngineType.VetHeartEPSS, vetHeartEPSS);
  244. }
  245. catch (Exception ex)
  246. {
  247. OnNotifyLog(this, new LogEventArgs(EnumLogType.ErrorLog, $"Load VetHeartEPSS Failed!:{ex}"));
  248. }
  249. }
  250. private void LoadEDES(string modelFileFolder, InferenceConfig config)
  251. {
  252. try
  253. {
  254. var vetHeartEndDiastoleEndSystole = new VetHeartEndDiastoleEndSystole(modelFileFolder, config);
  255. vetHeartEndDiastoleEndSystole.NotifyLog += OnNotifyLog;
  256. _moduleDict.Add(EnumVetHeartDiagnosisEngineType.VetHeartEndDiastoleEndSystole, vetHeartEndDiastoleEndSystole);
  257. }
  258. catch (Exception ex)
  259. {
  260. OnNotifyLog(this, new LogEventArgs(EnumLogType.ErrorLog, $"Load VetHeartEndDiastoleEndSystole Failed!:{ex}"));
  261. }
  262. }
  263. /// <summary>
  264. /// 当启用时切换使用的引擎
  265. /// </summary>
  266. /// <param name="functionInfo"></param>
  267. public void SwitchAIEngines2(FunctionInfo functionInfo)
  268. {
  269. //ToDoFelix
  270. }
  271. /// <summary>
  272. /// Start the Image Provider
  273. /// </summary>
  274. public void Start()
  275. {
  276. ResetParameters();
  277. if (_usImageProvider != null)
  278. {
  279. _usImageProvider.ImageProvided += OnImageProvided;
  280. _usImageProvider.Start();
  281. }
  282. }
  283. /// <summary>
  284. /// Stop the Image Provider
  285. /// </summary>
  286. public void Stop()
  287. {
  288. if (_usImageProvider != null)
  289. {
  290. _usImageProvider.ImageProvided -= OnImageProvided;
  291. _usImageProvider.Stop();
  292. }
  293. }
  294. /// <summary>
  295. /// Stop the Image Provider and Close the VetHeartMLine Diagnosis
  296. /// </summary>
  297. public void Close()
  298. {
  299. Stop();
  300. _handlingImageEvent.WaitOne();
  301. lock (_detectObject)
  302. {
  303. CloseDiagnosis();
  304. }
  305. }
  306. /// <summary>
  307. /// 开启处理,并返回处理ID
  308. /// </summary>
  309. /// <param name="typeName">Modlue Name</param>
  310. public string StartProcess(EnumVetHeartDiagnosisEngineType typeName)
  311. {
  312. if (_moduleDict.ContainsKey(typeName))
  313. {
  314. if (_processIdDict.ContainsKey(typeName))
  315. {
  316. var existProcessId = _processIdDict[typeName];
  317. _processIdDict.Remove(typeName);
  318. _moduleDict[typeName].EndProcess(existProcessId);
  319. }
  320. return _moduleDict[typeName].StartProcess();
  321. }
  322. else
  323. {
  324. return null;
  325. }
  326. }
  327. /// <summary>
  328. /// 结束处理
  329. /// </summary>
  330. /// <param name="typeName">Type Name</param>
  331. public void EndProcess(EnumVetHeartDiagnosisEngineType typeName, string processId)
  332. {
  333. if (_moduleDict.ContainsKey(typeName))
  334. {
  335. if (_processIdDict.ContainsKey(typeName))
  336. {
  337. _processIdDict.Remove(typeName);
  338. }
  339. _moduleDict[typeName].EndProcess(processId);
  340. }
  341. }
  342. /// <summary>
  343. /// 检测单张图片
  344. /// </summary>
  345. /// <param name="typeName">type Name</param>
  346. /// <param name="inputDatas">输入数据</param>
  347. public IReadOnlyDictionary<IDataId, IReadOnlyList<IResultData>> DetectOneImage(EnumVetHeartDiagnosisEngineType typeName, string processId, IImageInputData inputDatas)
  348. {
  349. return HandleImage(false, typeName, processId, inputDatas);
  350. }
  351. private void OnImageProvided(object sender, IImageInputData e)
  352. {
  353. if (sender is IImageProviderV2 imageProvider)
  354. {
  355. EnumVetHeartDiagnosisEngineType? type = null;
  356. if (imageProvider.EngineType == EnumVetHeartDiagnosisEngineType.VetHeartLVStudy.ToString())
  357. {
  358. type = EnumVetHeartDiagnosisEngineType.VetHeartLVStudy;
  359. }
  360. else if (imageProvider.EngineType == EnumVetHeartDiagnosisEngineType.VetHeartEPSS.ToString())
  361. {
  362. type = EnumVetHeartDiagnosisEngineType.VetHeartEPSS;
  363. }
  364. else if (imageProvider.EngineType == EnumVetHeartDiagnosisEngineType.VetHeartEndDiastoleEndSystole.ToString())
  365. {
  366. type = EnumVetHeartDiagnosisEngineType.VetHeartEndDiastoleEndSystole;
  367. }
  368. if (type.HasValue)
  369. {
  370. if (!_processIdDict.ContainsKey(type.Value))
  371. {
  372. var processId = _moduleDict[type.Value].StartProcess();
  373. _processIdDict.Add(type.Value, processId);
  374. }
  375. OnUsImageChanged(type.Value, _processIdDict[type.Value], e);
  376. }
  377. }
  378. }
  379. private void OnUsImageChanged(EnumVetHeartDiagnosisEngineType typeName, string processId, IImageInputData inputDatas)
  380. {
  381. if (DetectMode == EnumDetectMode.TimesPerSecond)///检测模式:每秒检测几次
  382. {//计算fps, 3秒检测一次
  383. if (_startTickCount == -1)
  384. {
  385. _startTickCount = Environment.TickCount;
  386. HandleImage(true, typeName, processId, inputDatas);
  387. }
  388. else
  389. {
  390. var fpscurrentTickCount = Environment.TickCount;
  391. var timespan = fpscurrentTickCount - _startTickCount;
  392. if (timespan >= 3000)
  393. {
  394. _displayFps = _imageCounter * 1000 / timespan;
  395. _detectInterval = (int)Math.Round((float)_displayFps / DetectTps);
  396. _imageCounter = 0;
  397. _startTickCount = Environment.TickCount; ;
  398. }
  399. if (_detectInterval > 0)
  400. {
  401. if (_imageCounter % _detectInterval == 0)
  402. {
  403. HandleImage(true, typeName, processId, inputDatas);
  404. }
  405. }
  406. }
  407. _imageCounter++;
  408. if (_imageCounter > 1000000)
  409. {
  410. _imageCounter = 0;
  411. }
  412. }
  413. else///检测模式:间隔固定时间检测
  414. {
  415. if (_startTickCount == -1)
  416. {
  417. _startTickCount = Environment.TickCount;
  418. HandleImage(true, typeName, processId, inputDatas);
  419. }
  420. else
  421. {
  422. var currentTickCount = Environment.TickCount;
  423. if (IntervalTime <= currentTickCount - _startTickCount)
  424. {
  425. HandleImage(true, typeName, processId, inputDatas);
  426. _startTickCount = Environment.TickCount;
  427. }
  428. }
  429. }
  430. }
  431. private IReadOnlyDictionary<IDataId, IReadOnlyList<IResultData>> HandleImage(bool isImageProviderMode, EnumVetHeartDiagnosisEngineType typeName, string processId, IImageInputData inputData)
  432. {
  433. _handlingImageEvent.Reset();
  434. IReadOnlyDictionary<IDataId, IReadOnlyList<IResultData>> diagResult = default;
  435. try
  436. {
  437. if (isImageProviderMode)
  438. {
  439. StartEvaluation?.Invoke(this, EventArgs.Empty);
  440. }
  441. lock (_detectObject)
  442. {
  443. if (IsSaveDetectImage && !string.IsNullOrEmpty(ImageSavePath))
  444. {
  445. if (!IsSaveAllImage)
  446. {
  447. RawImageHelper.ClearOldImages(_aiType, ImageSavePath);
  448. }
  449. RawImageHelper.SaveRawImageV2(inputData.Image, _aiType, ImageSavePath);
  450. }
  451. using (inputData.Image)
  452. {
  453. if (_moduleDict.ContainsKey(typeName))
  454. {
  455. diagResult = _moduleDict[typeName].PushOnePieceOfData(processId, new InputDataContainer(inputData));
  456. }
  457. }
  458. }
  459. if (isImageProviderMode)
  460. {
  461. FinishEvaluation?.Invoke(this, diagResult);
  462. }
  463. }
  464. catch (Exception ex)
  465. {
  466. NotifyLog?.Invoke(this, new LogEventArgs(EnumLogType.ErrorLog, $"HandleImage Error: {ex}"));
  467. }
  468. finally
  469. {
  470. _handlingImageEvent.Set();
  471. }
  472. return diagResult;
  473. }
  474. private void OnNotifyLog(object sender, LogEventArgs e)
  475. {
  476. NotifyLog?.Invoke(this, e);
  477. }
  478. private void ResetParameters()
  479. {
  480. _startTickCount = -1;
  481. _imageCounter = 0;
  482. _displayFps = -1;
  483. _detectInterval = 0;
  484. }
  485. private void CloseDiagnosis()
  486. {
  487. foreach (var module in _moduleDict.Values)
  488. {
  489. module.NotifyLog -= OnNotifyLog;
  490. module.Dispose();
  491. }
  492. _moduleDict.Clear();
  493. }
  494. }
  495. }