CustomizeDiagnosisService.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. using AI.Common.Interface;
  2. using AIDiagnosis.Common.Enums;
  3. using AIDiagnosis.Common.Models;
  4. using System;
  5. using System.Collections.Concurrent;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Threading;
  10. using Vinno.AI.CommonSDK.Enums;
  11. using Vinno.AI.CommonSDK.Models;
  12. using Vinno.AI.CommonSDK.Models.Data;
  13. using Vinno.AI.CommonSDK.Tools;
  14. using Vinno.AI.CustomizeDiagnosisSDK.Interfaces;
  15. using Vinno.AI.CustomizeDiagnosisSDK.Models;
  16. using Vinno.AI.CustomizeDiagnosisService.Tools;
  17. using Vinno.AI.Service.Common.Models;
  18. using Vinno.AI.Service.Common.Tools;
  19. using CustomizeDiagnosis = CustomizeDiagnosisSDK.CustomizeDiagnosis;
  20. namespace Vinno.AI.CustomizeDiagnosisService
  21. {
  22. public class CustomizeDiagnosisService : ICustomizeDiagnosisService, IDisposable
  23. {
  24. private readonly ConcurrentDictionary<string, ConcurrentStack<byte[]>> _singleImageCacheList;
  25. private readonly ConcurrentDictionary<string, PipeServer> _singleImagePipeServerList;
  26. private readonly ConcurrentDictionary<string, CustomizeImageProviderV2> _imageProviderList;
  27. private static readonly string _customizeFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CustomizeFolder");
  28. private bool _disposed;
  29. private static List<CustomizeDiagnosis> _customizeDiagnoses;
  30. public static List<FunctionInfo> AllFunctions { get; private set; }
  31. static CustomizeDiagnosisService()
  32. {
  33. try
  34. {
  35. _customizeDiagnoses = new List<CustomizeDiagnosis>();
  36. LoadCustomizeEngines();
  37. }
  38. catch (Exception ex)
  39. {
  40. Logger.Error($"CustomizeDiagnosisService-Constructor error:{ex}");
  41. }
  42. }
  43. private static void LoadCustomizeEngines()
  44. {
  45. if (!Directory.Exists(_customizeFolder))
  46. {
  47. return;
  48. }
  49. var folders = Directory.GetDirectories(_customizeFolder);
  50. if (folders == null || folders.Length == 0)
  51. {
  52. return;
  53. }
  54. foreach (var item in folders)
  55. {
  56. var directoryName = Path.GetFileName(item);
  57. var engineArray = directoryName.Split('_');
  58. if (engineArray.Length == 2)
  59. {
  60. if (!engineArray[1].ToLower().EndsWith(".dll"))
  61. {
  62. continue;
  63. }
  64. var engineType = engineArray[0];
  65. var engineDllName = engineArray[1];
  66. var engineDll = Directory.GetFiles(item).FirstOrDefault(x => x.EndsWith(engineDllName));
  67. if (engineDll == null)
  68. {
  69. continue;
  70. }
  71. try
  72. {
  73. var customizeDiagnosis = new CustomizeDiagnosis(engineDll, engineType);
  74. _customizeDiagnoses.Add(customizeDiagnosis);
  75. if (AllFunctions == null)
  76. {
  77. AllFunctions = new List<FunctionInfo>
  78. {
  79. new FunctionInfo(AIEnumType.CustomizeDiagnosis, true, customizeDiagnosis.FunctionVersion, null, new List<EngineInfo>())
  80. };
  81. }
  82. AllFunctions[0].Engines.Add(customizeDiagnosis.EngineInfo);
  83. }
  84. catch (Exception ex)
  85. {
  86. Logger.Warning($"LoadCustomizeEngines Error:{ex}");
  87. continue;
  88. }
  89. }
  90. else
  91. {
  92. continue;
  93. }
  94. }
  95. }
  96. public CustomizeDiagnosisService()
  97. {
  98. try
  99. {
  100. _singleImageCacheList = new ConcurrentDictionary<string, ConcurrentStack<byte[]>>();
  101. _singleImagePipeServerList = new ConcurrentDictionary<string, PipeServer>();
  102. _imageProviderList = new ConcurrentDictionary<string, CustomizeImageProviderV2>();
  103. if (AllFunctions?.FirstOrDefault()?.Engines == null || AllFunctions.FirstOrDefault()?.Engines.Count == 0)
  104. {
  105. throw new ArgumentNullException("CustomizeDiagnosisService has no enable Function or Engines");
  106. }
  107. foreach (var engine in AllFunctions.FirstOrDefault()?.Engines)
  108. {
  109. var uniqueString = engine.GetUniqueString();
  110. var singleImagePipeServer = new PipeServer(AIDiagnosisSystemConsts.PipeForCustomizeDiagnosisSingleImage + uniqueString);
  111. singleImagePipeServer.LogMsgThrow += OnLogMsgThrow;
  112. singleImagePipeServer.DataReceived += OnDataReceived;
  113. singleImagePipeServer.StartAndReceive();
  114. if (!_singleImagePipeServerList.TryAdd(uniqueString, singleImagePipeServer))
  115. {
  116. Logger.Error($"CustomizeDiagnosisService Try Add _singleImagePipeServerList Failed, UniqueString:{uniqueString}");
  117. continue;
  118. }
  119. if (!_singleImageCacheList.TryAdd(AIDiagnosisSystemConsts.PipeForCustomizeDiagnosisSingleImage + uniqueString, new ConcurrentStack<byte[]>()))
  120. {
  121. Logger.Error($"CustomizeDiagnosisService Try Add _singleImageCacheList Failed, UniqueString:{uniqueString}");
  122. continue;
  123. }
  124. if (!_imageProviderList.TryAdd(uniqueString, new CustomizeImageProviderV2(uniqueString)))
  125. {
  126. Logger.Error($"CustomizeDiagnosisService Try Add _imageProviderList Failed, UniqueString:{uniqueString}");
  127. continue;
  128. }
  129. }
  130. }
  131. catch (Exception ex)
  132. {
  133. Logger.Error($"CustomizeDiagnosis-Constructor error:{ex}");
  134. }
  135. }
  136. public void Initialize(AIEngineInfo aiEngineInfo, CustomizeDiagnosisParameter customizeDiagnosisParameter, bool hasImageProvider)
  137. {
  138. try
  139. {
  140. if (aiEngineInfo == null)
  141. {
  142. Logger.Error($"CustomizeDiagnosisService Initialize Error: engineInfo is null");
  143. return;
  144. }
  145. var uniqueString = aiEngineInfo.GetUniqueString();
  146. var existDiagnosis = _customizeDiagnoses.FirstOrDefault(x => x.EngineInfo.GetUniqueString() == uniqueString);
  147. if (existDiagnosis == null)
  148. {
  149. Logger.Error($"CustomizeDiagnosisService Initialize Error: {uniqueString} not found ");
  150. return;
  151. }
  152. CloseDiagnosis(existDiagnosis);
  153. var detectMode = (EnumDetectMode)customizeDiagnosisParameter.DetectMode;
  154. var detectTps = customizeDiagnosisParameter.DetectTps;
  155. var intervalTime = customizeDiagnosisParameter.IntervalTime;
  156. CustomizeImageProviderV2 imageProvider;
  157. if (hasImageProvider)
  158. {
  159. if (_imageProviderList.ContainsKey(uniqueString))
  160. {
  161. imageProvider = _imageProviderList[aiEngineInfo.GetUniqueString()];
  162. }
  163. else
  164. {
  165. imageProvider = null;
  166. }
  167. }
  168. else
  169. {
  170. imageProvider = null;
  171. }
  172. existDiagnosis.Initialize(Setting.Instance.IsSaveDetectImage, Setting.Instance.IsSaveAllImage, Logger.LogDir, imageProvider, detectMode, detectTps, intervalTime);
  173. existDiagnosis.StartEvaluation += OnStartEvaluation;
  174. existDiagnosis.FinishEvaluation += OnFinishEvaluation;
  175. existDiagnosis.NotifyLog += OnNotifyLog;
  176. }
  177. catch (Exception ex)
  178. {
  179. Logger.Error($"CustomizeDiagnosis-Initialize error:{ex}");
  180. }
  181. }
  182. public AICustomizeDetectedObjectInfo[] DetectOneImage(AIEngineInfo aiEngineInfo, int height, int width, AIEnumColorType colorType, AIImageDataId aiImageDataId, AIImageExtraInfo imageExtraInfo, AICustomizeUltrasoundImageRegionInfo ultrasoundImageRegionInfo)
  183. {
  184. try
  185. {
  186. if (aiEngineInfo == null)
  187. {
  188. Logger.Error($"CustomizeDiagnosisService DetectOneRawImage Error: engineInfo is null");
  189. return null;
  190. }
  191. var uniqueString = aiEngineInfo.GetUniqueString();
  192. var existDiagnosis = _customizeDiagnoses.FirstOrDefault(x => x.EngineInfo.GetUniqueString() == uniqueString);
  193. if (existDiagnosis == null)
  194. {
  195. Logger.Error($"CustomizeDiagnosisService DetectOneRawImage Error: {uniqueString} not found ");
  196. return null;
  197. }
  198. if (!_singleImageCacheList.ContainsKey(AIDiagnosisSystemConsts.PipeForCustomizeDiagnosisSingleImage + uniqueString))
  199. {
  200. Logger.Error($"CustomizeDiagnosisService DetectOneRawImage Error: _singleImageCacheList not found {uniqueString}");
  201. return null;
  202. }
  203. byte[] byteImage = null;
  204. int retryCount = 0;
  205. while (!_singleImageCacheList[AIDiagnosisSystemConsts.PipeForCustomizeDiagnosisSingleImage + uniqueString].TryPop(out byteImage) && retryCount < 50)
  206. {
  207. Thread.Sleep(10);
  208. retryCount++;
  209. }
  210. if (byteImage == null)
  211. {
  212. Logger.Error($"CustomizeDiagnosis-DetectOneRawImage Get Image Cache Fail");
  213. return null;
  214. }
  215. var rawImage = new RawImage(byteImage, width, height, (EnumColorType)colorType);
  216. var imageDataId = AICommonServiceConvertHelperV2.ConvertAIImageDataIdToImageDataId(aiImageDataId);
  217. Dictionary<string, object> extraInfoList = new Dictionary<string, object>();
  218. if (imageExtraInfo != null)
  219. {
  220. extraInfoList.Add(nameof(imageExtraInfo.CmPerPixel), imageExtraInfo.CmPerPixel);
  221. }
  222. if (ultrasoundImageRegionInfo != null)
  223. {
  224. var ultrasoundImageRegion = AIConvertHelper.ConvertAICustomizeUltrasoundImageRegionInfoToIUltrasoundImageRegion(ultrasoundImageRegionInfo);
  225. if (ultrasoundImageRegion != null)
  226. {
  227. extraInfoList.Add("UltrasoundImageRegion", ultrasoundImageRegion);
  228. }
  229. }
  230. var imageInputData = new ImageInputData(rawImage, imageDataId, extraInfoList);
  231. var detectedObjects = existDiagnosis.DetectOneImage(imageInputData);
  232. return AIConvertHelper.ConvertIDetectedObjectArrayToAICustomizeDetectedObjectInfoArray(detectedObjects);
  233. }
  234. catch (Exception ex)
  235. {
  236. Logger.Error($"CustomizeDiagnosis-DetectOneRawImage error:{ex}");
  237. return null;
  238. }
  239. }
  240. public void Start(AIEngineInfo aiEngineInfo)
  241. {
  242. try
  243. {
  244. if (aiEngineInfo == null)
  245. {
  246. Logger.Error($"CustomizeDiagnosisService Start Error: engineInfo is null");
  247. return;
  248. }
  249. var uniqueString = aiEngineInfo.GetUniqueString();
  250. var existDiagnosis = _customizeDiagnoses.FirstOrDefault(x => x.EngineInfo.GetUniqueString() == uniqueString);
  251. if (existDiagnosis == null)
  252. {
  253. Logger.Error($"CustomizeDiagnosisService Start Error: {uniqueString} not found ");
  254. return;
  255. }
  256. if (existDiagnosis.IsInitialized)
  257. {
  258. existDiagnosis.Start();
  259. }
  260. }
  261. catch (Exception ex)
  262. {
  263. Logger.Error($"CustomizeDiagnosisService-Start error:{ex}");
  264. }
  265. }
  266. public void Stop(AIEngineInfo aiEngineInfo)
  267. {
  268. try
  269. {
  270. if (aiEngineInfo == null)
  271. {
  272. Logger.Error($"CustomizeDiagnosisService Stop Error: engineInfo is null");
  273. return;
  274. }
  275. var uniqueString = aiEngineInfo.GetUniqueString();
  276. var existDiagnosis = _customizeDiagnoses.FirstOrDefault(x => x.EngineInfo.GetUniqueString() == uniqueString);
  277. if (existDiagnosis == null)
  278. {
  279. Logger.Error($"CustomizeDiagnosisService Stop Error: {uniqueString} not found ");
  280. return;
  281. }
  282. if (existDiagnosis.IsInitialized)
  283. {
  284. existDiagnosis.Stop();
  285. }
  286. }
  287. catch (Exception ex)
  288. {
  289. Logger.Error($"CustomizeDiagnosisService-Stop error:{ex}");
  290. }
  291. }
  292. public void SetDetectTps(AIEngineInfo aiEngineInfo, int detectTps)
  293. {
  294. try
  295. {
  296. if (aiEngineInfo == null)
  297. {
  298. Logger.Error($"CustomizeDiagnosisService SetDetectTps Error: engineInfo is null");
  299. return;
  300. }
  301. var uniqueString = aiEngineInfo.GetUniqueString();
  302. var existDiagnosis = _customizeDiagnoses.FirstOrDefault(x => x.EngineInfo.GetUniqueString() == uniqueString);
  303. if (existDiagnosis == null)
  304. {
  305. Logger.Error($"CustomizeDiagnosisService SetDetectTps Error: {uniqueString} not found ");
  306. return;
  307. }
  308. if (existDiagnosis.IsInitialized)
  309. {
  310. existDiagnosis.DetectTps = detectTps;
  311. }
  312. }
  313. catch (Exception ex)
  314. {
  315. Logger.Error($"CustomizeDiagnosisService-SetDetectTps error:{ex}");
  316. }
  317. }
  318. public void SetIntervalTime(AIEngineInfo aiEngineInfo, int intervalTime)
  319. {
  320. try
  321. {
  322. if (aiEngineInfo == null)
  323. {
  324. Logger.Error($"CustomizeDiagnosisService SetIntervalTime Error: engineInfo is null");
  325. return;
  326. }
  327. var uniqueString = aiEngineInfo.GetUniqueString();
  328. var existDiagnosis = _customizeDiagnoses.FirstOrDefault(x => x.EngineInfo.GetUniqueString() == uniqueString);
  329. if (existDiagnosis == null)
  330. {
  331. Logger.Error($"CustomizeDiagnosisService SetIntervalTime Error: {uniqueString} not found ");
  332. return;
  333. }
  334. if (existDiagnosis.IsInitialized)
  335. {
  336. existDiagnosis.IntervalTime = intervalTime;
  337. }
  338. }
  339. catch (Exception ex)
  340. {
  341. Logger.Error($"CustomizeDiagnosisService-SetIntervalTime error:{ex}");
  342. }
  343. }
  344. public void SetDetectMode(AIEngineInfo aiEngineInfo, AIEnumDetectMode detectMode)
  345. {
  346. try
  347. {
  348. if (aiEngineInfo == null)
  349. {
  350. Logger.Error($"CustomizeDiagnosisService SetDetectMode Error: engineInfo is null");
  351. return;
  352. }
  353. var uniqueString = aiEngineInfo.GetUniqueString();
  354. var existDiagnosis = _customizeDiagnoses.FirstOrDefault(x => x.EngineInfo.GetUniqueString() == uniqueString);
  355. if (existDiagnosis == null)
  356. {
  357. Logger.Error($"CustomizeDiagnosisService SetDetectMode Error: {uniqueString} not found ");
  358. return;
  359. }
  360. if (existDiagnosis.IsInitialized)
  361. {
  362. existDiagnosis.DetectMode = (EnumDetectMode)detectMode; ;
  363. }
  364. }
  365. catch (Exception ex)
  366. {
  367. Logger.Error($"CustomizeDiagnosisService-SetDetectMode error:{ex}");
  368. }
  369. }
  370. public void Close(AIEngineInfo aiEngineInfo)
  371. {
  372. try
  373. {
  374. if (aiEngineInfo == null)
  375. {
  376. Logger.Error($"CustomizeDiagnosisService Close Error: engineInfo is null");
  377. return;
  378. }
  379. Logger.Info($"CustomizeDiagnosis-Close Invoke {aiEngineInfo.GetUniqueString()}");
  380. var uniqueString = aiEngineInfo.GetUniqueString();
  381. var existDiagnosis = _customizeDiagnoses.FirstOrDefault(x => x.EngineInfo.GetUniqueString() == uniqueString);
  382. if (existDiagnosis == null)
  383. {
  384. Logger.Error($"CustomizeDiagnosisService Close Error: {uniqueString} not found ");
  385. return;
  386. }
  387. existDiagnosis.NotifyLog -= OnNotifyLog;
  388. existDiagnosis.Close();
  389. }
  390. catch (Exception ex)
  391. {
  392. Logger.Error($"CustomizeDiagnosis-Close error:{ex}");
  393. }
  394. }
  395. public void CloseAllEngines()
  396. {
  397. try
  398. {
  399. Logger.Info($"CustomizeDiagnosis-CloseAllEngines Invoke");
  400. foreach (var customizeDiagnosis in _customizeDiagnoses)
  401. {
  402. CloseDiagnosis(customizeDiagnosis);
  403. }
  404. }
  405. catch (Exception ex)
  406. {
  407. Logger.Error($"CustomizeDiagnosis-Close error:{ex}");
  408. }
  409. }
  410. private void CloseDiagnosis(CustomizeDiagnosis customizeDiagnosis)
  411. {
  412. customizeDiagnosis.StartEvaluation -= OnStartEvaluation;
  413. customizeDiagnosis.FinishEvaluation -= OnFinishEvaluation;
  414. customizeDiagnosis.NotifyLog -= OnNotifyLog;
  415. customizeDiagnosis.Close();
  416. }
  417. public void Dispose()
  418. {
  419. try
  420. {
  421. if (!_disposed)
  422. {
  423. Logger.Info($"CustomizeDiagnosis-Start Dispose");
  424. CloseAllEngines();
  425. foreach (var pipeKey in _singleImagePipeServerList.Keys.ToArray())
  426. {
  427. if (_singleImagePipeServerList.TryRemove(pipeKey, out var pipeServer))
  428. {
  429. pipeServer.DataReceived -= OnDataReceived;
  430. pipeServer.Dispose();
  431. pipeServer.LogMsgThrow -= OnLogMsgThrow;
  432. pipeServer = null;
  433. }
  434. }
  435. _singleImagePipeServerList.Clear();
  436. foreach (var key in _imageProviderList.Keys.ToArray())
  437. {
  438. if (_imageProviderList.TryRemove(key, out var imageProvider))
  439. {
  440. imageProvider.Dispose();
  441. imageProvider = null;
  442. }
  443. }
  444. _imageProviderList.Clear();
  445. _disposed = true;
  446. Logger.Info($"CustomizeDiagnosis Dispose End");
  447. }
  448. }
  449. catch (Exception ex)
  450. {
  451. Logger.Error($"CustomizeDiagnosis-Dispose error:{ex}");
  452. }
  453. }
  454. private void OnNotifyLog(object sender, LogEventArgs e)
  455. {
  456. if (e == null)
  457. {
  458. return;
  459. }
  460. switch (e.LogType)
  461. {
  462. case EnumLogType.InfoLog:
  463. Logger.Info($"CustomizeDiagnosis OnNotifyLog:{e.Msg}");
  464. break;
  465. case EnumLogType.WarnLog:
  466. Logger.Warning($"CustomizeDiagnosis OnNotifyLog:{e.Msg}");
  467. break;
  468. case EnumLogType.ErrorLog:
  469. case EnumLogType.FatalLog:
  470. default:
  471. Logger.Error($"CustomizeDiagnosis OnNotifyLog:{e.Msg}");
  472. break;
  473. }
  474. var logEventArgs = AICommonServiceConvertHelperV2.ConvertLogEventArgsToAILogEventArgs(e);
  475. NotificationSender.SendNotification(new AINotificationArgs() { NotificationType = AIEnumNotificationType.CustomizeDiagnosisNotifyLogRaised, Params = logEventArgs });
  476. }
  477. private void OnLogMsgThrow(object sender, AILogEventArgs e)
  478. {
  479. if (e == null)
  480. {
  481. return;
  482. }
  483. switch (e.LogType)
  484. {
  485. case AIEnumLogType.ErrorLog:
  486. case AIEnumLogType.FatalLog:
  487. Logger.Error(e.Msg);
  488. break;
  489. case AIEnumLogType.WarnLog:
  490. Logger.Warning(e.Msg);
  491. break;
  492. case AIEnumLogType.InfoLog:
  493. default:
  494. Logger.Info(e.Msg);
  495. break;
  496. }
  497. }
  498. private void OnDataReceived(object sender, byte[] e)
  499. {
  500. try
  501. {
  502. var pipeServer = (PipeServer)sender;
  503. if (_singleImageCacheList.ContainsKey(pipeServer.PipeName))
  504. {
  505. _singleImageCacheList[pipeServer.PipeName].Push(e);
  506. }
  507. }
  508. catch (Exception ex)
  509. {
  510. Logger.Error($"CustomizeDiagnosis-OnDataReceived error:{ex}");
  511. }
  512. }
  513. public void SendImageData(AIEngineInfo aiEngineInfo, int height, int width, AIEnumColorType colorType, AIImageDataId continuityExtraInfo, AIImageExtraInfo measuringScaleExtraInfo, AICustomizeUltrasoundImageRegionInfo ultrasoundImageRegion)
  514. {
  515. if (aiEngineInfo == null)
  516. {
  517. Logger.Error($"CustomizeDiagnosisService SendImageData Error: engineInfo is null");
  518. return;
  519. }
  520. var uniqueString = aiEngineInfo.GetUniqueString();
  521. if (_imageProviderList.ContainsKey(uniqueString))
  522. {
  523. _imageProviderList[aiEngineInfo.GetUniqueString()].ReceiveImageData(height, width, colorType, continuityExtraInfo, measuringScaleExtraInfo, ultrasoundImageRegion);
  524. }
  525. }
  526. private void OnStartEvaluation(object sender, EventArgs e)
  527. {
  528. var diagnosis = (CustomizeDiagnosis)sender;
  529. var aiEngineInfo = AIConvertHelper.ConvertEngineInfoToAIEngineInfo(diagnosis.EngineInfo, true);
  530. NotificationSender.SendNotification(new AINotificationArgs() { NotificationType = AIEnumNotificationType.CustomizeDiagnosisStartEvaluationRaised, Params = aiEngineInfo });
  531. }
  532. private void OnFinishEvaluation(object sender, IDetectedObject[] e)
  533. {
  534. var result = AIConvertHelper.ConvertIDetectedObjectArrayToAICustomizeDetectedObjectInfoArray(e);
  535. var diagnosis = (CustomizeDiagnosis)sender;
  536. var aiEngineInfo = AIConvertHelper.ConvertEngineInfoToAIEngineInfo(diagnosis.EngineInfo, true);
  537. NotificationSender.SendNotification(new AINotificationArgs() { NotificationType = AIEnumNotificationType.CustomizeDiagnosisFinishEvaluationRaised, Params = new TransAICustomizeDetectedObjectInfo(aiEngineInfo, result) });
  538. }
  539. }
  540. }