using MeterVision.Config; using MeterVision.db; using MeterVision.Helper; using MeterVision.model; using MeterVision.Util; using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using static MeterVision.FreeAi.FaImport; namespace MeterVision.FreeAi { //识别主程序 public class FaRun { //private FaLog faLog; //设备运行日志类 public static bool SendAiLogEnable = false; private StringBuilder mRunLog = new StringBuilder(); public event EventHandler OnAiRealLogInfo; private UdpSender udpSender; private static RealLogger realLogger; //public static bool RecordRealLogEnable = false; //实时日志记录 private static bool _recordRealLogEnable = false; public static bool RecordRealLogEnable { get => _recordRealLogEnable; set { if(_recordRealLogEnable != value) { _recordRealLogEnable = value; } if (!_recordRealLogEnable && realLogger != null) { realLogger.Close(); } } } //ai输出的日志回调函数 private void PrintfCallbackMethod(string message) { //Debug.Write(message); // 获取日志实例,将日志加入队列(不会创建新线程) //var logger = UdpLoggerSender.GetInstance(); //logger.EnqueueLog(message); // 只加入队列,避免创建过多线程 if (FaRun.SendAiLogEnable) { udpSender = UdpSender.GetInstance(); udpSender.SendLog(message); } if (FaRun.RecordRealLogEnable) { realLogger = RealLogger.GetInstance(); realLogger.Log(message); } //faLog.Append_aiLog(message); mRunLog.Append(message); //发送消息给主程序控件 OnAiRealLogInfo?.Invoke(this, new AiRealLogEventArgs(message)); } //增加MCU的日志 private void AddMCULog(string message) { mRunLog.Append(message + "\n"); OnAiRealLogInfo?.Invoke(this, new AiRealLogEventArgs(message)); } public ResultModel StartRecognition(object detailItem) { PrintfCallback callback = PrintfCallbackMethod; string srcImage = string.Empty; if(detailItem is SingleDetailItem) { srcImage = ((SingleDetailItem)detailItem).SrcImage; } else if(detailItem is PatchDetailItem) { srcImage = ((PatchDetailItem)detailItem).SrcImage; }else if(detailItem is TPatchDetail) { srcImage = ((TPatchDetail)detailItem).SrcImage; } else { return null; } //判断图像尺寸是否合规 if (!ThisApp.IsImageDimensionsValid(srcImage)) { Console.WriteLine($"{srcImage}图像尺寸不合规!"); return null; } short[] rgb565 = GetRGB565Array(srcImage); if (rgb565.Length != (320 * 240)) { throw new InvalidOperationException("无效的图像大小。"); } BeforeAI beforeAI = new BeforeAI(); if(detailItem is SingleDetailItem) { beforeAI = FaBefore.getBeforeAI((SingleDetailItem)detailItem); } else if(detailItem is PatchDetailItem) { beforeAI = FaBefore.getBeforeAI((PatchDetailItem)detailItem); } else if(detailItem is TPatchDetail) { beforeAI = FaBefore.getBeforeAI((TPatchDetail)detailItem); } AfterAI afterAI = new AfterAI(); SmallImage smallJpg = new SmallImage(); BigImage bigJpg = new BigImage(); //string onnxPath = ConfigItem.GetConfigItem().OnnxPath; string onnxPath = CfginiItem.GetConfigItem().OnnxPath; onnxPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, onnxPath); //判断onnxPath的路径是否存在 if (!File.Exists(onnxPath)) { throw new InvalidOperationException($"onnx文件{onnxPath}不存在!"); } //调用动态加载的方式 //初始化加载动态库, //string dllPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigItem.GetConfigItem().AiDll); string dllPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, CfginiItem.GetConfigItem().AiDll); if (!File.Exists(dllPath)) { throw new InvalidOperationException($"AI动态库文件{dllPath}不存在!"); } int result = -1; if (DynamicFaImport.Initialize(dllPath)) { try { result = DynamicFaImport.Recognition(rgb565, ref beforeAI, ref afterAI, ref smallJpg, ref bigJpg, onnxPath, callback); } catch (AccessViolationException ex) { // 处理异常,例如记录日志 Console.WriteLine("Access violation: " + ex.Message); } catch (Exception ex) { Console.WriteLine("Exeception: " + ex.Message); } } else { throw new InvalidOperationException($"初始化AI动态库{dllPath}失败!"); } DynamicFaImport.Unload(); //存储图像 string dstImagPath = CfginiItem.GetConfigItem().DstImgPath; dstImagPath = Path.Combine(dstImagPath, ThisApp.GetNowTime_yyyyMMdd()); if (!Directory.Exists(dstImagPath)) { Directory.CreateDirectory(dstImagPath); } dstImagPath = Path.Combine(dstImagPath, Guid.NewGuid().ToString() + ".jpg"); SaveBigJpg(bigJpg, dstImagPath); //存储日志 string aiLogPath = CfginiItem.GetConfigItem().AiLogPath; aiLogPath = Path.Combine(aiLogPath, ThisApp.GetNowTime_yyyyMMdd()); if (!Directory.Exists(aiLogPath)) { Directory.CreateDirectory(aiLogPath); } aiLogPath = Path.Combine(aiLogPath, Guid.NewGuid().ToString() + ".txt"); try { if (LicenseMana.mLicenseModel != null && LicenseMana.mLicenseModel.IsPermanent) { File.WriteAllText(aiLogPath, mRunLog.ToString()); } else { File.WriteAllText(aiLogPath, ""); } } catch (Exception ex) { throw new InvalidOperationException($"保存文件{aiLogPath}失败:{ex.Message}"); } //结果对象赋值 ResultModel resultModel = new ResultModel { SrcImage = srcImage, DstImage = dstImagPath, LogPath = aiLogPath, ResultMeter = afterAI.METER_TYPE, //1,2,7,8 ResultType = afterAI.AI_RESULT_ARRAY[11], RawValue = afterAI.INIT_AI_RESULT, FinalValue = afterAI.AI_RESULT, CompleteValue = afterAI.AI_COMPLETE_RESULT, ValueChanged = afterAI.IS_VALUE_CHANGED, CompressIndex = afterAI.COMPRESS_JPG_INDEX, }; if (beforeAI.METER_TYPE == 1 || beforeAI.METER_TYPE == 3) { resultModel.FeatureRegions = $"{afterAI.CONFIG_NUM_REGION[0]},{afterAI.CONFIG_NUM_REGION[1]} " + $"{afterAI.CONFIG_NUM_REGION[2]},{afterAI.CONFIG_NUM_REGION[3]} " + $"{afterAI.CONFIG_NUM_REGION[4]},{afterAI.CONFIG_NUM_REGION[5]} " + $"{afterAI.CONFIG_NUM_REGION[6]},{afterAI.CONFIG_NUM_REGION[7]}"; resultModel.MeterRegions = $"{afterAI.CONFIG_METER_REGION[0]}," + $"{afterAI.CONFIG_METER_REGION[1]} " + $"{afterAI.CONFIG_METER_REGION[2]}," + $"{afterAI.CONFIG_METER_REGION[3]}"; } else if (beforeAI.METER_TYPE == 2) { resultModel.FeatureRegions = $"{afterAI.CONFIG_TWO_IND[0]}," + $"{afterAI.CONFIG_TWO_IND[1]} " + $"{afterAI.CONFIG_TWO_IND[2]}," + $"{afterAI.CONFIG_TWO_IND[3]}"; resultModel.MeterRegions = $"{afterAI.CONFIG_METER_REGION[0]}," + $"{afterAI.CONFIG_METER_REGION[1]} " + $"{afterAI.CONFIG_METER_REGION[2]}," + $"{afterAI.CONFIG_METER_REGION[3]}"; } else { resultModel.MeterRegions = ""; resultModel.FeatureRegions = ""; } resultModel.AiVer = BitConverter.ToString(afterAI.AI_VER).Replace("-", ""); resultModel.DebugInfoBytes = afterAI.AI_RESULT_ARRAY; return resultModel; } private short[] GetRGB565Array(string jpgFilePath) { using (Bitmap bmp = new Bitmap(jpgFilePath)) { int width = bmp.Width; int height = bmp.Height; //string message = string.Format("width = %d,height = %d", width, height); string message = $"width = {width}, height = {height}"; AddMCULog(message); //创建数组存储RGB565数据 short[] rgb565Data = new short[width * height]; //给它多分配1倍的内存 //short[] rgb565Data = new short[width * height*2]; //锁定位图内存 BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); IntPtr ptr = bmpData.Scan0; //创建数据存储RGB888数据 byte[] rgb888Data = new byte[Math.Abs(bmpData.Stride) * height]; //将像素数据拷贝到字节数组中 Marshal.Copy(ptr, rgb888Data, 0, rgb888Data.Length); // 逐个像素转换为 RGB565 格式,并进行上下颠倒处理 for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // 颠倒行的顺序 int invertedY = height - 1 - y; //int index = y * bmpData.Stride + x * 3; int index = invertedY * bmpData.Stride + x * 3; byte r = rgb888Data[index + 2]; // R 通道 byte g = rgb888Data[index + 1]; // G 通道 byte b = rgb888Data[index]; // B 通道 // 将 RGB888 转换为 RGB565 short rgb565 = (short)(((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)); rgb565Data[y * width + x] = rgb565; } } //解锁位图 bmp.UnlockBits(bmpData); bmp.Dispose(); return rgb565Data; }//using Bitmap } private bool SaveBigJpg(BigImage bigJpg, string fileName) { if (bigJpg.size_of_JPEG_data == 0) { //Debug.Write("bigJpg dataSize error!"); AddMCULog("bigJpg dataSize error!"); return false; } bool saveResult = false; try { //获取文件夹路径 string directoryPath = Path.GetDirectoryName(fileName); //如果文件夹不存在,创建文件夹 if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } //保存文件 //File.WriteAllBytes(fileName, bigJpg.JPEG_data); using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write)) { fs.Write(bigJpg.JPEG_data, 0, bigJpg.size_of_JPEG_data); } saveResult = true; } catch (Exception e) { AddMCULog(e.Message); //Debug.Write(e.Message); } string strResult = string.Format("save {0} {1}", fileName, saveResult ? "success" : "fail"); //Debug.Write(strResult); AddMCULog(strResult); return saveResult; } //------------------------------------------------------------------- } //日志信息事件 public class AiRealLogEventArgs : EventArgs { public string mLogInfo { get; } public AiRealLogEventArgs(string logInfo) { mLogInfo = logInfo; } } //--------------------------------------------------- }