版博士V2.0程序
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

DefectLib.cs 19 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Drawing;
  5. using System.Drawing.Imaging;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Reflection;
  9. using System.Threading;
  10. using System.Threading.Tasks;
  11. using Microsoft.ML.OnnxRuntime;
  12. using Microsoft.ML.OnnxRuntime.Tensors;
  13. using OpenCvSharp;
  14. using Yolo5;
  15. namespace ProductionControl.Device
  16. {
  17. public class DefectLib : IDisposable
  18. {
  19. public Action<WarningEnum, string> WarningEvent;
  20. /// <summary>
  21. /// 检测结果JSON(原图,结果)
  22. /// </summary>
  23. public Action<DefectTask> finishEvent;
  24. /// <summary>
  25. /// 是否打开设备成功
  26. /// </summary>
  27. public bool IsInit { get; private set; } = false;
  28. //private System.Timers.Timer timer = new System.Timers.Timer();
  29. private Yolo_Class yolo1;
  30. private InferenceSession _onnxSession;
  31. //
  32. private Thread t_task, t_task_operation, t_task_operation2, t_task_tag;
  33. //=======task list
  34. private List<DefectTask> taskList = new List<DefectTask>();
  35. private List<DefectTask> taskOperationList = new List<DefectTask>();
  36. private List<DefectTask> taskTagList = new List<DefectTask>();
  37. public DefectLib()
  38. {
  39. }
  40. public bool start()
  41. {
  42. try
  43. {
  44. yolo1 = new Yolo_Class();
  45. //加载模型(只加载一次即可)
  46. //string modelFilePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\DevCfg\\best.onnx";
  47. //_onnxSession = yolo1.LoadModel(modelFilePath, true);//false-CPU true-显卡
  48. IsInit = true;
  49. //timer.Elapsed += Timer_Elapsed;
  50. //timer.Interval = 100;
  51. //timer.Enabled = true;
  52. taskList.Clear();
  53. taskOperationList.Clear();
  54. taskTagList.Clear();
  55. t_task = new System.Threading.Thread(runStep);
  56. t_task.IsBackground = true;
  57. t_task.Start();
  58. t_task_operation = new System.Threading.Thread(run2);
  59. t_task_operation.IsBackground = true;
  60. t_task_operation.Start();
  61. t_task_operation2 = new System.Threading.Thread(run2);
  62. t_task_operation2.IsBackground = true;
  63. t_task_operation2.Start();
  64. //t_task_tag = new System.Threading.Thread(run3);
  65. //t_task_tag.IsBackground = true;
  66. //t_task_tag.Start();
  67. return true;
  68. }
  69. catch (Exception ex)
  70. {
  71. WarningEvent?.Invoke(WarningEnum.High, ex.Message);
  72. return false;
  73. }
  74. }
  75. public void stop()
  76. {
  77. if (!IsInit) return;
  78. try
  79. {
  80. IsInit = false;
  81. //timer.Elapsed -= Timer_Elapsed;
  82. //释放模型
  83. if (_onnxSession != null)
  84. {
  85. _onnxSession.Dispose();
  86. _onnxSession = null;
  87. }
  88. _preLoadONNXFilePath = null;
  89. if (t_task != null)
  90. {
  91. bool b = t_task.Join(5000);
  92. if (!b) t_task.Abort();
  93. t_task = null;
  94. }
  95. if (t_task_operation != null)
  96. {
  97. bool b = t_task_operation.Join(5000);
  98. if (!b) t_task_operation.Abort();
  99. t_task_operation = null;
  100. }
  101. if (t_task_operation2 != null)
  102. {
  103. bool b = t_task_operation2.Join(5000);
  104. if (!b) t_task_operation2.Abort();
  105. t_task_operation2 = null;
  106. }
  107. if (t_task_tag != null)
  108. {
  109. bool b = t_task_tag.Join(5000);
  110. if (!b) t_task_tag.Abort();
  111. t_task_tag = null;
  112. }
  113. taskList.Clear();
  114. taskOperationList.Clear();
  115. taskTagList.Clear();
  116. }
  117. catch { }
  118. }
  119. private string _preLoadONNXFilePath;//记录上次成功加载的模型,不重复加载
  120. public void loadModelFile(string onnxFilePath)
  121. {
  122. //string modelFilePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\DevCfg\\best.onnx";
  123. //不重复加载
  124. if (!string.IsNullOrWhiteSpace(_preLoadONNXFilePath) && _preLoadONNXFilePath.ToLower() == onnxFilePath.ToLower())
  125. return;
  126. Task.Run(async () =>
  127. {
  128. if (_onnxSession != null)
  129. {
  130. _onnxSession.Dispose();
  131. _onnxSession = null;
  132. }
  133. _onnxSession = yolo1.LoadModel(onnxFilePath, true);//false-CPU true-显卡
  134. _preLoadONNXFilePath = onnxFilePath;
  135. });
  136. }
  137. /// <summary>
  138. /// 保存图片
  139. /// </summary>
  140. /// <param name="Img"></param>图片
  141. /// <param name="pictureUrl"></param>保存路径
  142. /// <param name="pictureName"></param>保存名称
  143. private void SaveImage(Bitmap Img, string pictureUrl, string pictureName)
  144. {
  145. if (!Directory.Exists(pictureUrl))
  146. {
  147. Directory.CreateDirectory(pictureUrl);
  148. }
  149. FileInfo FileUrl = new FileInfo(pictureUrl);//防止路径中有日期导致路径错误
  150. try
  151. {
  152. using (Bitmap bitmap = new Bitmap(Img))
  153. {
  154. using (MemoryStream stream = new MemoryStream())
  155. {
  156. bitmap.Save(stream, ImageFormat.Bmp);
  157. System.Drawing.Image img = System.Drawing.Image.FromStream(stream);
  158. //img.Save(FileUrl +"\\"+ pictureName);
  159. //img.Dispose();
  160. string szURL = FileUrl + "\\" + pictureName;
  161. img.Save(szURL, ImageFormat.Bmp);
  162. img.Dispose();
  163. }
  164. }
  165. }
  166. catch (Exception)
  167. {
  168. if (Img != null)
  169. {
  170. Img.Dispose();
  171. }
  172. }
  173. }
  174. private void runStep()
  175. {
  176. while (IsInit)
  177. {
  178. if (taskList.Count < 1 || _onnxSession == null)
  179. {
  180. Thread.Sleep(5);
  181. continue;
  182. }
  183. //
  184. var task = pop();
  185. try
  186. {
  187. if (task != null)
  188. {
  189. Stopwatch stopwatch = Stopwatch.StartNew();
  190. //源图
  191. //Bitmap bmp = yolo1.Read2Bmp(file_path);
  192. //切割图像,输入图像格式14208*10640
  193. stopwatch.Start();
  194. task.bmps_cut = yolo1.OpenCVToCutsMat(task.bmp, task.cut_size.Width, task.cut_size.Height);
  195. stopwatch.Stop();
  196. task.stopwatch[0] = stopwatch.ElapsedMilliseconds;
  197. //Resize图像
  198. stopwatch.Restart();
  199. task.bmps_resize = yolo1.OpenCVToResizesMat(task.bmps_cut, task.resize.Width, task.resize.Height);
  200. stopwatch.Stop();
  201. task.stopwatch[1] = stopwatch.ElapsedMilliseconds;
  202. //预处理模型
  203. stopwatch.Restart();
  204. task.tensors = yolo1.PreprocessImageMat(task.bmps_resize);
  205. stopwatch.Stop();
  206. task.stopwatch[2] = stopwatch.ElapsedMilliseconds;
  207. lock (taskOperationList)
  208. taskOperationList.Add(task);
  209. }
  210. Thread.Sleep(5);
  211. }
  212. catch (Exception ex)
  213. {
  214. WarningEvent?.Invoke(WarningEnum.Low, "DefectLib task1 err:" + ex.Message);
  215. task.isSucceed = false;
  216. task.resultInfo = ex.Message;
  217. callback(task);
  218. }
  219. }
  220. }
  221. private void run2()
  222. {
  223. while (IsInit)
  224. {
  225. if (taskOperationList.Count < 1)
  226. {
  227. Thread.Sleep(5);
  228. continue;
  229. }
  230. //
  231. var task = pop2();
  232. int liStep = 0;
  233. try
  234. {
  235. if (task != null)
  236. {
  237. Stopwatch stopwatch = Stopwatch.StartNew();
  238. //====运行推理(必需单队列)
  239. stopwatch.Start();
  240. IDisposableReadOnlyCollection<DisposableNamedOnnxValue>[] results = yolo1.RunModlel(_onnxSession, task.tensors);
  241. liStep = 1;
  242. task.informationList = yolo1.ScreeningResults_YD(results, task.bmps_resize, task.thresholds, task.thresholdsClass, task.recAreaThreshold);
  243. liStep = 2;
  244. //当前大图上缺陷个数
  245. int currPicDefectCount = 0;
  246. for (int x = 0; x < task.informationList.Count(); x++)
  247. currPicDefectCount += task.informationList[x].Count();
  248. task.defectCount = currPicDefectCount;
  249. stopwatch.Stop();
  250. task.stopwatch[3] = stopwatch.ElapsedMilliseconds;
  251. liStep = 3;
  252. if (task.informationList.Count > 0)
  253. {
  254. liStep = 4;
  255. //lock (taskTagList)
  256. // taskTagList.Add(task);
  257. //====打标 ,有缺陷返回缺陷图片数组,没缺陷返回所有图片数组
  258. stopwatch.Restart();
  259. task.bmps_tag = yolo1.DrawYoloPrediction2Mat(task.bmps_cut, task.informationList, 27, SixLabors.ImageSharp.Color.OrangeRed, task.resize.Width,
  260. task.Xmm, task.Ymm, out task.defectInfor2RestorationDesk);
  261. liStep = 5;
  262. if (Config.OpenFlawDistribution)
  263. {
  264. //大图缺陷坐标转换到图纸坐标
  265. if (!string.IsNullOrWhiteSpace(task.drawingPagePath) && task.defectInfor2RestorationDesk != null && task.defectInfor2RestorationDesk.Count > 0)
  266. task.defectInfor2RestorationDeskPage = yolo1.DefectDrawGerberImage(task.drawingPagePath, task.defectInfor2RestorationDesk);
  267. }
  268. stopwatch.Stop();
  269. task.stopwatch[4] = stopwatch.ElapsedMilliseconds;
  270. liStep = 6;
  271. task.bmpCompress = yolo1.ResizesMat_4(task.bmp);
  272. task.isSucceed = true;
  273. callback(task);
  274. }
  275. else
  276. {
  277. task.isSucceed = true;
  278. callback(task);
  279. }
  280. }
  281. Thread.Sleep(5);
  282. }
  283. catch (Exception ex)
  284. {
  285. WarningEvent?.Invoke(WarningEnum.Low, $"DefectLib task2 err({liStep}):" + ex.Message);
  286. task.isSucceed = false;
  287. task.resultInfo = ex.Message;
  288. callback(task);
  289. }
  290. }
  291. }
  292. /// <summary>
  293. /// 已不用
  294. /// </summary>
  295. private void run3()
  296. {
  297. while (IsInit)
  298. {
  299. if (taskTagList.Count < 1)
  300. {
  301. Thread.Sleep(0);
  302. continue;
  303. }
  304. //
  305. var task = pop3();
  306. try
  307. {
  308. if (task != null)
  309. {
  310. Stopwatch stopwatch = Stopwatch.StartNew();
  311. //====打标 ,有缺陷返回缺陷图片数组,没缺陷返回所有图片数组
  312. stopwatch.Start();
  313. task.bmps_tag = yolo1.DrawYoloPrediction2Mat(task.bmps_cut, task.informationList, 27, SixLabors.ImageSharp.Color.OrangeRed, task.resize.Width,
  314. task.Xmm,task.Ymm,out task.defectInfor2RestorationDesk);
  315. stopwatch.Stop();
  316. task.stopwatch[4] = stopwatch.ElapsedMilliseconds;
  317. task.isSucceed = true;
  318. callback(task);
  319. }
  320. }
  321. catch (Exception ex)
  322. {
  323. WarningEvent?.Invoke(WarningEnum.Low, "DefectLib task3 err:" + ex.Message);
  324. task.isSucceed = false;
  325. task.resultInfo = ex.Message;
  326. callback(task);
  327. }
  328. }
  329. }
  330. private void callback(DefectTask task)
  331. {
  332. //返回成功/失败,异步调用
  333. if (task.finishEvent != null || (task.finishEvent = finishEvent) != null)
  334. //task.finishEvent.BeginInvoke(result, errInfo, res => task.finishEvent.EndInvoke(res), null);
  335. System.Threading.ThreadPool.QueueUserWorkItem(waitCallback, task);
  336. }
  337. //异步回调
  338. WaitCallback waitCallback = new WaitCallback(o =>
  339. {
  340. var task = (DefectTask)o;
  341. task.finishEvent(task);
  342. });
  343. public class DefectTask
  344. {
  345. public int stepIndex;
  346. public string processName;
  347. public string drawingPagePath;//图纸路径bmp
  348. //图索引
  349. public int index = 0;
  350. /// <summary>
  351. /// 绝对位置-----X2轴
  352. /// </summary>
  353. public double Xmm;
  354. /// <summary>
  355. /// 绝对位置-----Y轴
  356. /// </summary>
  357. public double Ymm;
  358. /// <summary>
  359. /// 源文件
  360. /// </summary>
  361. public Mat bmp;
  362. public Mat bmpCompress;//压缩有缺陷大图
  363. public System.Drawing.Size cut_size = new System.Drawing.Size(592, 532);
  364. public System.Drawing.Size resize = new System.Drawing.Size(224, 224);
  365. /// <summary>
  366. /// 阈值
  367. /// </summary>
  368. public float thresholds = 0.4f;
  369. /// <summary>
  370. /// 种类阈值
  371. /// </summary>
  372. public string thresholdsClass;
  373. /// <summary>
  374. /// 缺陷在面积内数量
  375. /// </summary>
  376. public Dictionary<string, float> recAreaThreshold;
  377. /// <summary>
  378. /// 完成后回调
  379. /// </summary>
  380. public Action<DefectTask> finishEvent;
  381. //
  382. public long createTime = DateTime.Now.Ticks;
  383. public DateTime nowTime;
  384. //中间变量,供step2使用
  385. public Mat[] bmps_cut;
  386. public Mat[] bmps_resize;
  387. //预处理模型
  388. public Tensor<float>[] tensors;
  389. //==结果返回
  390. public List<Dictionary<int, List<string>[]>> informationList;
  391. public int defectCount;//informationList中的缺陷数
  392. public List<List<string>> defectInfor2RestorationDesk, defectInfor2RestorationDeskPage;//打标缺陷转为图纸的坐标
  393. public Bitmap[] bmps_tag; //打标小图 //bmps_tag.count<=bmps_cut.count bmps_tag.count=informationList.count
  394. public bool isSucceed;//转换是否成功
  395. public string resultInfo = "";//成功或失败信息
  396. public long[] stopwatch = new long[5];
  397. }
  398. public void add(DefectTask task)
  399. {
  400. lock (taskList)
  401. taskList.Add(task);
  402. }
  403. /// <summary>
  404. /// 打标 返回每张图的绝对位置X,Y
  405. /// </summary>
  406. /// <param name="defectBmpIndex">缺陷小图索引</param>
  407. /// <param name="X">拍照位绝对位置-----X2轴</param>
  408. /// <param name="Y">拍照位绝对位置-----Y轴</param>
  409. /// <param name="imagewidth">裁剪小图的宽592</param>
  410. /// <param name="imageheight">裁剪小图的高532</param>
  411. public List<double> makeTag(int defectBmpIndex, double X, double Y, int imagewidth, int imageheight)
  412. {
  413. return yolo1.ImageXY(defectBmpIndex, X, Y, imagewidth, imageheight);
  414. }
  415. /// <summary>
  416. /// 用相机1查看缺陷点
  417. /// </summary>
  418. /// <param name="defectBmpIndex"></param>
  419. /// <param name="X"></param>
  420. /// <param name="Y"></param>
  421. /// <param name="imagewidth"></param>
  422. /// <param name="imageheight"></param>
  423. /// <returns></returns>
  424. public List<double> viewTag(int defectBmpIndex, double X, double Y, int imagewidth, int imageheight)
  425. {
  426. return yolo1.ImageXY2(defectBmpIndex, X, Y, imagewidth, imageheight);
  427. }
  428. private DefectTask pop()
  429. {
  430. lock (taskList)
  431. {
  432. if (taskList.Count < 1)
  433. return null;
  434. //int index = 0;// taskList.FindIndex(p => { return p.isSync; });
  435. //if (index < 0) index = 0;
  436. var task = taskList[0];
  437. taskList.RemoveAt(0);
  438. return task;
  439. }
  440. }
  441. private DefectTask pop2()
  442. {
  443. lock (taskOperationList)
  444. {
  445. if (taskOperationList.Count < 1)
  446. return null;
  447. //int index = 0;// taskList.FindIndex(p => { return p.isSync; });
  448. //if (index < 0) index = 0;
  449. var task = taskOperationList[0];
  450. taskOperationList.RemoveAt(0);
  451. return task;
  452. }
  453. }
  454. private DefectTask pop3()
  455. {
  456. lock (taskTagList)
  457. {
  458. if (taskTagList.Count < 1)
  459. return null;
  460. //int index = 0;// taskList.FindIndex(p => { return p.isSync; });
  461. //if (index < 0) index = 0;
  462. var task = taskTagList[0];
  463. taskTagList.RemoveAt(0);
  464. return task;
  465. }
  466. }
  467. public void Dispose()
  468. {
  469. stop();
  470. }
  471. }
  472. }