FaRun.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. using MeterVision.Config;
  2. using MeterVision.db;
  3. using MeterVision.Helper;
  4. using MeterVision.model;
  5. using MeterVision.Util;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Diagnostics;
  9. using System.Drawing;
  10. using System.Drawing.Imaging;
  11. using System.IO;
  12. using System.Linq;
  13. using System.Runtime.InteropServices;
  14. using System.Text;
  15. using System.Threading.Tasks;
  16. using static MeterVision.FreeAi.FaImport;
  17. namespace MeterVision.FreeAi
  18. {
  19. //识别主程序
  20. public class FaRun
  21. {
  22. //private FaLog faLog; //设备运行日志类
  23. public static bool SendAiLogEnable = false;
  24. private StringBuilder mRunLog = new StringBuilder();
  25. public event EventHandler<AiRealLogEventArgs> OnAiRealLogInfo;
  26. private UdpSender udpSender;
  27. private static RealLogger realLogger;
  28. //public static bool RecordRealLogEnable = false; //实时日志记录
  29. private static bool _recordRealLogEnable = false;
  30. public static bool RecordRealLogEnable
  31. {
  32. get => _recordRealLogEnable;
  33. set
  34. {
  35. if(_recordRealLogEnable != value)
  36. {
  37. _recordRealLogEnable = value;
  38. }
  39. if (!_recordRealLogEnable && realLogger != null)
  40. {
  41. realLogger.Close();
  42. }
  43. }
  44. }
  45. //ai输出的日志回调函数
  46. private void PrintfCallbackMethod(string message)
  47. {
  48. //Debug.Write(message);
  49. // 获取日志实例,将日志加入队列(不会创建新线程)
  50. //var logger = UdpLoggerSender.GetInstance();
  51. //logger.EnqueueLog(message); // 只加入队列,避免创建过多线程
  52. if (FaRun.SendAiLogEnable)
  53. {
  54. udpSender = UdpSender.GetInstance();
  55. udpSender.SendLog(message);
  56. }
  57. if (FaRun.RecordRealLogEnable)
  58. {
  59. realLogger = RealLogger.GetInstance();
  60. realLogger.Log(message);
  61. }
  62. //faLog.Append_aiLog(message);
  63. mRunLog.Append(message);
  64. //发送消息给主程序控件
  65. OnAiRealLogInfo?.Invoke(this, new AiRealLogEventArgs(message));
  66. }
  67. //增加MCU的日志
  68. private void AddMCULog(string message)
  69. {
  70. mRunLog.Append(message + "\n");
  71. OnAiRealLogInfo?.Invoke(this, new AiRealLogEventArgs(message));
  72. }
  73. public ResultModel StartRecognition(object detailItem)
  74. {
  75. PrintfCallback callback = PrintfCallbackMethod;
  76. string srcImage = string.Empty;
  77. if(detailItem is SingleDetailItem)
  78. {
  79. srcImage = ((SingleDetailItem)detailItem).SrcImage;
  80. }
  81. else if(detailItem is PatchDetailItem)
  82. {
  83. srcImage = ((PatchDetailItem)detailItem).SrcImage;
  84. }else if(detailItem is TPatchDetail)
  85. {
  86. srcImage = ((TPatchDetail)detailItem).SrcImage;
  87. }
  88. else
  89. {
  90. return null;
  91. }
  92. //判断图像尺寸是否合规
  93. if (!ThisApp.IsImageDimensionsValid(srcImage))
  94. {
  95. Console.WriteLine($"{srcImage}图像尺寸不合规!");
  96. return null;
  97. }
  98. short[] rgb565 = GetRGB565Array(srcImage);
  99. if (rgb565.Length != (320 * 240))
  100. {
  101. throw new InvalidOperationException("无效的图像大小。");
  102. }
  103. BeforeAI beforeAI = new BeforeAI();
  104. if(detailItem is SingleDetailItem)
  105. {
  106. beforeAI = FaBefore.getBeforeAI((SingleDetailItem)detailItem);
  107. }
  108. else if(detailItem is PatchDetailItem)
  109. {
  110. beforeAI = FaBefore.getBeforeAI((PatchDetailItem)detailItem);
  111. }
  112. else if(detailItem is TPatchDetail)
  113. {
  114. beforeAI = FaBefore.getBeforeAI((TPatchDetail)detailItem);
  115. }
  116. AfterAI afterAI = new AfterAI();
  117. SmallImage smallJpg = new SmallImage();
  118. BigImage bigJpg = new BigImage();
  119. //string onnxPath = ConfigItem.GetConfigItem().OnnxPath;
  120. string onnxPath = CfginiItem.GetConfigItem().OnnxPath;
  121. onnxPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, onnxPath);
  122. //判断onnxPath的路径是否存在
  123. if (!File.Exists(onnxPath))
  124. {
  125. throw new InvalidOperationException($"onnx文件{onnxPath}不存在!");
  126. }
  127. //调用动态加载的方式
  128. //初始化加载动态库,
  129. //string dllPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigItem.GetConfigItem().AiDll);
  130. string dllPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, CfginiItem.GetConfigItem().AiDll);
  131. if (!File.Exists(dllPath))
  132. {
  133. throw new InvalidOperationException($"AI动态库文件{dllPath}不存在!");
  134. }
  135. int result = -1;
  136. if (DynamicFaImport.Initialize(dllPath))
  137. {
  138. try
  139. {
  140. result = DynamicFaImport.Recognition(rgb565, ref beforeAI, ref afterAI, ref smallJpg, ref bigJpg, onnxPath, callback);
  141. }
  142. catch (AccessViolationException ex)
  143. {
  144. // 处理异常,例如记录日志
  145. Console.WriteLine("Access violation: " + ex.Message);
  146. }
  147. catch (Exception ex)
  148. {
  149. Console.WriteLine("Exeception: " + ex.Message);
  150. }
  151. }
  152. else
  153. {
  154. throw new InvalidOperationException($"初始化AI动态库{dllPath}失败!");
  155. }
  156. DynamicFaImport.Unload();
  157. //存储图像
  158. string dstImagPath = CfginiItem.GetConfigItem().DstImgPath;
  159. dstImagPath = Path.Combine(dstImagPath, ThisApp.GetNowTime_yyyyMMdd());
  160. if (!Directory.Exists(dstImagPath))
  161. {
  162. Directory.CreateDirectory(dstImagPath);
  163. }
  164. dstImagPath = Path.Combine(dstImagPath, Guid.NewGuid().ToString() + ".jpg");
  165. SaveBigJpg(bigJpg, dstImagPath);
  166. //存储日志
  167. string aiLogPath = CfginiItem.GetConfigItem().AiLogPath;
  168. aiLogPath = Path.Combine(aiLogPath, ThisApp.GetNowTime_yyyyMMdd());
  169. if (!Directory.Exists(aiLogPath))
  170. {
  171. Directory.CreateDirectory(aiLogPath);
  172. }
  173. aiLogPath = Path.Combine(aiLogPath, Guid.NewGuid().ToString() + ".txt");
  174. try
  175. {
  176. if (LicenseMana.mLicenseModel != null && LicenseMana.mLicenseModel.IsPermanent)
  177. {
  178. File.WriteAllText(aiLogPath, mRunLog.ToString());
  179. }
  180. else
  181. {
  182. File.WriteAllText(aiLogPath, "");
  183. }
  184. }
  185. catch (Exception ex)
  186. {
  187. throw new InvalidOperationException($"保存文件{aiLogPath}失败:{ex.Message}");
  188. }
  189. //结果对象赋值
  190. ResultModel resultModel = new ResultModel
  191. {
  192. SrcImage = srcImage,
  193. DstImage = dstImagPath,
  194. LogPath = aiLogPath,
  195. ResultMeter = afterAI.METER_TYPE,
  196. //1,2,7,8
  197. ResultType = afterAI.AI_RESULT_ARRAY[11],
  198. RawValue = afterAI.INIT_AI_RESULT,
  199. FinalValue = afterAI.AI_RESULT,
  200. CompleteValue = afterAI.AI_COMPLETE_RESULT,
  201. ValueChanged = afterAI.IS_VALUE_CHANGED,
  202. CompressIndex = afterAI.COMPRESS_JPG_INDEX,
  203. };
  204. if (beforeAI.METER_TYPE == 1 || beforeAI.METER_TYPE == 3)
  205. {
  206. resultModel.FeatureRegions =
  207. $"{afterAI.CONFIG_NUM_REGION[0]},{afterAI.CONFIG_NUM_REGION[1]} " +
  208. $"{afterAI.CONFIG_NUM_REGION[2]},{afterAI.CONFIG_NUM_REGION[3]} " +
  209. $"{afterAI.CONFIG_NUM_REGION[4]},{afterAI.CONFIG_NUM_REGION[5]} " +
  210. $"{afterAI.CONFIG_NUM_REGION[6]},{afterAI.CONFIG_NUM_REGION[7]}";
  211. resultModel.MeterRegions = $"{afterAI.CONFIG_METER_REGION[0]}," +
  212. $"{afterAI.CONFIG_METER_REGION[1]} " +
  213. $"{afterAI.CONFIG_METER_REGION[2]}," +
  214. $"{afterAI.CONFIG_METER_REGION[3]}";
  215. }
  216. else if (beforeAI.METER_TYPE == 2)
  217. {
  218. resultModel.FeatureRegions = $"{afterAI.CONFIG_TWO_IND[0]}," +
  219. $"{afterAI.CONFIG_TWO_IND[1]} " +
  220. $"{afterAI.CONFIG_TWO_IND[2]}," +
  221. $"{afterAI.CONFIG_TWO_IND[3]}";
  222. resultModel.MeterRegions = $"{afterAI.CONFIG_METER_REGION[0]}," +
  223. $"{afterAI.CONFIG_METER_REGION[1]} " +
  224. $"{afterAI.CONFIG_METER_REGION[2]}," +
  225. $"{afterAI.CONFIG_METER_REGION[3]}";
  226. }
  227. else
  228. {
  229. resultModel.MeterRegions = "";
  230. resultModel.FeatureRegions = "";
  231. }
  232. resultModel.AiVer = BitConverter.ToString(afterAI.AI_VER).Replace("-", "");
  233. resultModel.DebugInfoBytes = afterAI.AI_RESULT_ARRAY;
  234. return resultModel;
  235. }
  236. private short[] GetRGB565Array(string jpgFilePath)
  237. {
  238. using (Bitmap bmp = new Bitmap(jpgFilePath))
  239. {
  240. int width = bmp.Width;
  241. int height = bmp.Height;
  242. //string message = string.Format("width = %d,height = %d", width, height);
  243. string message = $"width = {width}, height = {height}";
  244. AddMCULog(message);
  245. //创建数组存储RGB565数据
  246. short[] rgb565Data = new short[width * height];
  247. //给它多分配1倍的内存
  248. //short[] rgb565Data = new short[width * height*2];
  249. //锁定位图内存
  250. BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
  251. IntPtr ptr = bmpData.Scan0;
  252. //创建数据存储RGB888数据
  253. byte[] rgb888Data = new byte[Math.Abs(bmpData.Stride) * height];
  254. //将像素数据拷贝到字节数组中
  255. Marshal.Copy(ptr, rgb888Data, 0, rgb888Data.Length);
  256. // 逐个像素转换为 RGB565 格式,并进行上下颠倒处理
  257. for (int y = 0; y < height; y++)
  258. {
  259. for (int x = 0; x < width; x++)
  260. {
  261. // 颠倒行的顺序
  262. int invertedY = height - 1 - y;
  263. //int index = y * bmpData.Stride + x * 3;
  264. int index = invertedY * bmpData.Stride + x * 3;
  265. byte r = rgb888Data[index + 2]; // R 通道
  266. byte g = rgb888Data[index + 1]; // G 通道
  267. byte b = rgb888Data[index]; // B 通道
  268. // 将 RGB888 转换为 RGB565
  269. short rgb565 = (short)(((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3));
  270. rgb565Data[y * width + x] = rgb565;
  271. }
  272. }
  273. //解锁位图
  274. bmp.UnlockBits(bmpData);
  275. bmp.Dispose();
  276. return rgb565Data;
  277. }//using Bitmap
  278. }
  279. private bool SaveBigJpg(BigImage bigJpg, string fileName)
  280. {
  281. if (bigJpg.size_of_JPEG_data == 0)
  282. {
  283. //Debug.Write("bigJpg dataSize error!");
  284. AddMCULog("bigJpg dataSize error!");
  285. return false;
  286. }
  287. bool saveResult = false;
  288. try
  289. {
  290. //获取文件夹路径
  291. string directoryPath = Path.GetDirectoryName(fileName);
  292. //如果文件夹不存在,创建文件夹
  293. if (!Directory.Exists(directoryPath))
  294. {
  295. Directory.CreateDirectory(directoryPath);
  296. }
  297. //保存文件
  298. //File.WriteAllBytes(fileName, bigJpg.JPEG_data);
  299. using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
  300. {
  301. fs.Write(bigJpg.JPEG_data, 0, bigJpg.size_of_JPEG_data);
  302. }
  303. saveResult = true;
  304. }
  305. catch (Exception e)
  306. {
  307. AddMCULog(e.Message);
  308. //Debug.Write(e.Message);
  309. }
  310. string strResult = string.Format("save {0} {1}", fileName, saveResult ? "success" : "fail");
  311. //Debug.Write(strResult);
  312. AddMCULog(strResult);
  313. return saveResult;
  314. }
  315. //-------------------------------------------------------------------
  316. }
  317. //日志信息事件
  318. public class AiRealLogEventArgs : EventArgs
  319. {
  320. public string mLogInfo { get; }
  321. public AiRealLogEventArgs(string logInfo)
  322. {
  323. mLogInfo = logInfo;
  324. }
  325. }
  326. //---------------------------------------------------
  327. }