using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; using SkiaSharp; using Vinno.DataManager.Infrastructure; using Vinno.DataManager.Utilities; using Vinno.DataTypes; using WingServerCommon.Log; namespace WingAIDiagnosisService.URMManage { public partial class URMAnalysisManager { public static List UrmProcessorList = new List(); public static List VideoProcessorList = new List(); private void WatchingVideoProcessor() { Task.Run(async () => { Logger.WriteLineInfo($"URMAnalysisManager WatchingVideoProcessor start"); try { while (true) { await Task.Delay(TimeSpan.FromSeconds(60)); Logger.WriteLineInfo($"UrmProcessorList count1:{UrmProcessorList.Count}"); for (int i = UrmProcessorList.Count - 1; i >= 0; i--) { try { var item = UrmProcessorList[i]; if (item.LastActiveTime <= DateTime.UtcNow.AddMinutes(-1)) { item.Processor.Dispose(); DisposeArraySafely(() => { item.DenArray.Dispose(); }); DisposeArraySafely(() => { item.DirArray.Dispose(); }); DisposeArraySafely(() => { item.VelArray.Dispose(); }); DisposeArraySafely(() => { item.MaskArray.Dispose(); }); DisposeArraySafely(() => { item.AngleArray.Dispose(); }); UrmProcessorList.Remove(item); } } catch (Exception ex) { Logger.WriteLineError($"URMAnalysisManager WatchingVideoProcessor UrmProcessorList error:{ex}"); } } Logger.WriteLineInfo($"UrmProcessorList count2:{UrmProcessorList.Count}"); Logger.WriteLineInfo($"VideoProcessorList count1:{VideoProcessorList.Count}"); for (int i = VideoProcessorList.Count - 1; i >= 0; i--) { try { var item = VideoProcessorList[i]; if (item.LastActiveTime <= DateTime.UtcNow.AddMinutes(-1)) { item.Processor.Dispose(); DisposeArraySafely(() => { item.DenArray.Dispose(); }); DisposeArraySafely(() => { item.DirArray.Dispose(); }); DisposeArraySafely(() => { item.VelArray.Dispose(); }); DisposeArraySafely(() => { item.MaskArray.Dispose(); }); DisposeArraySafely(() => { item.AngleArray.Dispose(); }); VideoProcessorList.Remove(item); } } catch (Exception ex) { Logger.WriteLineError($"URMAnalysisManager WatchingVideoProcessor VideoProcessorList error:{ex}"); } } Logger.WriteLineInfo($"VideoProcessorList count2:{VideoProcessorList.Count}"); } } catch (Exception e) { Logger.WriteLineError($"URMAnalysisManager WatchingVideoProcessor error:{e}"); } }); } /// /// URM后处理 Draw Image /// /// public async Task DoUrmProcess(UrmProcessRequest request) { var result = new WingInterfaceLibrary.Request.RemedicalAISelected.URMProcessResult(); Logger.WriteLineInfo($"AIDiagnosis DoUrmProcess InitURMProcessor,GUID:{request.GUID},Token:{request.Token},RemedicalCode:{request.RemedicalCode}"); await InitURMProcessor(request); try { var processorClass = UrmProcessorList.FirstOrDefault(x => x.GUID == request.GUID); processorClass.LastActiveTime = DateTime.UtcNow; var processor = processorClass.Processor; using (await _lockManager.Acquire(request.GUID)) { await Task.Run(() => { double urmMinVal = 0; double urmMaxVal = 0; //赋值 processor.setUrmParams(RecordParams.UrmImageType, request.UrmImageType); processor.setUrmParams(RecordParams.UrmBlend, request.UrmBlend); processor.setUrmParams(RecordParams.URMDownSampleIndex, request.DownsampleIndex); processor.setUrmParams(RecordParams.URMIntPowerDen, request.IntPowerDen); processor.setUrmParams(RecordParams.URMIntPowerDir, request.IntPowerDir); processor.setUrmParams(RecordParams.URMSigmaGauss, request.SigmaGauss); processor.setUrmParams(RecordParams.URMVessScale, request.VessScale); processor.setUrmParams(RecordParams.URMVelMaxScaler, request.VelMaxScaler); processor.setUrmParams(RecordParams.URMVelMinScaler, request.VelMinScaler); processor.setUrmParams(RecordParams.URMIterations, request.Iterations); processor.setUrmBaseParam(request.Res, processorClass.DenArray, processorClass.DirArray, processorClass.VelArray, processorClass.AngleArray, processorClass.MaskArray, request.Urmsrcwidth, request.Urmsrcheight, request.ScaleOfPixel_x, request.ScaleOfPixel_y, request.ImgProcessVer); processor.setUrmDrawParam(request.ZoomOn, request.ZoomRoix, request.ZoomRoiy, request.ZoomRoiwidth, request.ZoomRoiheight, request.Roix, request.Roiy, request.Roiwidth, request.Roiheight, request.LeftRight, request.UpDown, request.ScreenWidth, request.ScreenHeight); processor.CalTracePointMask(request.UrmTraceDPoints); WingServerCommon.Log.Logger.WriteLineInfo($"getURMImageBase64,GUID:{request.GUID},token:{request.Token},RemedicalCode:{request.RemedicalCode}"); result.Base64String = processor.getURMImageBase64(true, ref urmMinVal, ref urmMaxVal); result.UrmMaxVal = urmMaxVal; result.UrmMinVal = urmMinVal; processorClass.UrmMinVal = urmMinVal; processorClass.UrmMaxVal = urmMaxVal; processorClass.HasDrawed = true; Logger.WriteLineInfo("AIDiagnosis DoUrmProcess end"); }); } } catch (Exception ex) { Logger.WriteLineWarn($"AIService URMAnalysisManager DoUrmProcess error, ex:{ex}"); } return result; } /// /// URM获取colorbar /// /// public async Task CreateUrmColorbarImage(UrmProcessRequest request) { var imgBase64 = ""; await InitURMProcessor(request); try { var processorClass = UrmProcessorList.FirstOrDefault(x => x.GUID == request.GUID); processorClass.LastActiveTime = DateTime.UtcNow; var processor = processorClass.Processor; try { using (await _lockManager.Acquire(request.GUID)) { await Task.Run(() => { //赋值 processor.setUrmParams(RecordParams.UrmImageType, request.UrmImageType); processor.setUrmParams(RecordParams.UrmBlend, request.UrmBlend); processor.setUrmParams(RecordParams.URMDownSampleIndex, request.DownsampleIndex); processor.setUrmParams(RecordParams.URMIntPowerDen, request.IntPowerDen); processor.setUrmParams(RecordParams.URMIntPowerDir, request.IntPowerDir); processor.setUrmParams(RecordParams.URMSigmaGauss, request.SigmaGauss); processor.setUrmParams(RecordParams.URMVessScale, request.VessScale); processor.setUrmParams(RecordParams.URMVelMaxScaler, request.VelMaxScaler); processor.setUrmParams(RecordParams.URMVelMinScaler, request.VelMinScaler); processor.setUrmParams(RecordParams.URMIterations, request.Iterations); processor.setUrmBaseParam(request.Res, processorClass.DenArray, processorClass.DirArray, processorClass.VelArray, processorClass.AngleArray, processorClass.MaskArray, request.Urmsrcwidth, request.Urmsrcheight, request.ScaleOfPixel_x, request.ScaleOfPixel_y, request.ImgProcessVer); processor.setUrmDrawParam(request.ZoomOn, request.ZoomRoix, request.ZoomRoiy, request.ZoomRoiwidth, request.ZoomRoiheight, request.Roix, request.Roiy, request.Roiwidth, request.Roiheight, request.LeftRight, request.UpDown, request.ScreenWidth, request.ScreenHeight); //colorbar WingServerCommon.Log.Logger.WriteLineInfo($"CreateUrmColorbarImage,GUID:{request.GUID},token:{request.Token},RemedicalCode:{request.RemedicalCode}"); imgBase64 = processor.CreateUrmColorbarImage(); }); } } catch (Exception ex) { WingServerCommon.Log.Logger.WriteLineError($"_urmProcessAlg.CreateUrmColorbarImage error :{ex}"); } } catch (Exception ex) { Logger.WriteLineWarn($"AIService URMAnalysisManager DoUrmProcess error, ex:{ex}"); } return imgBase64; } /// /// URM后处理 Measure Test /// /// /// public async Task MeasureProcess(string remedicalCode, UrmMeasureProcessRequest request) { WingInterfaceLibrary.Request.RemedicalAISelected.URMMeasureProcessResult outResult = new WingInterfaceLibrary.Request.RemedicalAISelected.URMMeasureProcessResult(); Logger.WriteLineInfo($"AIDiagnosis MeasureProcess,UrmMeasureType:{request.UrmMeasureType},GUID:{request.GUID},Token:{request.Token},RemedicalCode:{request.RemedicalCode}"); await InitURMProcessor(request); try { var processor = UrmProcessorList.FirstOrDefault(x => x.GUID == request.GUID); processor.LastActiveTime = DateTime.UtcNow; using (await _lockManager.Acquire(request.GUID)) { var urmMinVal = 0; var urmMaxVal = 0; await Task.Run(() => { // processor.Processor.getUrmVal(ref urmMinVal, ref urmMaxVal); int samplingPoints = 256; // 采样点数量 (cmlength 不传的话,默认是 256) if (request.CMlength != null) { samplingPoints = (int)(request.CMlength * 1000); } URMMeasure urmMeasure = new URMMeasure(processor.Processor); var param = new URMMeasureDataInput(); param.SrcDPoints = request.SrcDPoints; param.phywidth = request.Phywidth; if (request.ROIType != 0) { param.RoiType = request.ROIType; } param.SamplingPoints = samplingPoints; param.urmMeasureType = request.UrmMeasureType; param.ShellWidth = request.ShellWidth; WingServerCommon.Log.Logger.WriteLineInfo($"CalURMData,GUID:{request.GUID},token:{request.Token},RemedicalCode:{request.RemedicalCode}"); var result = urmMeasure.CalURMData(param, request.ScreenWidth, request.ScreenHeight, urmMaxVal, urmMinVal); // 获取灌注图 example IntPtr imgPtr = result.PerfusionImgData.Start; var perfusionImgBase64 = ConvertImageToBase64(remedicalCode, imgPtr, result.PerfusionPiexlRect.Width, result.PerfusionPiexlRect.Height); outResult = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(result)); outResult.PerfusionImgBase64 = perfusionImgBase64; outResult.UrmMaxVal = urmMaxVal; outResult.UrmMinVal = urmMinVal; }); } return outResult; } catch (Exception ex) { Logger.WriteLineWarn($"AIDiagnosisService URMAnalysisManager MeasureProcess error, ex:{ex}"); outResult.PerfusionImgBase64 = string.Empty; return null; } } public string ConvertImageToBase64(string remedicalCode, IntPtr imgPtr, int W, int H) { try { // 创建SKImageInfo以描述图像信息 SKImageInfo imageInfo = new SKImageInfo(W, H, SKColorType.Bgra8888, SKAlphaType.Premul); // 创建SKBitmap并复制图像数据 using (SKBitmap bitmap = new SKBitmap()) { bitmap.InstallPixels(imageInfo, imgPtr, W * 4, (addr, ctx) => { }, IntPtr.Zero); // 将SKBitmap编码为PNG格式的数据 using (MemoryStream memoryStream = new MemoryStream()) { using (SKImage skImage = SKImage.FromBitmap(bitmap)) { skImage.Encode(SKEncodedImageFormat.Png, 100).SaveTo(memoryStream); byte[] imageBytes = memoryStream.ToArray(); return Convert.ToBase64String(imageBytes); } } } } catch (Exception ex) { Logger.WriteLineWarn($"AIDiagnosis URMAnalysisManager ConvertImageToBase64 failed, remedicalCode:{remedicalCode}, W:{W}, H:{H}. ex:{ex}"); return string.Empty; } } /// /// URM后处理 Draw One frame /// /// /// public string DoUrmVideoProcess(DoUrmVideoProcessRequest request, ref double urmMinVal, ref double urmMaxVal) { var imgBase64 = ""; urmMinVal = 0; urmMaxVal = 0; InitVideoProcessor(request); try { var videoProcessor = VideoProcessorList.FirstOrDefault(x => x.GUID == request.GUID); videoProcessor.LastActiveTime = DateTime.UtcNow; urmMinVal = videoProcessor.UrmMinVal; urmMaxVal = videoProcessor.UrmMaxVal; imgBase64 = videoProcessor.Processor.getURMVideoImg(request.VideoFrame); } catch (Exception ex) { Logger.WriteLineWarn($"AIService URMAnalysisManager DoUrmVideoProcess error, ex:{ex}"); } return imgBase64; } public URMProcessorClass InitVideoProcessor(DoUrmVideoProcessRequest request) { URMProcessorClass processorClass = null; try { processorClass = VideoProcessorList.FirstOrDefault(x => x.GUID == request.GUID); if (processorClass == null) { double urmMaxVal = 0; double urmMinVal = 0; NativeArray DenArray = ResultDataIOHelper.ReadDoubleArrayFromFile(request.DenDataPath, request.Urmsrcwidth * request.Urmsrcheight); //Den的分析后数据 NativeArray DirArray = ResultDataIOHelper.ReadDoubleArrayFromFile(request.DirDataPath, request.Urmsrcwidth * request.Urmsrcheight); // Dir的分析后数据 NativeArray VelArray = ResultDataIOHelper.ReadDoubleArrayFromFile(request.VelDataPath, request.Urmsrcwidth * request.Urmsrcheight); // Vel的分析后数据 NativeArray AngleArray = ResultDataIOHelper.ReadDoubleArrayFromFile(request.AngleDataPath, request.Urmsrcwidth * request.Urmsrcheight); // 360图的数据 NativeArray MaskArray = ResultDataIOHelper.ReadByteArrayFromFile(request.MaskDataPath, request.Urmsrcwidth * request.Urmsrcheight); // Mask URMPoint[] URMPoints = ResultDataIOHelper.ReadURMPointsFromFile(request.PointsDataPath); int[] URMPointNums = ResultDataIOHelper.ReadURMPointNumsFromFile(request.PointNumsDataPath); // 参数设置 var videoProcessor = new URMProcess(); bool initSuccess = videoProcessor.init(request.FamilyName, request.TypeInfo, request.NativeId); // 设置视频配置 videoProcessor.setUrmParams(RecordParams.URMVideoScaler, request.URMVideoScaler); videoProcessor.setUrmParams(RecordParams.URMVideoParameter, request.URMVideoParameter); videoProcessor.setUrmParams(RecordParams.URMVideoType, request.URMVideoType); // 设置图像配置 videoProcessor.setUrmParams(RecordParams.UrmImageType, request.UrmImageType); videoProcessor.setUrmParams(RecordParams.UrmBlend, request.UrmBlend); videoProcessor.setUrmParams(RecordParams.URMDownSampleIndex, request.DownsampleIndex); videoProcessor.setUrmParams(RecordParams.URMIntPowerDen, request.IntPowerDen); videoProcessor.setUrmParams(RecordParams.URMIntPowerDir, request.IntPowerDir); videoProcessor.setUrmParams(RecordParams.URMSigmaGauss, request.SigmaGauss); videoProcessor.setUrmParams(RecordParams.URMVessScale, request.VessScale); videoProcessor.setUrmParams(RecordParams.URMVelMaxScaler, request.VelMaxScaler); videoProcessor.setUrmParams(RecordParams.URMVelMinScaler, request.VelMinScaler); videoProcessor.setUrmParams(RecordParams.URMIterations, request.Iterations); videoProcessor.setUrmBaseParam(request.Res, DenArray, DirArray, VelArray, AngleArray, MaskArray, request.Urmsrcwidth, request.Urmsrcheight, request.ScaleOfPixel_x, request.ScaleOfPixel_y, request.ImgProcessVer); videoProcessor.setUrmDrawParam(request.ZoomOn, request.ZoomRoix, request.ZoomRoiy, request.ZoomRoiwidth, request.ZoomRoiheight, request.Roix, request.Roiy, request.Roiwidth, request.Roiheight, request.LeftRight, request.UpDown, request.ScreenWidth, request.ScreenHeight ); videoProcessor.PreURMVideo(URMPoints, URMPointNums, ref urmMaxVal, ref urmMinVal); videoProcessor.CalTracePointMask(request.UrmTraceDPoints); processorClass = new URMProcessorClass { GUID = request.GUID, Processor = videoProcessor, LastActiveTime = DateTime.UtcNow, UrmMinVal = urmMinVal, UrmMaxVal = urmMaxVal }; VideoProcessorList.Add(processorClass); } } catch (Exception ex) { Logger.WriteLineWarn($"AIService URMAnalysisManager InitVideoProcessor error, ex:{ex}"); } return processorClass; } public async Task InitURMProcessor(UrmProcessRequest request) { Logger.WriteLineInfo($"AIDiagnosis DoUrmProcess InitURMProcessor start,GUID:{request.GUID},Token:{request.Token},RemedicalCode:{request.RemedicalCode}"); URMProcessorClass processorClass = null; try { using (await _lockManager.Acquire(request.GUID)) { processorClass = UrmProcessorList.FirstOrDefault(x => x.GUID == request.GUID); if (processorClass == null) { Logger.WriteLineInfo($"AIDiagnosis DoUrmProcess InitURMProcessor ReadFile,GUID:{request.GUID},Token:{request.Token},RemedicalCode:{request.RemedicalCode}"); NativeArray DenArray = ResultDataIOHelper.ReadDoubleArrayFromFile(request.DenDataPath, request.Urmsrcwidth * request.Urmsrcheight); //Den的分析后数据 NativeArray DirArray = ResultDataIOHelper.ReadDoubleArrayFromFile(request.DirDataPath, request.Urmsrcwidth * request.Urmsrcheight); // Dir的分析后数据 NativeArray VelArray = ResultDataIOHelper.ReadDoubleArrayFromFile(request.VelDataPath, request.Urmsrcwidth * request.Urmsrcheight); // Vel的分析后数据 NativeArray AngleArray = ResultDataIOHelper.ReadDoubleArrayFromFile(request.AngleDataPath, request.Urmsrcwidth * request.Urmsrcheight); // 360图的数据 NativeArray MaskArray = ResultDataIOHelper.ReadByteArrayFromFile(request.MaskDataPath, request.Urmsrcwidth * request.Urmsrcheight); // Mask Logger.WriteLineInfo($"AIDiagnosis DoUrmProcess InitURMProcessor init,GUID:{request.GUID},Token:{request.Token},RemedicalCode:{request.RemedicalCode}"); // 参数设置 var urmProcessor = new URMProcess(); urmProcessor.init(request.FamilyName, request.TypeInfo, request.NativeId); //测量 if (request.ProcessType == 3) { //赋值 urmProcessor.setUrmParams(RecordParams.UrmImageType, request.UrmImageType); urmProcessor.setUrmParams(RecordParams.UrmBlend, request.UrmBlend); urmProcessor.setUrmParams(RecordParams.URMDownSampleIndex, request.DownsampleIndex); urmProcessor.setUrmParams(RecordParams.URMIntPowerDen, request.IntPowerDen); urmProcessor.setUrmParams(RecordParams.URMIntPowerDir, request.IntPowerDir); urmProcessor.setUrmParams(RecordParams.URMSigmaGauss, request.SigmaGauss); urmProcessor.setUrmParams(RecordParams.URMVessScale, request.VessScale); urmProcessor.setUrmParams(RecordParams.URMVelMaxScaler, request.VelMaxScaler); urmProcessor.setUrmParams(RecordParams.URMVelMinScaler, request.VelMinScaler); urmProcessor.setUrmParams(RecordParams.URMIterations, request.Iterations); urmProcessor.setUrmBaseParam(request.Res, DenArray, DirArray, VelArray, AngleArray, MaskArray, request.Urmsrcwidth, request.Urmsrcheight, request.ScaleOfPixel_x, request.ScaleOfPixel_y, request.ImgProcessVer); urmProcessor.setUrmDrawParam(request.ZoomOn, request.ZoomRoix, request.ZoomRoiy, request.ZoomRoiwidth, request.ZoomRoiheight, request.Roix, request.Roiy, request.Roiwidth, request.Roiheight, request.LeftRight, request.UpDown, request.ScreenWidth, request.ScreenHeight); urmProcessor.CalTracePointMask(request.UrmTraceDPoints); urmProcessor.GetURMImage(); } Logger.WriteLineInfo($"AIDiagnosis DoUrmProcess InitURMProcessor setUrmParams,GUID:{request.GUID},Token:{request.Token},RemedicalCode:{request.RemedicalCode}"); processorClass = new URMProcessorClass { GUID = request.GUID, Processor = urmProcessor, LastActiveTime = DateTime.UtcNow, DenArray = DenArray, DirArray = DirArray, VelArray = VelArray, AngleArray = AngleArray, MaskArray = MaskArray }; UrmProcessorList.Add(processorClass); Logger.WriteLineInfo($"AIDiagnosis DoUrmProcess InitURMProcessor end,GUID:{request.GUID},Token:{request.Token},RemedicalCode:{request.RemedicalCode}"); } } } catch (Exception ex) { Logger.WriteLineWarn($"AIService URMAnalysisManager InitURMProcessor error, ex:{ex}"); } return processorClass; } private URMProcess SetUrmProcessorByParams(URMProcessorClass processorClass, UrmProcessRequest request) { processorClass.LastActiveTime = DateTime.UtcNow; var UrmProcessor = processorClass.Processor; UrmProcessor.setUrmParams(RecordParams.UrmImageType, request.UrmImageType); UrmProcessor.setUrmParams(RecordParams.UrmBlend, request.UrmBlend); UrmProcessor.setUrmParams(RecordParams.URMDownSampleIndex, request.DownsampleIndex); UrmProcessor.setUrmParams(RecordParams.URMIntPowerDen, request.IntPowerDen); UrmProcessor.setUrmParams(RecordParams.URMIntPowerDir, request.IntPowerDir); UrmProcessor.setUrmParams(RecordParams.URMSigmaGauss, request.SigmaGauss); UrmProcessor.setUrmParams(RecordParams.URMVessScale, request.VessScale); UrmProcessor.setUrmParams(RecordParams.URMVelMaxScaler, request.VelMaxScaler); UrmProcessor.setUrmParams(RecordParams.URMVelMinScaler, request.VelMinScaler); UrmProcessor.setUrmParams(RecordParams.URMIterations, request.Iterations); UrmProcessor.setUrmBaseParam(request.Res, processorClass.DenArray, processorClass.DirArray, processorClass.VelArray, processorClass.AngleArray, processorClass.MaskArray, request.Urmsrcwidth, request.Urmsrcheight, request.ScaleOfPixel_x, request.ScaleOfPixel_y, request.ImgProcessVer); UrmProcessor.setUrmDrawParam(request.ZoomOn, request.ZoomRoix, request.ZoomRoiy, request.ZoomRoiwidth, request.ZoomRoiheight, request.Roix, request.Roiy, request.Roiwidth, request.Roiheight, request.LeftRight, request.UpDown, request.ScreenWidth, request.ScreenHeight); return UrmProcessor; } public static void DisposeArraySafely(Action disposeAction) { try { disposeAction.Invoke(); } catch (Exception ex) { Logger.WriteLineWarn("An error occurred during array disposal: " + ex.Message); } } } }