革博士V2程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1421 lines
73 KiB

  1. //#define Online_One
  2. using CCWin.Win32.Const;
  3. using DocumentFormat.OpenXml.Office2010.ExcelAc;
  4. using DocumentFormat.OpenXml.Office2021.DocumentTasks;
  5. using DocumentFormat.OpenXml.Spreadsheet;
  6. //using DocumentFormat.OpenXml.Drawing.Charts;
  7. using GeBoShi.SysCtrl;
  8. using HalconDotNet;
  9. using HZH_Controls;
  10. using HZH_Controls.Controls;
  11. using MaiMuControl.Device;
  12. using MaiMuControl.Device.CamDev;
  13. using Models;
  14. using OpenCvSharp;
  15. using PG_Detect;
  16. using S7.Net.Types;
  17. using System;
  18. using System.Collections.Generic;
  19. using System.Data;
  20. using System.Diagnostics;
  21. using System.Linq;
  22. using System.Reflection;
  23. using System.Runtime.InteropServices;
  24. using System.Text;
  25. using System.Threading;
  26. using System.Threading.Tasks;
  27. using static System.ComponentModel.Design.ObjectSelectorEditor;
  28. namespace GeBoShi.ImageDefect
  29. {
  30. public class DefectLib
  31. {
  32. #region C++dll
  33. private const string dll_path = "yolo_trt.dll";
  34. [DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
  35. static extern IntPtr CreateDetector(string model_path);
  36. [DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
  37. extern static bool DestroyDetector(IntPtr detector);
  38. /// <summary>
  39. /// 非0值表示成功,0表示失败 返回小图张数
  40. /// </summary>
  41. /// <param name="detector"></param>
  42. /// <returns></returns>
  43. [DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
  44. static extern int GetBatchSize(IntPtr detector);
  45. [DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
  46. static extern bool Detect(IntPtr detector, ref byte bgrs_data,
  47. int image_num, int width, int height, int channels,
  48. float conf_threshold, float iou_threshold,
  49. ref float output, int output_size, ref int object_num,
  50. int expand_pixel);
  51. #endregion
  52. public Action<WarningEnum, string> WarningEvent;
  53. /// <summary>
  54. /// 检测结果JSON(原图,结果)
  55. /// </summary>
  56. public Action<DefectTask> finishEvent;
  57. /// <summary>
  58. /// 是否打开设备成功
  59. /// </summary>
  60. public bool IsInit { get; private set; } = false;
  61. private IntPtr detector = IntPtr.Zero;
  62. private Thread t_task, t_task_operation, t_task_maketag, t_task_defectover;
  63. //=======task list
  64. private List<DefectTask> taskList = new List<DefectTask>();
  65. private List<DefectTask> taskOperationList = new List<DefectTask>();
  66. private List<DefectTask> taskMakeTagList = new List<DefectTask>();
  67. private List<DefectTask> taskDefectOverList = new List<DefectTask>();
  68. private string preModelName = "";
  69. //传统算法核心
  70. private PGDetect tPGDetect = new PGDetect();
  71. #region 图片处理参数
  72. private readonly int image_width = 2048;
  73. private readonly int image_hight = 2048;
  74. private readonly int image_channels = 3;
  75. private readonly int image_bytes = 2048 * 2048 * 3;
  76. private readonly int detect_elem_size = 7; //维度数据结果,x y w h conf classid
  77. private readonly int detect_max_object_num = 20;//这个指的是一张子图可能最多给你返回的目标个球
  78. public Action<int, int> QueueCountEvent;//0/1/2, 数量
  79. #endregion
  80. public DefectLib()
  81. {
  82. }
  83. public bool start()
  84. {
  85. try
  86. {
  87. //detector = CreateDetector(Config.model_path, Config.labels_path, true, 6);
  88. //if (detector == IntPtr.Zero)
  89. // throw new Exception("模型初始化失败!");
  90. preModelName = "";
  91. IsInit = true;
  92. taskList.Clear();
  93. taskOperationList.Clear();
  94. taskMakeTagList.Clear();
  95. #if Online_One
  96. t_task = new System.Threading.Thread(run);
  97. t_task.IsBackground = true;
  98. t_task.Start();
  99. #else
  100. t_task = new System.Threading.Thread(runStep);
  101. t_task.IsBackground = true;
  102. t_task.Start();
  103. t_task_operation = new System.Threading.Thread(run2);
  104. t_task_operation.IsBackground = true;
  105. t_task_operation.Start();
  106. t_task_maketag = new System.Threading.Thread(run3);
  107. t_task_maketag.IsBackground = true;
  108. t_task_maketag.Start();
  109. //t_task_defectover = new System.Threading.Thread(run4);
  110. //t_task_defectover.IsBackground = true;
  111. //t_task_defectover.Start();
  112. #endif
  113. return true;
  114. }
  115. catch (Exception ex)
  116. {
  117. WarningEvent?.Invoke(WarningEnum.High, ex.Message);
  118. return false;
  119. }
  120. }
  121. public void stop()
  122. {
  123. if (!IsInit) return;
  124. try
  125. {
  126. IsInit = false;
  127. //timer.Elapsed -= Timer_Elapsed;
  128. preModelName = "";
  129. //释放模型
  130. if (detector != IntPtr.Zero)
  131. {
  132. DestroyDetector(detector);
  133. detector = IntPtr.Zero;
  134. }
  135. if (t_task != null)
  136. {
  137. bool b = t_task.Join(5000);
  138. if (!b) t_task.Abort();
  139. t_task = null;
  140. }
  141. if (t_task_operation != null)
  142. {
  143. bool b = t_task_operation.Join(5000);
  144. if (!b) t_task_operation.Abort();
  145. t_task_operation = null;
  146. }
  147. if (t_task_maketag != null)
  148. {
  149. bool b = t_task_maketag.Join(5000);
  150. if (!b) t_task_maketag.Abort();
  151. t_task_maketag = null;
  152. }
  153. //if (t_task_defectover != null)
  154. //{
  155. // bool b = t_task_defectover.Join(5000);
  156. // if (!b) t_task_defectover.Abort();
  157. // t_task_defectover = null;
  158. //}
  159. taskList.Clear();
  160. taskOperationList.Clear();
  161. taskMakeTagList.Clear();
  162. taskDefectOverList.Clear();
  163. }
  164. catch { }
  165. }
  166. /// <summary>
  167. /// 切割(先左右,后上下)
  168. /// </summary>
  169. /// <param name="mat"></param>
  170. /// <param name="width"></param>
  171. /// <param name="height"></param>
  172. /// <returns></returns>
  173. private Mat[] OpenCVToCutsMat(Mat mat, int width, int height)
  174. {
  175. Mat[] array = new Mat[mat.Width / width * mat.Height / height];
  176. int num = 0;
  177. for (int i = 0; i < mat.Height / height; i++)
  178. {
  179. for (int j = 0; j < mat.Width / width; j++)
  180. {
  181. int x = j * width;
  182. int y = i * height;
  183. System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle(x, y, width, height);
  184. Rect roi = new Rect(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
  185. array[num] = new Mat(mat, roi).Clone();
  186. num++;
  187. }
  188. }
  189. return array;
  190. }
  191. public static string ToGB2312(int codepage, string str)
  192. {
  193. try
  194. {
  195. Encoding cp850 = Encoding.GetEncoding(codepage);
  196. Encoding gb2312 = Encoding.GetEncoding("gb2312");//Encoding.Default ,936
  197. byte[] temp = cp850.GetBytes(str);
  198. return Encoding.GetEncoding("gb2312").GetString(temp, 0, temp.Length);
  199. }
  200. catch (Exception ex)//(UnsupportedEncodingException ex)
  201. {
  202. Console.Write(ex.Message);
  203. return null;
  204. }
  205. }
  206. public bool LoadModel(ImageDefectType itype, string modelPath)
  207. {
  208. int step = 0;
  209. try
  210. {
  211. if (itype == ImageDefectType.Yolo)
  212. {
  213. if (preModelName != modelPath)
  214. {
  215. step = 3;
  216. //先释放模型
  217. if (detector != IntPtr.Zero)
  218. {
  219. step = 4;
  220. DestroyDetector(detector);
  221. detector = IntPtr.Zero;
  222. }
  223. step = 5;
  224. //string modelPath = $"{ConfMgr.Instance.SysConfigParams.AIModelPath}\\{task.modelName}";
  225. string tmodelPath = $".\\ConfigFiles\\Models\\{modelPath}";
  226. detector = CreateDetector(tmodelPath);
  227. if (detector == IntPtr.Zero)
  228. throw new Exception($"模型({modelPath})初始化失败!");
  229. step = 6;
  230. preModelName = modelPath;
  231. }
  232. }
  233. else if(itype == ImageDefectType.Anomalib)
  234. {
  235. return false;
  236. }
  237. else if (itype == ImageDefectType.Def)
  238. {
  239. HObject obj = new HObject();
  240. Mat mat = new Mat($"{ConfMgr.Instance.ConfigDir}\\init.bmp");
  241. OpencvUtils.MatToHObject(mat, out obj);
  242. //HOperatorSet.GenImageConst(out obj, "byte", 2048 * 8, 2048 * 2);//生成一幅图像,用byte格式,默认是黑色
  243. //Mat initMat = new Mat(2048 * 2, 2048 * 8, MatType.CV_8UC3);
  244. if(!tPGDetect.IniOptimization(obj, ConfMgr.Instance.SysConfigParams.HalconDataPath))
  245. throw new Exception($"传统算法({ConfMgr.Instance.SysConfigParams.HalconDataPath})初始化失败!");
  246. }
  247. else
  248. return false;
  249. return true;
  250. }
  251. catch (Exception e)
  252. {
  253. WarningEvent?.Invoke(WarningEnum.Low, $"Load Model-{itype} err({step}):" + e.Message);
  254. return false;
  255. }
  256. }
  257. private void runStep()
  258. {
  259. int step = 0;
  260. while (IsInit)
  261. {
  262. if (taskList.Count < 1)
  263. {
  264. Thread.Sleep(25);
  265. continue;
  266. }
  267. //
  268. step = 1;
  269. var task = pop();
  270. try
  271. {
  272. if (task != null)
  273. {
  274. Stopwatch stopwatch = Stopwatch.StartNew();
  275. step = 2;
  276. LoadModel(task.iType, task.modelName);
  277. #if false //封装使用
  278. if (preModelName != task.modelName)
  279. {
  280. step = 3;
  281. //先释放模型
  282. if (detector != IntPtr.Zero)
  283. {
  284. step = 4;
  285. DestroyDetector(detector);
  286. detector = IntPtr.Zero;
  287. }
  288. step = 5;
  289. //string modelPath = $"{ConfMgr.Instance.SysConfigParams.AIModelPath}\\{task.modelName}";
  290. string modelPath = $".\\ConfigFiles\\Models\\{task.modelName}";
  291. detector = CreateDetector(modelPath);
  292. if (detector == IntPtr.Zero)
  293. throw new Exception($"模型({modelPath})初始化失败!");
  294. step = 6;
  295. preModelName = task.modelName;
  296. }
  297. #endif
  298. //源图
  299. //Bitmap bmp = yolo1.Read2Bmp(file_path);
  300. //切割图像,输入图像格式14208*10640
  301. stopwatch.Start();
  302. //task.resizeBmp = OpenCVUtil.resize( task.bmp.Clone(), task.resize.Width, task.resize.Height);//在外面已做了resize
  303. if (task.iType == ImageDefectType.Yolo)
  304. {
  305. //Cv2.CvtColor(task.bmp, task.bmpBgr2rgb, ColorConversionCodes.BGR2RGB);
  306. //task.bmps_cut = OpenCVToCutsMat(task.bmpBgr2rgb, image_width, image_hight); //这里cut时之前加的clone
  307. step = 7;
  308. task.bmps_cut = OpenCVToCutsMat(task.bmp, image_width, image_hight); //这里cut时之前加的clone
  309. stopwatch.Stop();
  310. task.stopwatch[0] = stopwatch.ElapsedMilliseconds;
  311. //Resize图像
  312. //stopwatch.Restart();
  313. //task.bmps_resize = yolo1.OpenCVToResizesMat(task.bmps_cut, task.resize.Width, task.resize.Height);
  314. //stopwatch.Stop();
  315. //task.stopwatch[1] = stopwatch.ElapsedMilliseconds;
  316. //预处理模型
  317. //stopwatch.Restart();
  318. //task.tensors = yolo1.PreprocessImageMat(task.bmps_resize);
  319. //stopwatch.Stop();
  320. //task.stopwatch[2] = stopwatch.ElapsedMilliseconds;
  321. step = 8;
  322. lock (taskOperationList)
  323. {
  324. taskOperationList.Add(task);
  325. QueueCountEvent?.BeginInvoke(1, taskOperationList.Count, null, null);
  326. }
  327. step = 9;
  328. }
  329. else if (task.iType == ImageDefectType.Anomalib)
  330. {
  331. }
  332. else
  333. {
  334. step = 20;
  335. int object_num = 0;
  336. //转换
  337. OpencvUtils.MatToHObject(task.bmp, out task.ho_Img);
  338. stopwatch.Stop();
  339. task.stopwatch[0] = stopwatch.ElapsedMilliseconds;
  340. stopwatch.Restart();
  341. step = 21;
  342. //预处理
  343. tPGDetect.Processing(task.ho_Img, out task.ho_imgG, out task.ho_ImageResult3, out task.ho_ImageSub,
  344. ConfMgr.Instance.SysConfigParams.HalconDataPath,
  345. out task.hv_RES, out task.hv_gauss_filter1, out task.hv_gauss_filter2,
  346. out task.hv_Energy_value, out task.hv_Region_S_value, out task.hv_class);
  347. stopwatch.Stop();
  348. task.stopwatch[1] = stopwatch.ElapsedMilliseconds;
  349. lock (taskOperationList)
  350. {
  351. taskOperationList.Add(task);
  352. QueueCountEvent?.BeginInvoke(1, taskOperationList.Count, null, null);
  353. }
  354. }
  355. }
  356. }
  357. catch (Exception ex)
  358. {
  359. WarningEvent?.Invoke(WarningEnum.Low, $"DefectLib task1 err({step}):" + ex.Message);
  360. task.isSucceed = false;
  361. task.resultInfo = ex.Message;
  362. callback(task);
  363. }
  364. Thread.Sleep(5);
  365. }
  366. }
  367. //推理
  368. private void run2()
  369. {
  370. QualifiedLimit qualifiedLimit;
  371. while (IsInit)
  372. {
  373. if (taskOperationList.Count < 1)
  374. {
  375. Thread.Sleep(25);
  376. continue;
  377. }
  378. //
  379. var task = pop2();
  380. int cut_count = 0, step = 0;
  381. try
  382. {
  383. if (task != null && task.bmps_cut.Count() > 0 && task.iType == ImageDefectType.Yolo)
  384. {
  385. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, "DefectLib tasks 运行推理...");
  386. cut_count = task.bmps_cut.Count();
  387. Stopwatch stopwatch = Stopwatch.StartNew();
  388. //====推理(必需单队列)
  389. stopwatch.Start();
  390. // 把数据转为byte数组,【h, w, c】的bgr格式,第一张在前,第二张在后
  391. byte[] imgData = new byte[image_bytes * cut_count];
  392. for (int i = 0; i < cut_count; i++)
  393. Marshal.Copy(task.bmps_cut[i].Data, imgData, image_bytes * i, image_bytes);
  394. step = 1;
  395. stopwatch.Stop();
  396. task.stopwatch[1] = stopwatch.ElapsedMilliseconds;
  397. stopwatch.Restart();
  398. task.output = new float[cut_count * detect_elem_size * detect_max_object_num];
  399. task.output_num = new int[cut_count];
  400. //执行推理
  401. step = 2;
  402. bool ok = Detect(detector, ref imgData[0], cut_count, image_width, image_hight, image_channels,
  403. 0.25f, 0.45f, ref task.output[0], task.output.Length, ref task.output_num[0], task.expand_pixel);
  404. //bool ok = Detect(_detector, ref imgData[0], imgs.Count, ImageWidth, image_hight, image_channels,
  405. // 0.25f, 0.45f, ref output[0], output.Length, ref output_num[0]);
  406. step = 3;
  407. stopwatch.Stop();
  408. task.stopwatch[2] = stopwatch.ElapsedMilliseconds;
  409. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"DefectLib tasks 结果推理={ok}");
  410. for (int i = 0; i < cut_count; i++)
  411. task.bmps_cut[i].Dispose();
  412. if (ok == false)
  413. throw new Exception($"推理失败或者输入数组太小({cut_count})");
  414. //
  415. lock (taskMakeTagList)
  416. {
  417. taskMakeTagList.Add(task);
  418. QueueCountEvent?.BeginInvoke(2, taskMakeTagList.Count, null, null);
  419. }
  420. }
  421. else if (task.iType == ImageDefectType.Anomalib)
  422. {
  423. }
  424. else if (task.iType == ImageDefectType.Def)
  425. {
  426. Stopwatch stopwatch = Stopwatch.StartNew();
  427. stopwatch.Start();
  428. step = 22;
  429. //算法处理
  430. tPGDetect.Detect(task.ho_Img, task.ho_imgG, task.ho_ImageResult3, task.ho_ImageSub,
  431. task.hv_Energy_value, task.hv_Region_S_value, task.hv_class,
  432. out task.hv_defectinfo, out task.object_num);
  433. stopwatch.Stop();
  434. task.stopwatch[2] = stopwatch.ElapsedMilliseconds;
  435. lock (taskMakeTagList)
  436. {
  437. taskMakeTagList.Add(task);
  438. QueueCountEvent?.BeginInvoke(2, taskMakeTagList.Count, null, null);
  439. }
  440. }
  441. }
  442. catch (Exception ex)
  443. {
  444. WarningEvent?.Invoke(WarningEnum.Low, $"DefectLib task2 err({step}):({cut_count}){ex.Message}");
  445. task.isSucceed = false;
  446. task.resultInfo = ex.Message;
  447. callback(task);
  448. }
  449. Thread.Sleep(5);
  450. }
  451. }
  452. //打标
  453. private void run3()
  454. {
  455. QualifiedLimit qualifiedLimit;
  456. while (IsInit)
  457. {
  458. if (taskMakeTagList.Count < 1)
  459. {
  460. Thread.Sleep(25);
  461. continue;
  462. }
  463. //
  464. var task = pop3();
  465. int liStep = 0;
  466. try
  467. {
  468. Stopwatch stopwatch = Stopwatch.StartNew();
  469. stopwatch.Restart();
  470. int cut_count = task.bmps_cut.Count();//上面bmps_cut已销毁
  471. int colNum = task.bmp.Width / image_width;
  472. int rowNum = task.bmp.Height / image_hight;
  473. int count = 0;
  474. liStep = 3;
  475. if (task.iType == ImageDefectType.Yolo)
  476. {
  477. //车用革去除接头处横档误判
  478. bool haveJieTou = false;
  479. List<DefectLabelInfo> DefectLabelInfoList = new List<DefectLabelInfo>();
  480. for (int i = 0; i < cut_count; i++)
  481. {
  482. liStep = i * 100;
  483. task.resultInfo += $"第 {i}/{cut_count} 张小图(大图索引{task.photoIndex}): 缺陷数 = {task.output_num[i]}-{task.output.Length}\n";
  484. //task.resultInfo +=$"大图({task.tag})[{task.bmp.Width}*{task.bmp.Height}],第 {i + 1}/{cut_count} 张小图[{task.bmps_cut[i].Width}*{task.bmps_cut[i].Height}]: 瑕疵output_num = {output_num[i]}\n";
  485. #region 检测信息汇总
  486. for (int j = 0; j < task.output_num[i]; j++)//缺陷数
  487. {
  488. liStep += j + 10000;//0
  489. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"-------");
  490. int index = count * detect_elem_size;
  491. // 打印输出信息(示例代码,根据实际情况进行修改和格式化)
  492. // 获取输出信息
  493. int x = (int)task.output[index];
  494. int y = (int)task.output[index + 1];
  495. int w = (int)task.output[index + 2];
  496. int h = (int)task.output[index + 3];
  497. int classId = (int)task.output[index + 4];
  498. double confidence = Math.Round(task.output[index + 5], 2); //置信度
  499. double contrast = Math.Round(task.output[index + 6], 3);//对比度
  500. //y = image_hight-y-h;//转到右下角为原点
  501. count++;
  502. liStep += 10000;//0
  503. //var cmW = Math.Round(w * task.widthRatio / task.cm2px_x, 2);
  504. //var cmH = Math.Round(h * task.widthRatio / task.cm2px_y, 2);
  505. // 打印输出信息
  506. //task.resultInfo += $"----{i}----col:{i % colNum}/{colNum} row:{i / colNum}/{colNum}-----------\n目标:{j + 1} 类别ID:{classId} 置信度:{confidence} 对比度:{contrast} 坐标:({x},{y})-({x + w},{y + h}) 宽高:w={w},h={h}; \n";
  507. DefectLabelInfoList.Add(new DefectLabelInfo()
  508. {
  509. x = (int)task.output[index],
  510. y = (int)task.output[index + 1],
  511. w = (int)task.output[index + 2],
  512. h = (int)task.output[index + 3],
  513. classId = (int)task.output[index + 4],
  514. confidence = Math.Round(task.output[index + 5], 2), //置信度
  515. contrast = Math.Round(task.output[index + 6], 3),//对比度
  516. cmW = Math.Round(w * task.widthRatio / task.cm2px_x, 2),
  517. cmH = Math.Round(h * task.widthRatio / task.cm2px_y, 2),
  518. i = i,
  519. j = j,
  520. });
  521. }
  522. #endregion
  523. }
  524. liStep = 7777;
  525. #region 合并接头横档
  526. if (DefectLabelInfoList.Count > 0)
  527. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "jietou", DefectLabelInfoList);
  528. if (DefectLabelInfoList.Count > 0)
  529. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "hengdang", DefectLabelInfoList);
  530. if (DefectLabelInfoList.Count > 0)
  531. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "jt", DefectLabelInfoList);
  532. if (DefectLabelInfoList.Count > 0)
  533. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "hd", DefectLabelInfoList);
  534. if (DefectLabelInfoList.Count > 0)
  535. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "bj", DefectLabelInfoList);
  536. if (DefectLabelInfoList.Count > 0)
  537. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "zj", DefectLabelInfoList);
  538. #endregion
  539. //结果过滤
  540. #region 结果过滤
  541. liStep = 8888;
  542. if (DefectLabelInfoList.Count > 0)
  543. {
  544. //降序排序,先得到是否有接头检出
  545. List<DefectLabelInfo> DefectLabelInfoListByClassID = DefectLabelInfoList.OrderByDescending(t => t.classId).ToList();//降序
  546. for (int q = 0; q < DefectLabelInfoList.Count; q++)
  547. {
  548. //是否满足此产品标准
  549. if (task.qualifiedLimitList != null && task.qualifiedLimitList.Count > 0)
  550. {
  551. qualifiedLimit = task.qualifiedLimitList.FirstOrDefault(m => m.Code == task.labelDic[DefectLabelInfoList[q].classId]);
  552. if (qualifiedLimit != null)
  553. {
  554. //if ((qualifiedLimit.ZXD > 0 && qualifiedLimit.ZXD > confidence)
  555. // || (qualifiedLimit.ContrastTop + qualifiedLimit.ContrastLower > 0 && x> qualifiedLimit.ContrastLower && x < qualifiedLimit.ContrastTop)
  556. // || (qualifiedLimit.Area > 0 && qualifiedLimit.Area > cmW * cmH))
  557. if (DefectLabelInfoList[q].confidence <= qualifiedLimit.ZXD)//confidence > qualifiedLimit.ZXD 是瑕疵 才继续判断下面的两个条件
  558. {
  559. task.resultInfo += $" 置信度不满足此产品瑕疵标准,跳过! \n";
  560. continue;
  561. }
  562. //下限<对比度<上限:不是瑕疵
  563. var ContrastTotal = qualifiedLimit.ContrastTop + qualifiedLimit.ContrastLower;
  564. if (qualifiedLimit.IsOR)
  565. {
  566. if (!(
  567. (qualifiedLimit.Area <= 0 || DefectLabelInfoList[q].cmW * DefectLabelInfoList[q].cmH >= (qualifiedLimit.Area / 100)) ||
  568. (ContrastTotal <= 0 || (DefectLabelInfoList[q].contrast < qualifiedLimit.ContrastLower || DefectLabelInfoList[q].contrast > qualifiedLimit.ContrastTop))))
  569. {
  570. task.resultInfo += $" 不满足此产品瑕疵标准,跳过! \n";
  571. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断不是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])");
  572. continue;
  573. }
  574. }
  575. else
  576. {
  577. if (!(
  578. (qualifiedLimit.Area <= 0 || DefectLabelInfoList[q].cmW * DefectLabelInfoList[q].cmH >= (qualifiedLimit.Area / 100)) &&
  579. (ContrastTotal <= 0 || (DefectLabelInfoList[q].contrast < qualifiedLimit.ContrastLower || DefectLabelInfoList[q].contrast > qualifiedLimit.ContrastTop))))
  580. {
  581. task.resultInfo += $" 不满足此产品瑕疵标准,跳过! \n";
  582. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断不是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])");
  583. continue;
  584. }
  585. }
  586. if (task.labelDic[DefectLabelInfoList[q].classId] == "jietou")
  587. haveJieTou = true;
  588. if (haveJieTou && (task.labelDic[DefectLabelInfoList[q].classId] == "hengdang"))
  589. {
  590. task.resultInfo += $" 判断为接头处横档,跳过! \n";
  591. continue;
  592. }
  593. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])");
  594. }
  595. }
  596. liStep++;
  597. //1
  598. int penLine = 20;
  599. //打标
  600. var point1 = new OpenCvSharp.Point((DefectLabelInfoList[q].i % colNum) * image_width + DefectLabelInfoList[q].x - penLine / 2, (DefectLabelInfoList[q].i / colNum) * image_hight + DefectLabelInfoList[q].y - penLine / 2);
  601. var point2 = new OpenCvSharp.Point(point1.X + DefectLabelInfoList[q].w + penLine / 2, point1.Y + DefectLabelInfoList[q].h + penLine / 2);
  602. liStep++;//2
  603. task.resultInfo += $" 转换到大图坐标(px):p1={point1.X},{point1.Y}; p2={point2.X},{point2.Y}\n";
  604. Cv2.Rectangle(task.bmpTag, point1, point2, new Scalar(0.0, 0.0, 255.0), penLine);//画打标点
  605. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"保存第 {count} 行缺陷信息;");
  606. int px = (point1.X - task.xw) > 0 ? (point1.X - task.xw) : 0;
  607. var cmX = Math.Round(px * task.widthRatio / task.cm2px_x, 2);
  608. var cmY = Math.Round((task.bmp.Height - point1.Y - DefectLabelInfoList[q].h) * task.widthRatio / task.cm2px_y, 2);//外面计Y从右下角为原点
  609. liStep++;//3
  610. task.resultInfo += $" 转换到大图坐标(cm)[widthRatio={task.widthRatio}]:x={cmX},y={cmY}; w={DefectLabelInfoList[q].cmW},h={DefectLabelInfoList[q].cmH}\n";
  611. task.excelTable.Rows.Add($"{task.photoIndex}", cmX, cmY, DefectLabelInfoList[q].cmW, DefectLabelInfoList[q].cmH, DefectLabelInfoList[q].j + 1, DefectLabelInfoList[q].classId, DefectLabelInfoList[q].confidence, Utils.ContrastToPercent(DefectLabelInfoList[q].contrast));
  612. liStep++;//4
  613. //切缺陷小图
  614. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"保存第 {count} 个缺陷小图;");
  615. int left, top, decX, decY;
  616. //decX = (DefectLabelInfoList[q].w > 236 ? 20 : 256 - DefectLabelInfoList[q].w) / 2;
  617. //decY = (DefectLabelInfoList[q].h > 236 ? 20 : 256 - DefectLabelInfoList[q].h) / 2;
  618. int tdecX = (DefectLabelInfoList[q].w / 2) / 2;
  619. int tdecY = DefectLabelInfoList[q].w / DefectLabelInfoList[q].h > 4 ? DefectLabelInfoList[q].w / 8 : (DefectLabelInfoList[q].h / 1) / 2;
  620. decX = (DefectLabelInfoList[q].w > 236 ? tdecX : 256 - DefectLabelInfoList[q].w) / 2;
  621. decY = (DefectLabelInfoList[q].h > 236 ? tdecY : 256 - DefectLabelInfoList[q].h) / 2;
  622. left = point1.X - decX;
  623. top = point1.Y - decY;
  624. if (left < 0) left = 0;
  625. if (top < 0) top = 0;
  626. int width = DefectLabelInfoList[q].w + decX * 2;
  627. int height = DefectLabelInfoList[q].h + decY * 2;
  628. if (left + width > task.bmp.Width - 1) width = task.bmp.Width - left - 1;
  629. if (top + height > task.bmp.Height - 1) height = task.bmp.Height - top - 1;
  630. liStep++;//5
  631. Rect roi = new Rect(left, top, width, height);
  632. liStep++;//6
  633. if (height < 1 || width < 1)
  634. {
  635. task.resultInfo += $" 打标到大图坐标Rect(px):left={left},top={top}; width={width},height={height}\n";
  636. task.resultInfo += $" test point1.Y={point1.Y},h={DefectLabelInfoList[q].h}; top={top},mat.Height={task.bmp.Height}\n================\n";
  637. WarningEvent?.Invoke(WarningEnum.Normal, task.resultInfo);
  638. }
  639. //保存
  640. //string filename = $"{Config.appBasePath}\\temp\\{task.tag}\\{task.tag}_X{mmX.ToString()}_Y{mmY.ToString()}_W{mmW.ToString()}_H{mmH.ToString()}_目标{j + 1}_类别{classId}_置信度{confidence}.bmp";
  641. //OpenCvSharp.Extensions.BitmapConverter.ToBitmap(new Mat(task.bmp, roi)).Save(filename, ImageFormat.Jpeg);
  642. task.lstDefectBmp.Add(new Mat(task.bmpTag, roi).Clone());
  643. liStep++;//7
  644. }
  645. }
  646. #endregion
  647. }
  648. else if (task.iType == ImageDefectType.Anomalib)
  649. {
  650. }
  651. else if (task.iType == ImageDefectType.Def)
  652. {
  653. stopwatch.Restart();
  654. //打标
  655. var defectinfo = task.hv_defectinfo.ToOArr();
  656. List<DefectLabelInfo> DefectLabelInfoList = new List<DefectLabelInfo>();
  657. for (int i = 0; i < task.object_num; i++)
  658. {
  659. liStep = 23 + i;
  660. #region 检测信息汇总
  661. int index = i * 6;
  662. // 打印输出信息(示例代码,根据实际情况进行修改和格式化)
  663. // 获取输出信息
  664. int x = (int)defectinfo[index].ToInt();
  665. int y = (int)defectinfo[index + 1].ToInt();
  666. int w = (int)defectinfo[index + 2].ToInt();
  667. int h = (int)defectinfo[index + 3].ToInt();
  668. int classId = -99;//(int)defectinfo[index + 4].ToInt();
  669. double confidence = Math.Round(defectinfo[index + 5].ToDouble(), 2); //置信度
  670. int px = x;
  671. var cmX = Math.Round(px * task.widthRatio / task.cm2px_x, 2);
  672. var cmY = Math.Round((task.bmp.Height - y - h) * task.widthRatio / task.cm2px_y, 2);//外面计Y从右下角为原点
  673. DefectLabelInfoList.Add(new DefectLabelInfo()
  674. {
  675. x = x,
  676. y = y,
  677. w = w,
  678. h = h,
  679. classId = classId,
  680. confidence = confidence, //置信度
  681. cmW = Math.Round(w * task.widthRatio / task.cm2px_x, 2),
  682. cmH = Math.Round(h * task.widthRatio / task.cm2px_y, 2),
  683. i = i,
  684. j = i,
  685. });
  686. //y = image_hight-y-h;//转到右下角为原点
  687. task.excelTable.Rows.Add($"{task.photoIndex}", cmX, cmY,
  688. Math.Round(w * task.widthRatio / task.cm2px_x, 2), Math.Round(h * task.widthRatio / task.cm2px_y, 2),
  689. i, classId, confidence, 0);
  690. int penLine = 20;
  691. //打标
  692. var point1 = new OpenCvSharp.Point(x, y);
  693. var point2 = new OpenCvSharp.Point(point1.X + w + penLine / 2, point1.Y + h + penLine / 2);
  694. Cv2.Rectangle(task.bmpTag, point1, point2, new Scalar(0.0, 0.0, 255.0), penLine);//画打标点
  695. //切小图
  696. int left, top, decX, decY;
  697. int tdecX = (w / 2) / 2;
  698. int tdecY = w / h > 4 ? w / 8 : (h / 1) / 2;
  699. decX = (w > 236 ? tdecX : 256 - w) / 2;
  700. decY = (h > 236 ? tdecY : 256 - h) / 2;
  701. left = point1.X - decX;
  702. top = point1.Y - decY;
  703. if (left < 0) left = 0;
  704. if (top < 0) top = 0;
  705. int width = w + decX * 2;
  706. int height = h + decY * 2;
  707. if (left + width > task.bmp.Width - 1) width = task.bmp.Width - left - 1;
  708. if (top + height > task.bmp.Height - 1) height = task.bmp.Height - top - 1;
  709. Rect roi = new Rect(left, top, width, height);
  710. task.lstDefectBmp.Add(new Mat(task.bmpTag, roi).Clone());
  711. #endregion
  712. }
  713. }
  714. liStep = 99;
  715. stopwatch.Stop();
  716. task.stopwatch[3] = stopwatch.ElapsedMilliseconds;
  717. task.isSucceed = true;
  718. //lock (taskDefectOverList)
  719. //{
  720. // taskDefectOverList.Add(task);
  721. // QueueCountEvent?.BeginInvoke(3, taskDefectOverList.Count, null, null);
  722. //}
  723. callback(task);
  724. Thread.Sleep(5);
  725. }
  726. catch (Exception ex)
  727. {
  728. WarningEvent?.Invoke(WarningEnum.Low, $"DefectLib task3 err({liStep}):" + ex.Message + $"-{task.resultInfo}");
  729. task.isSucceed = false;
  730. task.resultInfo = ex.Message;
  731. callback(task);
  732. }
  733. }
  734. }
  735. //最终处理
  736. private void run()
  737. {
  738. int step = 0;
  739. QualifiedLimit qualifiedLimit;
  740. while (IsInit)
  741. {
  742. if (taskList.Count < 1)
  743. {
  744. Thread.Sleep(5);
  745. continue;
  746. }
  747. step = 1;
  748. var task = pop();
  749. try
  750. {
  751. if (task != null)
  752. {
  753. Stopwatch stopwatch = Stopwatch.StartNew();
  754. step = 2;
  755. if (preModelName != task.modelName)
  756. {
  757. step = 3;
  758. //先释放模型
  759. if (detector != IntPtr.Zero)
  760. {
  761. step = 4;
  762. DestroyDetector(detector);
  763. detector = IntPtr.Zero;
  764. }
  765. step = 5;
  766. string modelPath = $"{ConfMgr.Instance.SysConfigParams.AIModelPath}\\{task.modelName}";
  767. detector = CreateDetector(modelPath);
  768. if (detector == IntPtr.Zero)
  769. throw new Exception($"模型({modelPath})初始化失败!");
  770. step = 6;
  771. preModelName = task.modelName;
  772. }
  773. //源图
  774. stopwatch.Start();
  775. step = 7;
  776. //裁切
  777. task.bmps_cut = OpenCVToCutsMat(task.bmp, image_width, image_hight); //这里cut时之前加的clone
  778. stopwatch.Stop();
  779. task.stopwatch[0] = stopwatch.ElapsedMilliseconds;
  780. step = 8;
  781. int cut_count = task.bmps_cut.Count();
  782. //====推理(必需单队列)
  783. stopwatch.Restart();
  784. // 把数据转为byte数组,【h, w, c】的bgr格式,第一张在前,第二张在后
  785. byte[] imgData = new byte[image_bytes * cut_count];
  786. for (int i = 0; i < cut_count; i++)
  787. Marshal.Copy(task.bmps_cut[i].Data, imgData, image_bytes * i, image_bytes);
  788. step = 9;
  789. stopwatch.Stop();
  790. task.stopwatch[1] = stopwatch.ElapsedMilliseconds;
  791. stopwatch.Restart();
  792. task.output = new float[cut_count * detect_elem_size * detect_max_object_num];
  793. task.output_num = new int[cut_count];
  794. //执行推理
  795. step = 10;
  796. bool ok = Detect(detector, ref imgData[0], cut_count, image_width, image_hight, image_channels,
  797. 0.25f, 0.45f, ref task.output[0], task.output.Length, ref task.output_num[0], task.expand_pixel);
  798. step = 11;
  799. stopwatch.Stop();
  800. task.stopwatch[2] = stopwatch.ElapsedMilliseconds;
  801. stopwatch.Restart();
  802. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"DefectLib tasks 结果推理={ok}");
  803. for (int i = 0; i < cut_count; i++)
  804. task.bmps_cut[i].Dispose();
  805. if (ok == false)
  806. throw new Exception($"推理失败或者输入数组太小({cut_count})");
  807. step = 12;
  808. //打标
  809. cut_count = task.bmps_cut.Count();//上面bmps_cut已销毁
  810. int colNum = task.bmp.Width / image_width;
  811. int rowNum = task.bmp.Height / image_hight;
  812. int count = 0;
  813. step = 13;
  814. //车用革去除接头处横档误判
  815. bool haveJieTou = false;
  816. List<DefectLabelInfo> DefectLabelInfoList = new List<DefectLabelInfo>();
  817. for (int i = 0; i < cut_count; i++)
  818. {
  819. step = i * 100;
  820. task.resultInfo += $"第 {i}/{cut_count} 张小图(大图索引{task.photoIndex}): 缺陷数 = {task.output_num[i]}-{task.output.Length}\n";
  821. //task.resultInfo +=$"大图({task.tag})[{task.bmp.Width}*{task.bmp.Height}],第 {i + 1}/{cut_count} 张小图[{task.bmps_cut[i].Width}*{task.bmps_cut[i].Height}]: 瑕疵output_num = {output_num[i]}\n";
  822. #region 检测信息汇总
  823. for (int j = 0; j < task.output_num[i]; j++)//缺陷数
  824. {
  825. step += j + 10000;//0
  826. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"-------");
  827. int index = count * detect_elem_size;
  828. // 打印输出信息(示例代码,根据实际情况进行修改和格式化)
  829. // 获取输出信息
  830. int x = (int)task.output[index];
  831. int y = (int)task.output[index + 1];
  832. int w = (int)task.output[index + 2];
  833. int h = (int)task.output[index + 3];
  834. int classId = (int)task.output[index + 4];
  835. double confidence = Math.Round(task.output[index + 5], 2); //置信度
  836. double contrast = Math.Round(task.output[index + 6], 3);//对比度
  837. //y = image_hight-y-h;//转到右下角为原点
  838. count++;
  839. step += 10000;//0
  840. DefectLabelInfoList.Add(new DefectLabelInfo()
  841. {
  842. x = (int)task.output[index],
  843. y = (int)task.output[index + 1],
  844. w = (int)task.output[index + 2],
  845. h = (int)task.output[index + 3],
  846. classId = (int)task.output[index + 4],
  847. confidence = Math.Round(task.output[index + 5], 2), //置信度
  848. contrast = Math.Round(task.output[index + 6], 3),//对比度
  849. cmW = Math.Round(w * task.widthRatio / task.cm2px_x, 2),
  850. cmH = Math.Round(h * task.widthRatio / task.cm2px_y, 2),
  851. i = i,
  852. j = j,
  853. });
  854. }
  855. #endregion
  856. }
  857. step = 7777;
  858. #region 合并接头横档
  859. if (DefectLabelInfoList.Count > 0)
  860. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "jietou", DefectLabelInfoList);
  861. if (DefectLabelInfoList.Count > 0)
  862. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "hengdang", DefectLabelInfoList);
  863. if (DefectLabelInfoList.Count > 0)
  864. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "jt", DefectLabelInfoList);
  865. if (DefectLabelInfoList.Count > 0)
  866. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "hd", DefectLabelInfoList);
  867. if (DefectLabelInfoList.Count > 0)
  868. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "bj", DefectLabelInfoList);
  869. #endregion
  870. //结果过滤
  871. #region 结果过滤
  872. step = 8888;
  873. if (DefectLabelInfoList.Count > 0)
  874. {
  875. //降序排序,先得到是否有接头检出
  876. List<DefectLabelInfo> DefectLabelInfoListByClassID = DefectLabelInfoList.OrderByDescending(t => t.classId).ToList();//降序
  877. for (int q = 0; q < DefectLabelInfoList.Count; q++)
  878. {
  879. //是否满足此产品标准
  880. if (task.qualifiedLimitList != null && task.qualifiedLimitList.Count > 0)
  881. {
  882. qualifiedLimit = task.qualifiedLimitList.FirstOrDefault(m => m.Code == task.labelDic[DefectLabelInfoList[q].classId]);
  883. if (qualifiedLimit != null)
  884. {
  885. //if ((qualifiedLimit.ZXD > 0 && qualifiedLimit.ZXD > confidence)
  886. // || (qualifiedLimit.ContrastTop + qualifiedLimit.ContrastLower > 0 && x> qualifiedLimit.ContrastLower && x < qualifiedLimit.ContrastTop)
  887. // || (qualifiedLimit.Area > 0 && qualifiedLimit.Area > cmW * cmH))
  888. if (DefectLabelInfoList[q].confidence <= qualifiedLimit.ZXD)//confidence > qualifiedLimit.ZXD 是瑕疵 才继续判断下面的两个条件
  889. {
  890. task.resultInfo += $" 置信度不满足此产品瑕疵标准,跳过! \n";
  891. continue;
  892. }
  893. //下限<对比度<上限:不是瑕疵
  894. var ContrastTotal = qualifiedLimit.ContrastTop + qualifiedLimit.ContrastLower;
  895. if (qualifiedLimit.IsOR)
  896. {
  897. if (!(
  898. (qualifiedLimit.Area <= 0 || DefectLabelInfoList[q].cmW * DefectLabelInfoList[q].cmH >= (qualifiedLimit.Area / 100)) ||
  899. (ContrastTotal <= 0 || (DefectLabelInfoList[q].contrast < qualifiedLimit.ContrastLower || DefectLabelInfoList[q].contrast > qualifiedLimit.ContrastTop))))
  900. {
  901. task.resultInfo += $" 不满足此产品瑕疵标准,跳过! \n";
  902. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断不是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])");
  903. continue;
  904. }
  905. }
  906. else
  907. {
  908. if (!(
  909. (qualifiedLimit.Area <= 0 || DefectLabelInfoList[q].cmW * DefectLabelInfoList[q].cmH >= qualifiedLimit.Area / 100) &&
  910. (ContrastTotal <= 0 || (DefectLabelInfoList[q].contrast < qualifiedLimit.ContrastLower || DefectLabelInfoList[q].contrast > qualifiedLimit.ContrastTop))))
  911. {
  912. task.resultInfo += $" 不满足此产品瑕疵标准,跳过! \n";
  913. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断不是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])");
  914. continue;
  915. }
  916. }
  917. if (task.labelDic[DefectLabelInfoList[q].classId] == "jietou")
  918. haveJieTou = true;
  919. if (haveJieTou && (task.labelDic[DefectLabelInfoList[q].classId] == "hengdang"))
  920. {
  921. task.resultInfo += $" 判断为接头处横档,跳过! \n";
  922. continue;
  923. }
  924. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])");
  925. }
  926. }
  927. step++;
  928. //1
  929. int penLine = 20;
  930. //打标
  931. var point1 = new OpenCvSharp.Point((DefectLabelInfoList[q].i % colNum) * image_width + DefectLabelInfoList[q].x - penLine / 2, (DefectLabelInfoList[q].i / colNum) * image_hight + DefectLabelInfoList[q].y - penLine / 2);
  932. var point2 = new OpenCvSharp.Point(point1.X + DefectLabelInfoList[q].w + penLine / 2, point1.Y + DefectLabelInfoList[q].h + penLine / 2);
  933. step++;//2
  934. task.resultInfo += $" 转换到大图坐标(px):p1={point1.X},{point1.Y}; p2={point2.X},{point2.Y}\n";
  935. Cv2.Rectangle(task.bmpTag, point1, point2, new Scalar(0.0, 0.0, 255.0), penLine);//画打标点
  936. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"保存第 {count} 行缺陷信息;");
  937. int px = (point1.X - task.xw) > 0 ? (point1.X - task.xw) : 0;
  938. var cmX = Math.Round(px * task.widthRatio / task.cm2px_x, 2);
  939. var cmY = Math.Round((task.bmp.Height - point1.Y - DefectLabelInfoList[q].h) * task.widthRatio / task.cm2px_y, 2);//外面计Y从右下角为原点
  940. step++;//3
  941. task.resultInfo += $" 转换到大图坐标(cm)[widthRatio={task.widthRatio}]:x={cmX},y={cmY}; w={DefectLabelInfoList[q].cmW},h={DefectLabelInfoList[q].cmH}\n";
  942. task.excelTable.Rows.Add($"{task.photoIndex}", cmX, cmY, DefectLabelInfoList[q].cmW, DefectLabelInfoList[q].cmH, DefectLabelInfoList[q].j + 1, DefectLabelInfoList[q].classId, DefectLabelInfoList[q].confidence, Utils.ContrastToPercent(DefectLabelInfoList[q].contrast));
  943. step++;//4
  944. //切缺陷小图
  945. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"保存第 {count} 个缺陷小图;");
  946. int left, top, decX, decY;
  947. //decX = (DefectLabelInfoList[q].w > 236 ? 20 : 256 - DefectLabelInfoList[q].w) / 2;
  948. //decY = (DefectLabelInfoList[q].h > 236 ? 20 : 256 - DefectLabelInfoList[q].h) / 2;
  949. int tdecX = (DefectLabelInfoList[q].w / 2) / 2;
  950. int tdecY = DefectLabelInfoList[q].w / DefectLabelInfoList[q].h > 4 ? DefectLabelInfoList[q].w / 8 : (DefectLabelInfoList[q].h / 1) / 2;
  951. decX = (DefectLabelInfoList[q].w > 236 ? tdecX : 256 - DefectLabelInfoList[q].w) / 2;
  952. decY = (DefectLabelInfoList[q].h > 236 ? tdecY : 256 - DefectLabelInfoList[q].h) / 2;
  953. left = point1.X - decX;
  954. top = point1.Y - decY;
  955. if (left < 0) left = 0;
  956. if (top < 0) top = 0;
  957. int width = DefectLabelInfoList[q].w + decX * 2;
  958. int height = DefectLabelInfoList[q].h + decY * 2;
  959. if (left + width > task.bmp.Width - 1) width = task.bmp.Width - left - 1;
  960. if (top + height > task.bmp.Height - 1) height = task.bmp.Height - top - 1;
  961. step++;//5
  962. Rect roi = new Rect(left, top, width, height);
  963. step++;//6
  964. if (height < 1 || width < 1)
  965. {
  966. task.resultInfo += $" 打标到大图坐标Rect(px):left={left},top={top}; width={width},height={height}\n";
  967. task.resultInfo += $" test point1.Y={point1.Y},h={DefectLabelInfoList[q].h}; top={top},mat.Height={task.bmp.Height}\n================\n";
  968. WarningEvent?.Invoke(WarningEnum.Normal, task.resultInfo);
  969. }
  970. //保存
  971. //string filename = $"{Config.appBasePath}\\temp\\{task.tag}\\{task.tag}_X{mmX.ToString()}_Y{mmY.ToString()}_W{mmW.ToString()}_H{mmH.ToString()}_目标{j + 1}_类别{classId}_置信度{confidence}.bmp";
  972. //OpenCvSharp.Extensions.BitmapConverter.ToBitmap(new Mat(task.bmp, roi)).Save(filename, ImageFormat.Jpeg);
  973. task.lstDefectBmp.Add(new Mat(task.bmpTag, roi).Clone());
  974. step++;//7
  975. }
  976. }
  977. #endregion
  978. step = 99;
  979. stopwatch.Stop();
  980. task.stopwatch[3] = stopwatch.ElapsedMilliseconds;
  981. task.isSucceed = true;
  982. //lock (taskDefectOverList)
  983. //{
  984. // taskDefectOverList.Add(task);
  985. // QueueCountEvent?.BeginInvoke(3, taskDefectOverList.Count, null, null);
  986. //}
  987. callback(task);
  988. }
  989. }
  990. catch (Exception ex)
  991. {
  992. WarningEvent?.Invoke(WarningEnum.Low, $"DefectLib taskRun err({step}):" + ex.Message);
  993. task.isSucceed = false;
  994. task.resultInfo = ex.Message;
  995. callback(task);
  996. }
  997. Thread.Sleep(5);
  998. }
  999. }
  1000. #region 词条合并
  1001. private List<DefectLabelInfo> HeBingDefect(int Width, string label, List<DefectLabelInfo> DefectLabelInfoList)
  1002. {
  1003. int fw = 2000;
  1004. List<DefectLabelInfo> outList = new List<DefectLabelInfo>();
  1005. List<DefectLabelInfo> HeBingList = new List<DefectLabelInfo>();
  1006. List<DefectLabelInfo> XcHeBingList = new List<DefectLabelInfo>();
  1007. List<int> xPos = new List<int>();
  1008. List<int> yPos = new List<int>();
  1009. List<double> xZXD = new List<double>();
  1010. List<double> xDBD = new List<double>();
  1011. DefectLabelInfo stpoint = DefectLabelInfoList[0];
  1012. int colNum = Width / image_width;
  1013. //寻找在一条线上
  1014. for (int q = 0; q < DefectLabelInfoList.Count; q++)
  1015. {
  1016. if (SysMgr.Instance.GetDefectCode()[DefectLabelInfoList[q].classId] == label)
  1017. {
  1018. int max = stpoint.y + fw;
  1019. int min = stpoint.y - fw > 0 ? stpoint.y - fw : 0;
  1020. if (DefectLabelInfoList[q].y >= min && DefectLabelInfoList[q].y <= max)
  1021. {
  1022. HeBingList.Add(DefectLabelInfoList[q]);
  1023. xPos.Add((DefectLabelInfoList[q].i % colNum) * image_width + DefectLabelInfoList[q].x);
  1024. yPos.Add((DefectLabelInfoList[q].i / colNum) * image_hight + DefectLabelInfoList[q].y);
  1025. xZXD.Add(DefectLabelInfoList[q].confidence);
  1026. xDBD.Add(DefectLabelInfoList[q].contrast);
  1027. }
  1028. else
  1029. XcHeBingList.Add(DefectLabelInfoList[q]);
  1030. }
  1031. else
  1032. outList.Add(DefectLabelInfoList[q]);
  1033. }
  1034. //递归下次合并数据
  1035. List<DefectLabelInfo> dg1 = new List<DefectLabelInfo>();
  1036. if (XcHeBingList.Count > 0)
  1037. dg1 = HeBingDefect(Width, label, XcHeBingList);
  1038. //多个jietou合并
  1039. if (HeBingList.Count > 0)
  1040. {
  1041. var stIt = HeBingList.Find(x => ((x.i % colNum) * image_width + x.x) == xPos.Min());
  1042. var edIt = HeBingList.Find(x => ((x.i % colNum) * image_width + x.x) == xPos.Max());
  1043. var stIty = HeBingList.Find(x => ((x.i / colNum) * image_hight + x.y) == yPos.Min());
  1044. var edIty = HeBingList.Find(x => ((x.i / colNum) * image_hight + x.y) == yPos.Max());
  1045. var eZXD = HeBingList.Find(x => x.confidence == xZXD.Max());
  1046. double eDBD = 0;
  1047. double DBD = 0;
  1048. for (int i = 0; i < xDBD.Count; i++)
  1049. {
  1050. if (Math.Abs(xDBD[i] - 1) >= eDBD)
  1051. {
  1052. eDBD = Math.Abs(xDBD[i] - 1);
  1053. DBD = xDBD[i];
  1054. }
  1055. }
  1056. int newW = Math.Abs(((edIt.i % colNum) * image_width + edIt.x) - ((stIt.i % colNum) * image_width + stIt.x)) + edIt.w;
  1057. int newh = Math.Abs(((edIt.i / colNum) * image_hight + edIt.y) - ((stIt.i / colNum) * image_hight + stIt.y)) + edIt.h;
  1058. outList.Add(new DefectLabelInfo()
  1059. {
  1060. x = stIt.x,
  1061. y = edIt.y,
  1062. w = newW, //多图叠加
  1063. h = newh, //多图叠加
  1064. classId = eZXD.classId,
  1065. confidence = eZXD.confidence,
  1066. contrast = DBD,
  1067. cmH = Math.Round(edIt.h * 1.0 / ConfMgr.Instance.SysConfigParams.Cm2px_y, 2),
  1068. cmW = Math.Round(newW * 1.0 / ConfMgr.Instance.SysConfigParams.Cm2px_x, 2),
  1069. i = stIt.i,
  1070. j = stIt.j,
  1071. });
  1072. }
  1073. outList = outList.Concat(dg1).ToList<DefectLabelInfo>();//保留重复项
  1074. return outList;
  1075. }
  1076. #endregion
  1077. #region 结果回调
  1078. private void callback(DefectTask task)
  1079. {
  1080. //返回成功/失败,异步调用
  1081. if (task.finishEvent != null || (task.finishEvent = finishEvent) != null)
  1082. //task.finishEvent.BeginInvoke(result, errInfo, res => task.finishEvent.EndInvoke(res), null);
  1083. System.Threading.ThreadPool.QueueUserWorkItem(waitCallback, task);
  1084. }
  1085. //异步回调
  1086. WaitCallback waitCallback = new WaitCallback(o =>
  1087. {
  1088. var task = (DefectTask)o;
  1089. task.finishEvent(task);
  1090. });
  1091. #endregion
  1092. #region 处理队列
  1093. public string GetDefectInfo()
  1094. {
  1095. string str = "";
  1096. int cnt1, cnt2, cnt3;
  1097. lock (taskList)
  1098. {
  1099. cnt1 = taskList.Count;
  1100. }
  1101. lock (taskOperationList)
  1102. {
  1103. cnt2 = taskOperationList.Count;
  1104. }
  1105. lock (taskMakeTagList)
  1106. {
  1107. cnt3 = taskMakeTagList.Count;
  1108. }
  1109. str = $"预处理:{cnt1},推理:{cnt2},打标:{cnt3}";
  1110. return str; ;
  1111. }
  1112. public void add(DefectTask task)
  1113. {
  1114. lock (taskList)
  1115. {
  1116. taskList.Add(task);
  1117. QueueCountEvent?.BeginInvoke(0, taskList.Count, null, null);
  1118. }
  1119. }
  1120. private DefectTask pop()
  1121. {
  1122. lock (taskList)
  1123. {
  1124. if (taskList.Count < 1)
  1125. return null;
  1126. //int index = 0;// taskList.FindIndex(p => { return p.isSync; });
  1127. //if (index < 0) index = 0;
  1128. var task = taskList[0];
  1129. taskList.RemoveAt(0);
  1130. QueueCountEvent?.BeginInvoke(0, taskList.Count, null, null);
  1131. return task;
  1132. }
  1133. }
  1134. private DefectTask pop2()
  1135. {
  1136. lock (taskOperationList)
  1137. {
  1138. if (taskOperationList.Count < 1)
  1139. return null;
  1140. //int index = 0;// taskList.FindIndex(p => { return p.isSync; });
  1141. //if (index < 0) index = 0;
  1142. var task = taskOperationList[0];
  1143. taskOperationList.RemoveAt(0);
  1144. QueueCountEvent?.BeginInvoke(1, taskOperationList.Count, null, null);
  1145. return task;
  1146. }
  1147. }
  1148. private DefectTask pop3()
  1149. {
  1150. lock (taskMakeTagList)
  1151. {
  1152. if (taskMakeTagList.Count < 1)
  1153. return null;
  1154. //int index = 0;// taskList.FindIndex(p => { return p.isSync; });
  1155. //if (index < 0) index = 0;
  1156. var task = taskMakeTagList[0];
  1157. taskMakeTagList.RemoveAt(0);
  1158. QueueCountEvent?.BeginInvoke(2, taskMakeTagList.Count, null, null);
  1159. return task;
  1160. }
  1161. }
  1162. private DefectTask pop4()
  1163. {
  1164. lock (taskDefectOverList)
  1165. {
  1166. if (taskDefectOverList.Count < 1)
  1167. return null;
  1168. //int index = 0;// taskList.FindIndex(p => { return p.isSync; });
  1169. //if (index < 0) index = 0;
  1170. var task = taskDefectOverList[0];
  1171. taskDefectOverList.RemoveAt(0);
  1172. QueueCountEvent?.BeginInvoke(3, taskDefectOverList.Count, null, null);
  1173. return task;
  1174. }
  1175. }
  1176. #endregion
  1177. public void Dispose()
  1178. {
  1179. stop();
  1180. }
  1181. private class DefectLabelInfo
  1182. {
  1183. public int x { get; set; }
  1184. public int y { get; set; }
  1185. public int w { get; set; }
  1186. public int h { get; set; }
  1187. public int classId { get; set; }
  1188. public double confidence { get; set; } //置信度
  1189. public double contrast { get; set; }//对比度
  1190. public double cmW { get; set; }
  1191. public double cmH { get; set; }
  1192. public int i { get; set; }//小图index
  1193. public int j { get; set; }//缺陷index
  1194. }
  1195. }
  1196. public class DefectTask
  1197. {
  1198. public DefectTask()
  1199. {
  1200. // 创建一个 DataTable 对象来存储数据
  1201. excelTable = new DataTable("MyData");
  1202. // 添加列到 DataTable
  1203. excelTable.Columns.Add("FileName", typeof(string));
  1204. excelTable.Columns.Add("X", typeof(decimal));
  1205. excelTable.Columns.Add("Y", typeof(decimal));
  1206. excelTable.Columns.Add("W", typeof(decimal));
  1207. excelTable.Columns.Add("H", typeof(decimal));
  1208. excelTable.Columns.Add("目标", typeof(int));
  1209. excelTable.Columns.Add("类别", typeof(int));
  1210. excelTable.Columns.Add("置信度", typeof(decimal));
  1211. excelTable.Columns.Add("对比度", typeof(decimal));
  1212. // 向 DataTable 中添加数据行
  1213. //excelTable.Rows.Add("John Doe", 30);
  1214. //excelTable.Rows.Add("Jane Smith", 25);
  1215. }
  1216. /// <summary>
  1217. /// 处理参数
  1218. /// </summary>
  1219. public int expand_pixel;
  1220. public int cm2px_x;
  1221. public int cm2px_y;
  1222. public Dictionary<int, string> labelDic;
  1223. /// <summary>
  1224. /// 模型名字
  1225. /// </summary>
  1226. public string modelName;
  1227. public Models.Records record;
  1228. //public string bmpPath;//源图路径(仅目录)
  1229. /// <summary>
  1230. /// 源图(resize后的)
  1231. /// </summary>
  1232. public Mat bmp;
  1233. //public Mat bmpBgr2rgb=new Mat();
  1234. public System.Drawing.Size resize = new System.Drawing.Size(224, 224);
  1235. //public Mat resizeBmp;//resize后 BGR2RGB图,只用于识别
  1236. public Mat bmpTag;
  1237. /// <summary>
  1238. /// 图片索引0-n
  1239. /// </summary>
  1240. public int photoIndex;//excel中对应的图像路径标识
  1241. public float widthRatio;//宽度比例,resize前/resize后
  1242. //切割后
  1243. public Mat[] bmps_cut;
  1244. //用于比对参数 }//置信度 面积 对比度
  1245. public List<QualifiedLimit> qualifiedLimitList;
  1246. //推理后结果用于打标
  1247. public float[] output;
  1248. public int[] output_num;
  1249. //
  1250. /// <summary>
  1251. /// 完成后回调
  1252. /// </summary>
  1253. public Action<DefectTask> finishEvent;
  1254. //==结果返回
  1255. public bool isSucceed;//转换是否成功
  1256. public string resultInfo = "";//成功或失败信息
  1257. public List<Mat> lstDefectBmp = new List<Mat>();
  1258. /// <summary>
  1259. /// fileIndex,x_mm,y_mm,w_mm,h_mm,目标,类别ID,置信度
  1260. /// </summary>
  1261. public DataTable excelTable = new DataTable();
  1262. public long[] stopwatch = new long[6];
  1263. /// <summary>
  1264. /// 等比例填充的宽度
  1265. /// </summary>
  1266. public int xw;
  1267. /// <summary>
  1268. /// 当前图像计米器位置
  1269. /// </summary>
  1270. public double CurrDis;
  1271. /// <summary>
  1272. /// 算法选择
  1273. /// </summary>
  1274. public ImageDefectType iType;
  1275. //传统算法使用
  1276. public HObject ho_Img = new HObject();
  1277. public HObject ho_imgG = new HObject();
  1278. public HObject ho_ImageResult3 = new HObject();
  1279. public HObject ho_ImageSub = new HObject();
  1280. public HTuple hv_RES, hv_gauss_filter1, hv_gauss_filter2, hv_Energy_value, hv_Region_S_value, hv_class, hv_defectinfo;
  1281. public int object_num = 0;
  1282. }
  1283. }