|
@@ -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();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+}
|