Browse Source

引入2d测量切面壳子的接口

Jimmy 2 years ago
parent
commit
d3a1f02cee

+ 6 - 1
fis/Managers/Interfaces/IUltra3DManager.cs

@@ -1,6 +1,7 @@
 using fis.Managers.Interfaces;
 using fis.Win.Dev.Managers.Modules.Ultra3D;
 using fis.Win.Dev.Win.Ultra3D.manager;
+using fis.Win.Dev.Win.Ultra3D.Manager;
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -11,7 +12,11 @@ namespace fis.Win.Dev.Managers.Interfaces
 {
     internal interface IUltra3DManager : IFisManager
     {
-        Parse3DModelManager Parse3DModelManager { get; set; }
+        Parse3DModelManager Parse3DModelManager { get; }
+
+        MeasureImageManager MeasureImageManager { get; }
+
+        CarotidModelAdjustManager CarotidModelAdjustManager { get; }
 
         void AccessUltra3DFiles(Ultr3DParameter ultr3DParameter);
     }

+ 7 - 1
fis/Managers/Ultra3DManager.cs

@@ -4,6 +4,7 @@ using fis.Win.Dev.Managers.Interfaces;
 using fis.Win.Dev.Managers.Modules.Ultra3D;
 using fis.Win.Dev.Utilities;
 using fis.Win.Dev.Win.Ultra3D.manager;
+using fis.Win.Dev.Win.Ultra3D.Manager;
 using fis.Win.Dev.Win.Ultra3D.Utils;
 using System;
 using System.Collections.Generic;
@@ -17,13 +18,18 @@ namespace fis.Win.Dev.Managers
 {
     internal class Ultra3DManager : IUltra3DManager
     {
-        public Parse3DModelManager Parse3DModelManager { get; set; }
+        public Parse3DModelManager Parse3DModelManager { get; }
+        public MeasureImageManager MeasureImageManager { get; }
+        public CarotidModelAdjustManager CarotidModelAdjustManager { get; }
+
         private Ultra3DDownloadWorker _ultr3DFileWorker;
         private object _lock = new object();
 
         internal Ultra3DManager()
         {
             Parse3DModelManager = new Parse3DModelManager();
+            MeasureImageManager=new MeasureImageManager();
+            CarotidModelAdjustManager = new CarotidModelAdjustManager(Parse3DModelManager, MeasureImageManager);
             _ultr3DFileWorker = new Ultra3DDownloadWorker();
             _ultr3DFileWorker.MainSurfaceFileReady += OnMainSurfaceReady ;
             _ultr3DFileWorker.MainMDFileReady += OnMainMDFileReady;

+ 22 - 1
fis/Utilities/FisBrowserScriptObject.cs

@@ -73,7 +73,26 @@ namespace fis.Win.Dev.Utilities
         }
 
         /// <summary>
-        /// Get clip plane data.
+        /// 调取切面2D图像
+        /// 切换到测量模式
+        /// </summary>
+        public string SwitchMeasureMode(string cefInputData)
+        {
+            try
+            {
+                var cefData = JsonConvert.DeserializeObject<CefInputData>(cefInputData.ToString());
+                _ultr3DManager.MeasureImageManager.SwitchDisplayMode(DisplayMode.Measure, cefData, _ultr3DManager.Parse3DModelManager);
+
+                return _ultr3DManager.MeasureImageManager.GetCurrentMeasureData();
+            }
+            catch
+            {
+                return string.Empty;
+            }
+        }
+
+        /// <summary>
+        /// 设置3d数据访问列表
         /// </summary>
         public void SetUltr3DData(string ultr3DDataStr)
         {
@@ -84,6 +103,8 @@ namespace fis.Win.Dev.Utilities
             }
         }
 
+
+
         /// <summary>
         /// get vessel plane points
         /// </summary>

+ 418 - 0
fis/Win/Ultra3D/Manager/CarotidModelAdjustManager.cs

@@ -0,0 +1,418 @@
+using Emgu.CV;
+using Emgu.CV.CvEnum;
+using Emgu.CV.Structure;
+using fis.Log;
+using fis.Win.Dev.Win.Ultra3D.Carotid;
+using fis.Win.Dev.Win.Ultra3D.Carotid.ImageProcess;
+using fis.Win.Dev.Win.Ultra3D.manager;
+using fis.Win.Dev.Win.Ultra3D.Utils;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace fis.Win.Dev.Win.Ultra3D.Manager
+{
+    public class CarotidModelAdjustManager
+    {
+        private readonly MeasureImageManager _measureImageManager;
+        private readonly Parse3DModelManager _parse3DModelManager;
+
+        private readonly ImageProcessQueue _processQueue;
+        private DisplayMode _displayMode;
+
+        /// <summary>
+        /// Get image parameter wrapper.
+        /// </summary>
+        public ImageParameterWrapper ParameterWrapper { get; }
+
+        /// <summary>
+        /// Trigger when image parameter changed.
+        /// </summary>
+        public event EventHandler<Carotid3DImagesArgBase> ImageParameterChanged;
+
+        public CarotidModelAdjustManager(Parse3DModelManager parse3DModelManager, MeasureImageManager measureImageManager)
+        {
+            _measureImageManager = measureImageManager;
+            _parse3DModelManager = parse3DModelManager;
+            _measureImageManager.DisplayModeChanged += OnDisplayModeChanged;
+            _processQueue = new ImageProcessQueue(6);
+            var bParameter = new BrightnessParameter();
+            var cParameter = new ContrastParameter();
+            var sParameter = new SharpnessParameter();
+            ParameterWrapper = new ImageParameterWrapper(cParameter, bParameter, sParameter);
+            bParameter.ValueChanged += OnParameterValueChanged;
+            cParameter.ValueChanged += OnParameterValueChanged;
+            sParameter.ValueChanged += OnParameterValueChanged;
+            if (!Directory.Exists(InfoConstant.RootFolder))
+            {
+                Directory.CreateDirectory(InfoConstant.RootFolder);
+            }
+            if (!Directory.Exists(InfoConstant.TempClipImgFolder))
+            {
+                Directory.CreateDirectory(InfoConstant.TempClipImgFolder);
+            }
+
+        }
+
+
+        protected void OnDisposeManagedResource()
+        {
+            _measureImageManager.DisplayModeChanged -= OnDisplayModeChanged;
+            ParameterWrapper.Brightness.ValueChanged -= OnParameterValueChanged;
+            ParameterWrapper.Contrast.ValueChanged -= OnParameterValueChanged;
+            ParameterWrapper.Sharpness.ValueChanged -= OnParameterValueChanged;
+
+        }
+
+        /// <summary>
+        /// Adjust the clip image with three parameter together.
+        /// </summary>
+        public void AdjustClipImage(string imagePath)
+        {
+            var imageName = Path.GetFileName(imagePath);
+            var tempClipImagePath = Path.Combine(InfoConstant.TempClipImgFolder,
+                imageName ?? throw new InvalidOperationException());
+            MutexFileOperationTool.Instance.MutexExec(tempClipImagePath, () =>
+            {
+                SaveAdjustedImg(imagePath, tempClipImagePath);
+            });
+
+        }
+
+        /// <summary>
+        /// Get surface files.
+        /// </summary>
+        /// <returns>Get folder path.</returns>
+        public string GetSurfaceFolder()
+        {
+            var path = ParameterWrapper.IsAnyValueNotStandard
+                ? InfoConstant.SurfaceTempFolder
+                : InfoConstant.SurfaceFolder;
+            if (ParameterWrapper.IsAnyValueNotStandard)
+            {
+                AdjustSurfaceImages();
+            }
+
+            return path;
+        }
+
+        private void AdjustSurfaceImages()
+        {
+            for (var i = 1; i <= _parse3DModelManager.SurfaceFile.ImageCount; i++)
+                SaveAdjustedImg(Path.Combine(InfoConstant.SurfaceFolder, $"{i}.jpg"),
+                    Path.Combine(InfoConstant.SurfaceTempFolder, $"{i}.jpg"));
+        }
+
+        private void AdjustFree3DImages()
+        {
+            var surfaceFolder = GetSurfaceFolder();
+            if (ParameterWrapper.IsAnyValueNotStandard && Directory.Exists(InfoConstant.ClipImgFolder))
+            {
+                var clipImgFullPath = new DirectoryInfo(InfoConstant.ClipImgFolder);
+                var files = clipImgFullPath.GetFiles();
+                foreach (var file in files) AdjustClipImage(file.FullName);
+            }
+
+            var clipImgPath = ParameterWrapper.IsAnyValueNotStandard
+                ? InfoConstant.TempClipImgFolder
+                : InfoConstant.ClipImgFolder;
+            ImageParameterChanged?.Invoke(this, new Carotid3DWebImagesArg(surfaceFolder, clipImgPath));
+        }
+
+        private void OnDisplayModeChanged(object sender, DisplayModeArgs e)
+        {
+            _displayMode = e.DisplayMode;
+            OnParameterValueChanged(this, EventArgs.Empty);
+        }
+
+        private void OnParameterValueChanged(object sender, EventArgs e)
+        {
+            if (_parse3DModelManager.SurfaceFile == null)
+            {
+                return;
+            }
+
+            if (_displayMode.Equals(DisplayMode.Measure))
+            {
+                AdjustCurrentMeasureBitmap();
+            }
+            else
+            {
+                _processQueue.Add(AdjustFree3DImages);
+            }
+        }
+
+        /// <summary>
+        /// adjust current measure bitmap
+        /// </summary>
+        private void AdjustCurrentMeasureBitmap()
+        {
+            if (_measureImageManager.CurrentMeasureBitmap != null)
+            {
+                var adsd = new byte[0];
+                using (var image = new Image<Gray, byte>(""))
+                {
+                    ImageParameterChanged?.Invoke(this, new Carotid3DMeasureImagesArg(AdjustImg(image.Mat)));
+                }
+            }
+        }
+
+        /// <summary>
+        /// 显示模型用,图像亮度、对比度等调节
+        /// </summary>
+        /// <param name="srcImageFilePath"></param>
+        /// <param name="dstImageFilePath"></param>
+        /// <returns></returns>
+        private void SaveAdjustedImg(string srcImageFilePath, string dstImageFilePath)
+        {
+            try
+            {
+                using (var imageMat = CvInvoke.Imread(srcImageFilePath, ImreadModes.Grayscale))
+                {
+                    Adjust(imageMat);
+                    //imageMat.Save(dstImageFilePath);
+                }
+
+            }
+            catch (Exception e)
+            {
+                Logger.WriteShellLog("SaveAdjustedImg error." + e.Message + "," + e.StackTrace);
+            }
+
+        }
+
+        private void Adjust(Mat imageMat)
+        {
+            var contrastDegree = ParameterWrapper.Contrast.Value * 0.01f;
+            var brightness = ParameterWrapper.Brightness.Value;
+            var sharpFactor = ParameterWrapper.Sharpness.Value * 0.01f;
+            imageMat.ConvertTo(imageMat, DepthType.Cv8U, contrastDegree, brightness);
+
+            float[,] temp =
+                {{0, -sharpFactor, 0}, {-sharpFactor, 1 + 4 * sharpFactor, -sharpFactor}, {0, -sharpFactor, 0}};
+            ConvolutionKernelF kernel = new ConvolutionKernelF(temp);
+
+            CvInvoke.Filter2D(imageMat, imageMat, kernel, new Point(-1, -1));
+        }
+
+        /// <summary>
+        /// 测量图像用,图像亮度、对比度等调节
+        /// </summary>
+        /// <param name="srcImageFilePath"></param>
+        /// <param name="dstImageFilePath"></param>
+        /// <returns></returns>
+        private Bitmap AdjustImg(Mat imageMat)
+        {
+            try
+            {
+                Adjust(imageMat);
+                return imageMat.ToBitmap().Clone() as Bitmap;
+            }
+            catch (Exception e)
+            {
+                Logger.WriteShellLog("AdjustImg error." + e.Message + "," + e.StackTrace);
+                return null;
+            }
+        }
+
+    }
+
+    class ImageProcessQueue : IDisposable
+    {
+        private readonly int _maxCount;
+        private readonly Queue<Action> _queue;
+        private readonly object _locker;
+        private bool _isRunning;
+        private bool _disposed;
+
+        public ImageProcessQueue(int maxCount)
+        {
+            _maxCount = maxCount;
+            _locker = new object();
+            _queue = new Queue<Action>();
+        }
+
+        ~ImageProcessQueue()
+        {
+            Dispose(false);
+        }
+
+        /// <summary>
+        /// Add new item
+        /// </summary>
+        /// <param name="item">item</param>
+        public void Add(Action item)
+        {
+            lock (_locker)
+            {
+                if (_disposed)
+                {
+                    return;
+                }
+
+                if (_queue.Count > _maxCount)
+                {
+                    _queue.Clear();
+                }
+                _queue.Enqueue(item);
+
+                if (!_isRunning)
+                {
+                    _isRunning = true;
+                    Task.Run(() => { Execut(); });
+                }
+            }
+        }
+
+        private void Execut()
+        {
+            Action item;
+            lock (_locker)
+            {
+                if (_queue.Count > 0)
+                {
+                    item = _queue.Dequeue();
+                }
+                else
+                {
+                    //Exit;
+                    _isRunning = false;
+                    return;
+                }
+            }
+
+            try
+            {
+                item();
+            }
+            catch (Exception e)
+            {
+                Logger.WriteShellLog($"Image process exception : {e}");
+            }
+            Execut();
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        protected void Dispose(bool disposing)
+        {
+            if (!_disposed)
+            {
+                lock (_locker)
+                {
+                    _queue.Clear();
+                }
+
+                _disposed = true;
+            }
+        }
+    }
+
+    public class Carotid3DImagesArgBase : EventArgs
+    {
+        /// <summary>
+        /// display Mode
+        /// </summary>
+        public DisplayMode DisplayMode { get; }
+
+        public Carotid3DImagesArgBase(DisplayMode displayMode)
+        {
+            DisplayMode = displayMode;
+        }
+    }
+
+    public class Carotid3DWebImagesArg : Carotid3DImagesArgBase
+    {
+        /// <summary>
+        /// Get surface image paths.
+        /// </summary>
+        public string SurfaceFolder { get; }
+
+        /// <summary>
+        /// Get mesh image path. 
+        /// clipImgPath 切面图的路径
+        /// </summary>
+        public string MeshImagePath { get; }
+
+
+        public Carotid3DWebImagesArg(string surfaceFolder, string meshImagePath) : base(DisplayMode.Free3D)
+        {
+            SurfaceFolder = surfaceFolder;
+            MeshImagePath = meshImagePath;
+        }
+    }
+    public class Carotid3DMeasureImagesArg : Carotid3DImagesArgBase
+    {
+        /// <summary>
+        /// Get measure bitmap
+        /// </summary>
+        public Bitmap MeasureBitmap { get; }
+
+        public Carotid3DMeasureImagesArg(Bitmap measureBitmap) : base(DisplayMode.Measure)
+        {
+            MeasureBitmap = measureBitmap;
+        }
+    }
+
+    public class MutexFileOperationTool
+    {
+        private static MutexFileOperationTool _instance;
+        /// <summary>
+        /// Get instance.
+        /// </summary>
+        public static MutexFileOperationTool Instance => _instance ?? (_instance = new MutexFileOperationTool());
+        /// <summary>
+        /// Get mutexKey to the file path 
+        /// </summary>
+        /// <param name="filePath">filePath</param>
+        /// <returns>mutexKey</returns>
+        public string GetFilePathMutexKey(string filePath)
+        {
+            return Convert.ToBase64String(Encoding.Default.GetBytes(filePath));
+        }
+
+        /// <summary>
+        /// Mutex execute file operation
+        /// </summary>
+        /// <param name="filePath"> file path</param>
+        /// <param name="action">file operation</param>
+        public void MutexExec(string filePath, Action action)
+        {
+            var mutexKey = GetFilePathMutexKey(filePath);
+            MutexExec(mutexKey, action, false);
+        }
+
+        private void MutexExec(string mutexKey, Action action, bool recursive)
+        {
+            using (Mutex mut = new Mutex(false, mutexKey))
+            {
+                try
+                {
+                    mut.WaitOne();
+                    action();
+                }
+                catch (AbandonedMutexException ex)
+                {
+                    if (recursive)
+                        Logger.WriteShellLog($"MutexExec error : {ex},mutexKey{mutexKey}");
+
+                    MutexExec(mutexKey, action, true);
+                }
+                finally
+                {
+                    mut.ReleaseMutex();
+                }
+            }
+        }
+
+    }
+}

+ 125 - 0
fis/Win/Ultra3D/Manager/MeasureImageManager.cs

@@ -0,0 +1,125 @@
+using fis.Win.Dev.Win.Ultra3D.Carotid;
+using fis.Win.Dev.Win.Ultra3D.manager;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace fis.Win.Dev.Win.Ultra3D.Manager
+{
+    public class DisplayModeArgs 
+    {
+        public DisplayMode DisplayMode { get; }
+
+        public bool IsAiClip { get; }
+
+        public DisplayModeArgs(DisplayMode displayMode, bool isAiClip)
+        {
+            DisplayMode = displayMode;
+            IsAiClip = isAiClip;
+        }
+    }
+    /// <summary>
+    /// Carotid measure image manager
+    /// </summary>
+    public class MeasureImageManager
+    {
+        private Func<Task<CefInputData>> _getClipInfoDataFunc;
+
+
+        /// <summary>
+        /// Enter measure mode event
+        /// </summary>
+        public event EventHandler MeasureModeChanged;
+
+        /// <summary>
+        ///  Current 3D Model measure bitmap
+        /// </summary>
+        public Bitmap CurrentMeasureBitmap { get; private set; }
+
+        /// <summary>
+        /// Trigger when display mode change.
+        /// </summary>
+        public event EventHandler<DisplayModeArgs> DisplayModeChanged;
+
+        /// <summary>
+        /// Switch display mode.
+        /// </summary>
+        /// <param name="displayMode">display mode.</param>
+        public void SwitchDisplayMode(DisplayMode displayMode, CefInputData cefInputData, Parse3DModelManager parse3DModelManager)
+        {
+            var isAiClip = false;
+            if (displayMode == DisplayMode.Measure && _getClipInfoDataFunc != null)
+            {
+                if (cefInputData != null && parse3DModelManager.SurfaceFile.AiPoints != null)
+                {
+                    isAiClip = IsAiPoints(parse3DModelManager.SurfaceFile.AiPoints, cefInputData);
+                }
+                CurrentMeasureBitmap = parse3DModelManager.GetSurfaceBitmap(cefInputData);
+
+            }
+            DisplayModeChanged?.Invoke(this, new DisplayModeArgs(displayMode, isAiClip));
+        }
+
+        /// <summary>
+        /// Regist get clip info data func
+        /// </summary>
+        /// <param name="getClipInfoDataFunc">get clip info data func.</param>
+        public void RegistGetClipInfoDataFunc(Func<Task<CefInputData>> getClipInfoDataFunc)
+        {
+            _getClipInfoDataFunc = getClipInfoDataFunc;
+        }
+
+        /// <summary>
+        /// Enter measure mode
+        /// </summary>
+        public void EnterMeasureMode()
+        {
+            MeasureModeChanged?.Invoke(this, EventArgs.Empty);
+        }
+
+        public string GetCurrentMeasureData()
+        {
+            return ImgToBase64String(CurrentMeasureBitmap);
+        }
+        private bool IsAiPoints(Vector3D[] aiPoints, CefInputData inputData)
+        {
+            foreach (var point in aiPoints)
+            {
+                if (!inputData.PointsList.Contains(point))
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        protected void OnDisposeManagedResource()
+        {
+            CurrentMeasureBitmap?.Dispose();
+        }
+
+        public static string ImgToBase64String(Bitmap bmp)
+        {
+            try
+            {
+                MemoryStream ms = new MemoryStream();
+                bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
+                byte[] arr = new byte[ms.Length];
+                ms.Position = 0;
+                ms.Read(arr, 0, (int)ms.Length);
+                ms.Close();
+                var data = Convert.ToBase64String(arr);
+                return "data:image/jpeg;base64," + data;
+            }
+            catch (Exception ex)
+            {
+                return null;
+            }
+        }
+    }
+}