FocusAnalyzerControl.xaml.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. using CSScripting;
  2. using OpenCvSharp;
  3. using OpenCvSharp.Extensions;
  4. using OpenCvSharp.WpfExtensions;
  5. using OxyPlot;
  6. using OxyPlot.Axes;
  7. using OxyPlot.Series;
  8. using Prism.Commands;
  9. using Prism.Mvvm;
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Collections.ObjectModel;
  13. using System.ComponentModel;
  14. using System.Linq;
  15. using System.Runtime.CompilerServices;
  16. using System.Threading.Tasks;
  17. using System.Windows;
  18. using System.Windows.Controls;
  19. using System.Windows.Input;
  20. using System.Windows.Media;
  21. using System.Windows.Media.Imaging;
  22. using TeamAAS_VP.Core;
  23. using TeamAAS_VP.Enums;
  24. using TeamAAS_VP.Models;
  25. namespace TeamAAS_VP.Controls
  26. {
  27. public partial class FocusAnalyzerControl : UserControl
  28. {
  29. private FocusAnalyzerViewModel ViewModel;
  30. // 鼠标状态
  31. private bool _isMouseDown = false;
  32. private System.Windows.Point _mouseDownPoint;
  33. public FocusAnalyzerControl()
  34. {
  35. InitializeComponent();
  36. Loaded += OnLoaded;
  37. }
  38. private void OnLoaded(object sender, RoutedEventArgs e)
  39. {
  40. // 初始化ViewModel
  41. if (DataContext == null)
  42. DataContext = new FocusAnalyzerViewModel();
  43. ViewModel=DataContext as FocusAnalyzerViewModel;
  44. }
  45. #region 鼠标事件处理
  46. private void ImageDisplay_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  47. {
  48. if (ViewModel == null) return;
  49. _isMouseDown = true;
  50. _mouseDownPoint = e.GetPosition(ImageDisplay);
  51. // 处理ROI操作
  52. if (ViewModel.CurrentRoi != null)
  53. {
  54. // 检查是否点击了ROI
  55. if (ViewModel.StartRoiDrag(_mouseDownPoint))
  56. {
  57. CaptureMouse();
  58. return;
  59. }
  60. }
  61. // 开始绘制新ROI
  62. if (ViewModel.RoiMode == RoiOperationMode.Draw)
  63. {
  64. ViewModel.StartRoiDrawing(_mouseDownPoint);
  65. CaptureMouse();
  66. }
  67. }
  68. private void ImageDisplay_MouseMove(object sender, MouseEventArgs e)
  69. {
  70. if (ViewModel == null || !_isMouseDown) return;
  71. var currentPoint = e.GetPosition(ImageDisplay);
  72. // 处理ROI拖动
  73. if (ViewModel.RoiMode != RoiOperationMode.Draw && ViewModel.CurrentRoi != null)
  74. {
  75. ViewModel.UpdateRoiDrag(currentPoint);
  76. UpdateRoiVisual();
  77. }
  78. // 处理ROI绘制
  79. else if (ViewModel.RoiMode == RoiOperationMode.Draw)
  80. {
  81. ViewModel.UpdateRoiDrawing(currentPoint);
  82. UpdateRoiVisual();
  83. }
  84. }
  85. private void ImageDisplay_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
  86. {
  87. if (ViewModel == null || !_isMouseDown) return;
  88. _isMouseDown = false;
  89. ReleaseMouseCapture();
  90. if (ViewModel.RoiMode == RoiOperationMode.Draw)
  91. {
  92. ViewModel.FinishRoiDrawing();
  93. }
  94. else
  95. {
  96. ViewModel.FinishRoiDrag();
  97. }
  98. }
  99. #endregion
  100. #region ROI可视化更新
  101. private void UpdateRoiVisual()
  102. {
  103. if (ViewModel?.CurrentRoi == null) return;
  104. // 更新ROI矩形位置和大小
  105. Canvas.SetLeft(RoiRectangle, ViewModel.CurrentRoi.X);
  106. Canvas.SetTop(RoiRectangle, ViewModel.CurrentRoi.Y);
  107. RoiRectangle.Width = ViewModel.CurrentRoi.Width;
  108. RoiRectangle.Height = ViewModel.CurrentRoi.Height;
  109. // 更新控制点位置
  110. UpdateRoiHandles();
  111. }
  112. private void UpdateRoiHandles()
  113. {
  114. if (ViewModel?.CurrentRoi == null) return;
  115. var roi = ViewModel.CurrentRoi;
  116. // 更新角点
  117. UpdateHandlePosition(TopLeftHandle, roi.X, roi.Y);
  118. UpdateHandlePosition(TopRightHandle, roi.X + roi.Width, roi.Y);
  119. UpdateHandlePosition(BottomLeftHandle, roi.X, roi.Y + roi.Height);
  120. UpdateHandlePosition(BottomRightHandle, roi.X + roi.Width, roi.Y + roi.Height);
  121. // 更新边中点
  122. UpdateHandlePosition(TopHandle, roi.X + roi.Width / 2, roi.Y);
  123. UpdateHandlePosition(RightHandle, roi.X + roi.Width, roi.Y + roi.Height / 2);
  124. UpdateHandlePosition(BottomHandle, roi.X + roi.Width / 2, roi.Y + roi.Height);
  125. UpdateHandlePosition(LeftHandle, roi.X, roi.Y + roi.Height / 2);
  126. // 更新旋转控制点
  127. UpdateRotateHandlePosition(roi);
  128. }
  129. private void UpdateHandlePosition(FrameworkElement handle, double x, double y)
  130. {
  131. if (handle == null) return;
  132. Canvas.SetLeft(handle, x - handle.Width / 2);
  133. Canvas.SetTop(handle, y - handle.Height / 2);
  134. }
  135. private void UpdateRotateHandlePosition(RotatedRect roi)
  136. {
  137. if (RotateHandle == null) return;
  138. // 旋转控制点在矩形顶部中心上方
  139. double centerX = roi.X + roi.Width / 2;
  140. double centerY = roi.Y + roi.Height / 2;
  141. // 计算旋转后的位置
  142. double angleRad = roi.Angle * Math.PI / 180;
  143. double radius = Math.Max(roi.Width, roi.Height) / 2 + 20; // 距离中心20像素
  144. double x = centerX + radius * Math.Sin(angleRad);
  145. double y = centerY - radius * Math.Cos(angleRad);
  146. // 设置位置
  147. RotateHandle.RenderTransform = new RotateTransform(roi.Angle);
  148. Canvas.SetLeft(RotateHandle, x - 5); // 5是三角形宽度的一半
  149. Canvas.SetTop(RotateHandle, y - 5); // 5是三角形高度的一半
  150. }
  151. #endregion
  152. #region 依赖属性
  153. // CurrentImage依赖属性
  154. public static readonly DependencyProperty CurrentImageProperty =
  155. DependencyProperty.Register("CurrentImage", typeof(ImageSource), typeof(FocusAnalyzerControl),
  156. new PropertyMetadata(null, OnCurrentImageChanged));
  157. public ImageSource CurrentImage
  158. {
  159. get => (ImageSource)GetValue(CurrentImageProperty);
  160. set => SetValue(CurrentImageProperty, value);
  161. }
  162. private static void OnCurrentImageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  163. {
  164. var control = d as FocusAnalyzerControl;
  165. if (control.ViewModel != null)
  166. control.ViewModel.CurrentImage = e.NewValue as ImageSource;
  167. }
  168. // Parameters依赖属性
  169. public static readonly DependencyProperty ParametersProperty =
  170. DependencyProperty.Register("Parameters", typeof(AnalysisParameters), typeof(FocusAnalyzerControl),
  171. new PropertyMetadata(new AnalysisParameters(), OnParametersChanged));
  172. public AnalysisParameters Parameters
  173. {
  174. get => (AnalysisParameters)GetValue(ParametersProperty);
  175. set => SetValue(ParametersProperty, value);
  176. }
  177. private static void OnParametersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  178. {
  179. var control = d as FocusAnalyzerControl;
  180. if (control.ViewModel != null)
  181. control.ViewModel.Parameters = e.NewValue as AnalysisParameters;
  182. }
  183. // CurrentResult依赖属性
  184. public static readonly DependencyProperty CurrentResultProperty =
  185. DependencyProperty.Register("CurrentResult", typeof(AnalysisResult), typeof(FocusAnalyzerControl),
  186. new PropertyMetadata(new AnalysisResult(), OnCurrentResultChanged));
  187. public AnalysisResult CurrentResult
  188. {
  189. get => (AnalysisResult)GetValue(CurrentResultProperty);
  190. set => SetValue(CurrentResultProperty, value);
  191. }
  192. private static void OnCurrentResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  193. {
  194. var control = d as FocusAnalyzerControl;
  195. if (control.ViewModel != null)
  196. control.ViewModel.CurrentResult = e.NewValue as AnalysisResult;
  197. }
  198. // StartAnalysisCommand依赖属性
  199. public static readonly DependencyProperty StartAnalysisCommandProperty =
  200. DependencyProperty.Register("StartAnalysisCommand", typeof(ICommand), typeof(FocusAnalyzerControl),
  201. new PropertyMetadata(null, OnStartAnalysisCommandChanged));
  202. public ICommand StartAnalysisCommand
  203. {
  204. get => (ICommand)GetValue(StartAnalysisCommandProperty);
  205. set => SetValue(StartAnalysisCommandProperty, value);
  206. }
  207. private static void OnStartAnalysisCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  208. {
  209. var control = d as FocusAnalyzerControl;
  210. if (control.ViewModel != null)
  211. control.ViewModel.StartAnalysisCommand = e.NewValue as ICommand;
  212. }
  213. // 其他命令和属性的依赖属性...
  214. #endregion
  215. #region 公共方法
  216. /// <summary>
  217. /// 处理图像帧
  218. /// </summary>
  219. public async Task ProcessImageFrameAsync(OpenCvSharp.Mat frame)
  220. {
  221. if (ViewModel != null)
  222. await ViewModel.ProcessImageFrameAsync(frame);
  223. }
  224. /// <summary>
  225. /// 执行单次分析
  226. /// </summary>
  227. public void PerformAnalysis(OpenCvSharp.Mat frame)
  228. {
  229. ViewModel?.PerformAnalysis(frame);
  230. }
  231. /// <summary>
  232. /// 获取当前ROI区域
  233. /// </summary>
  234. public OpenCvSharp.Rect? GetCurrentRoiRect()
  235. {
  236. if (ViewModel?.CurrentRoi == null)
  237. return null;
  238. return new OpenCvSharp.Rect(
  239. (int)ViewModel.CurrentRoi.X,
  240. (int)ViewModel.CurrentRoi.Y,
  241. (int)ViewModel.CurrentRoi.Width,
  242. (int)ViewModel.CurrentRoi.Height);
  243. }
  244. /// <summary>
  245. /// 获取旋转ROI
  246. /// </summary>
  247. public OpenCvSharp.RotatedRect? GetCurrentRotatedRoi()
  248. {
  249. if (ViewModel?.CurrentRoi == null)
  250. return null;
  251. return ViewModel.CurrentRoi.ToCvRotatedRect();
  252. }
  253. #endregion
  254. }
  255. }