革博士程序V1仓库
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

1304 righe
68 KiB

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