using AI.Common; using AI.Common.Log; using AI.Common.Tools; using UsHepatoRenalRatioDetectLib.OrganSegProcessModule; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using UsHepatoRenalRatioDetectLib.EchoROIAnalyserModule; using System.ComponentModel; using UsHepatoRenalRatioDetectLib.UsHRRCalculaterModule; namespace UsHepatoRenalRatioDetectLib { public class UsHepatoRenalRatioDetect : IUsHepatoRenalRatioDetect { #region private private readonly object _netNameLocker = new object(); private IOrganSegProcess _organSegProcess; private bool _isCropped = false; private volatile bool _initialized = false; private volatile bool _enable = false; private ConcurrentQueue _inputImages = new ConcurrentQueue(); private const int _queueMaxSize = 1; private readonly ManualResetEvent _waitImageEvent = new ManualResetEvent(true); private readonly ManualResetEvent _processFinishEvent = new ManualResetEvent(true); private Thread _imageProcessThread; private volatile bool _disposing = false; private IUsHRRAnalyser _echoAnalyser = new UsHRRAnalyser(); private IUsHRRCalculater _echoCalculater = new UsHRRCalculater(); private InferenceCore _inferenceCore = new InferenceCore(); #endregion #region 实现接口 /// /// 通知订阅者,有log要记 /// public event EventHandler NotifyLog; /// /// 通知订阅者,有错误发生 /// public event EventHandler NotifyError; /// /// 通知订阅者,肝肾比计算结果有更新 /// public event EventHandler NotifyProcessFinish; /// /// 初始化分割模型 /// /// 模型地址 /// 是否裁剪 public void Init(string netDir, bool isCropped) { if (!_initialized) { if (_organSegProcess == null) { _organSegProcess = new OrganSegProcess(); _organSegProcess.NotifyLog += OnLogWrite; int modelCpu = 1; // 设置inferCore的参数 _inferenceCore.SetConfig(EnumInferCoreConfigKey.CPU_THREADS_NUM, modelCpu.ToString(), EnumDeviceType.CPU); _organSegProcess.Init(_inferenceCore, EnumDeviceType.CPU, netDir); } _isCropped = isCropped; _initialized = true; } } /// /// 加载网络 /// public void LoadInferNet() { if (!_initialized) { NotifyError?.Invoke(this, new ErrorEventArgs(new Exception("HepatoRenalEchoContrastDetect should be initialized before use."))); } _organSegProcess.LoadGuideInferNet(); } /// /// 开始处理 /// public void StartProcess() { _enable = true; } /// /// 停止处理 /// public void StopProcess() { _enable = false; // 是否需要清空待处理队列里的数据? } /// /// 更新超声图像 /// /// public void UpdateUsImage(RawImage image) { if (!_initialized) { NotifyError?.Invoke(this, new ErrorEventArgs(new Exception("HepatoRenalEchoContrastDetect should be initialized before use."))); } if (_enable) { _inputImages.Enqueue(image.Clone()); _waitImageEvent.Set(); if (_imageProcessThread == null || !_imageProcessThread.IsAlive) { _imageProcessThread = new Thread(() => DoImageProcess()) { IsBackground = true, Name = "ImageProcess" }; _imageProcessThread.Start(); } } } /// /// 计算两个Roi区域内回声比值 /// /// /// /// /// public double GetHepatoRenalRatio(RawImage image, Rect rcLiver, Rect rcKidney) { EnumHRRStatus status = EnumHRRStatus.HRR_SUCCESSED; double hrrRatio = 0; try { status = _echoCalculater.GetHepatoRenalRatio(image, rcLiver, rcKidney, out hrrRatio); if (status!= EnumHRRStatus.HRR_SUCCESSED) { // 通知订阅者,预处理的结果有更新 NotifyProcessFinish?.Invoke(this, new UsHRRDetectUpdateEvent(status, new HRRDetectResultPerImg(), new Dictionary (), new RawImage())); } } catch (Exception excep) { NotifyError?.Invoke(this, new ErrorEventArgs(excep)); } return hrrRatio; } /// /// 主动销毁 /// public void Dispose() { DoDispose(); GC.SuppressFinalize(this); LogHelper.InfoLog("HepatoRenalEchoContrastDetect.Disposed manually.", string.Empty); } /// /// 析构 /// ~UsHepatoRenalRatioDetect() { DoDispose(); LogHelper.InfoLog("HepatoRenalEchoContrastDetect.Disposed by destructor.", string.Empty); } #endregion #region private funcs /// /// 对图像进行处理 /// private void DoImageProcess() { while (!_disposing) { if (_inputImages.Count > 0) { _inputImages.TryDequeue(out RawImage image); // 如果队列里待处理的数据过多,则对该图不做处理,直接跳到下一幅图 if (_inputImages.Count >= _queueMaxSize) { image.Dispose(); continue; } try { // 让dispose的线程等待执行完毕后再销毁 _processFinishEvent.Reset(); var totalStartTime = Environment.TickCount; var OraganSegStartTime = Environment.TickCount; // 对当前图像进行推理 var result = _organSegProcess.EvaluateOneImage(image, _isCropped); var OrganSegTime = Environment.TickCount - OraganSegStartTime; // 可能会存在检测出其他脏器的情况,先判断是否肝脏和肾脏都被检测出,如有未检测到的情况,后续不作处理 List detectOrgans = new List(); for (int ni = 0; ni < result.Count; ni++) { var detectedOb = result[ni]; if (detectedOb.Organ == EnumOrgans.Liver || detectedOb.Organ == EnumOrgans.Kidney) { detectOrgans.Add(detectedOb); } } SegResultPerOrgan[] segResult = new SegResultPerOrgan[detectOrgans.Count]; for (int ni = 0; ni < detectOrgans.Count; ni++) { var detectedOb = detectOrgans[ni]; segResult[ni] = new SegResultPerOrgan(detectedOb.Organ, detectedOb.Confidence, detectedOb.BoundingBox, detectedOb.Contours); } Dictionary rois = new Dictionary(); RawImage mask = new RawImage(); double ratio = 0; // 只有当肝肾都被检测到的时候才进行处理 if (detectOrgans.Count == 2) { EnumHRRStatus status = new EnumHRRStatus(); _echoAnalyser.Init(image, segResult[0].Contours[0], segResult[1].Contours[0]); status = _echoAnalyser.ImagePreProcess(/*out RawImage maskTmp*/); if (status != EnumHRRStatus.HRR_SUCCESSED) { // 通知订阅者,预处理的结果有更新 NotifyProcessFinish?.Invoke(this, new UsHRRDetectUpdateEvent(status, new HRRDetectResultPerImg(), new Dictionary(), new RawImage())); _echoAnalyser.Dispose(); // 用过后的图像销毁 image.Dispose(); // 执行完毕了,dispose的线程可以开始销毁了 _processFinishEvent.Set(); continue; } mask = _echoAnalyser.GetHRRMask(); status = _echoAnalyser.HRRROIDetect(out Rect[] roisDec); if (status != EnumHRRStatus.HRR_SUCCESSED) { // 通知订阅者,预处理的结果有更新 NotifyProcessFinish?.Invoke(this, new UsHRRDetectUpdateEvent(status, new HRRDetectResultPerImg(), new Dictionary(), new RawImage())); _echoAnalyser.Dispose(); // 用过后的图像销毁 image.Dispose(); mask.Dispose(); // 执行完毕了,dispose的线程可以开始销毁了 _processFinishEvent.Set(); continue; } status = _echoCalculater.GetHepatoRenalRatio(image, roisDec[0], roisDec[1], out ratio); if (status != EnumHRRStatus.HRR_SUCCESSED) { // 通知订阅者,预处理的结果有更新 NotifyProcessFinish?.Invoke(this, new UsHRRDetectUpdateEvent(status, new HRRDetectResultPerImg(), new Dictionary(), new RawImage())); _echoAnalyser.Dispose(); // 用过后的图像销毁 image.Dispose(); mask.Dispose(); // 执行完毕了,dispose的线程可以开始销毁了 _processFinishEvent.Set(); continue; } _echoAnalyser.Dispose(); rois.Add(EnumOrgans.Liver, roisDec[0]); rois.Add(EnumOrgans.Kidney, roisDec[1]); } // 用过后的图像销毁 image.Dispose(); // 执行完毕了,dispose的线程可以开始销毁了 _processFinishEvent.Set(); var totalProcessTime = Environment.TickCount - totalStartTime; Dictionary timeElapsed = new Dictionary(); timeElapsed.Add(EnumProcessTime.OrganSegProcessTime, OrganSegTime); timeElapsed.Add(EnumProcessTime.TotalTime, totalProcessTime); // 通知订阅者,预处理的结果有更新 NotifyProcessFinish?.Invoke(this, new UsHRRDetectUpdateEvent(EnumHRRStatus.HRR_SUCCESSED, new HRRDetectResultPerImg(segResult, rois, ratio), timeElapsed, mask)); mask.Dispose(); } catch (Exception excep) { _processFinishEvent.Set(); NotifyError?.Invoke(this, new ErrorEventArgs(excep)); } } else { // 如果已经没有要处理的数据了,就等有新数据输入的时候再继续while循环 _waitImageEvent.Reset(); _waitImageEvent.WaitOne(); } } } /// /// 销毁 /// private void DoDispose() { if (!_disposing) { _disposing = true; _waitImageEvent.Set(); _processFinishEvent.WaitOne(); if (_organSegProcess != null) { _organSegProcess.Dispose(); _organSegProcess.NotifyLog -= OnLogWrite; _organSegProcess = null; } while (_inputImages.Count > 0) { if (_inputImages.TryDequeue(out var input)) { input?.Dispose(); } } } } /// /// 有log要记 /// /// /// private void OnLogWrite(object sender, LogEventArgs e) { NotifyLog?.Invoke(sender, e); } #endregion } }