FaRun.cs 11 KB

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