XSyncMapAcquisition.xaml.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. namespace OINA.Extender.WPF.Testharness
  2. {
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Collections.ObjectModel;
  6. using System.ComponentModel;
  7. using System.Linq;
  8. using System.Threading.Tasks;
  9. using System.Windows;
  10. using System.Windows.Controls;
  11. using System.Windows.Threading;
  12. using OINA.Extender.Acquisition;
  13. using OINA.Extender.Acquisition.Ed;
  14. using OINA.Extender.Acquisition.XSync;
  15. using OINA.Extender.Data.Ed;
  16. using OINA.Extender.Data.Image;
  17. using OINA.Extender.Processing.Ed;
  18. /// <summary>
  19. /// Interaction logic for XSyncMapAcquisition.xaml
  20. /// </summary>
  21. public partial class XSyncMapAcquisition : UserControl, INotifyPropertyChanged
  22. {
  23. private readonly List<DetectorEnableModel> enabledDetectors;
  24. private EdHardwareId primaryHardwareId;
  25. private List<DetectorEnableModel> secondaryHardwareIds;
  26. private IXSyncEdMapAcquisitionController controller;
  27. private IEdSpectrum spectrum;
  28. private bool isPaused;
  29. private string pauseResumeState;
  30. private int completedFrames;
  31. private ObservableCollection<IEdMap> acquiredMaps;
  32. private IEdMap selectedMap;
  33. private IReadOnlyList<IImageCorrection> elementMaps;
  34. private IEdMapFLSProcessor flsProcessor;
  35. private double progressPercentage;
  36. private IEdMapAcquisitionData processedMapData;
  37. public XSyncMapAcquisition()
  38. {
  39. this.InitializeComponent();
  40. this.DataContext = this;
  41. this.Settings = AcquireFactory.CreateXSyncEdMapSettings();
  42. this.Settings.XSyncSettings.SynchronizationMode = XSyncMode.CASLineSync;
  43. // pixel size is the number of data pixels in x
  44. double pixelSize = 1.0 / 120;
  45. // assume that there are also 120 data pixels in y
  46. Size size = new Size(1.0, 1.0);
  47. this.Settings.XSyncSettings.AcquisitionRegion.CreateRectangleRegion(new Rect(size), pixelSize);
  48. this.Settings.XSyncSettings.FrameCount = 1;
  49. // assume that there are 2040 lines scanned, this gives a binning factor of 17
  50. this.Settings.XSyncSettings.LineSync.BinFactorY = 17;
  51. this.Settings.XSyncSettings.LineSync.LinesPerFrame = 2040; // = (120 * 17)
  52. // set the calibrated field width to set the image viewer scale bar
  53. this.Settings.XSyncSettings.CalibratedFieldWidthmm = 180;
  54. this.enabledDetectors = this.Settings.EdSettings.IsHardwareEnabled
  55. .Select(i => new DetectorEnableModel(i.Key, i.Value)).ToList();
  56. this.PrimaryHardwareId = this.Settings.EdSettings.PrimaryHardwareId;
  57. this.controller = AcquireFactory.CreateXSyncEdMapServer();
  58. this.controller.ExperimentStarted += this.OnExperimentStarted;
  59. this.controller.ExperimentFinished += this.OnExperimentFinished;
  60. this.controller.PauseRequested += this.OnPauseRequested;
  61. this.controller.ResumeRequested += this.OnResumeRequested;
  62. this.controller.FrameCompleted += this.OnFrameCompleted;
  63. this.acquiredMaps = new ObservableCollection<IEdMap>();
  64. }
  65. /// <summary>
  66. /// Event that notifies that the processing progress has changed
  67. /// </summary>
  68. public event PropertyChangedEventHandler PropertyChanged;
  69. private void RaisePropertyChanged(string propertyName)
  70. {
  71. this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  72. }
  73. private void StartButton_Click(object sender, System.Windows.RoutedEventArgs e)
  74. {
  75. this.PauseResumeState = string.Empty;
  76. this.IsPaused = false;
  77. this.CompletedFrames = 0;
  78. this.ElementMaps = null;
  79. this.ProgressPercentage = 0;
  80. this.processedMapData = null;
  81. var edSettings = this.Settings.EdSettings;
  82. var xsyncSettings = this.Settings.XSyncSettings;
  83. foreach (var detectorEnabled in this.secondaryHardwareIds)
  84. {
  85. edSettings.EnableDevice(detectorEnabled.EdHardwareId, detectorEnabled.IsDetectorEnabled);
  86. }
  87. edSettings.PrimaryHardwareId = this.primaryHardwareId;
  88. if (xsyncSettings.SynchronizationMode == XSyncMode.CASLineSync)
  89. {
  90. edSettings.AcquisitionMode = EdAcquireMode.RealTime;
  91. edSettings.AcquisitionTime = TimeSpan.FromTicks((long)(xsyncSettings.LineSync.DwellTimeMicroSeconds * TimeSpan.TicksPerMillisecond / 1000));
  92. edSettings.TimeMode = EdTimeMode.Pixel;
  93. }
  94. var results = this.Settings.Validate();
  95. if (!results.IsValid)
  96. {
  97. string errors = string.Join(Environment.NewLine, results.ValidationErrors);
  98. MessageBox.Show(errors, @"Invalid acquisition settings");
  99. return;
  100. }
  101. this.controller.StartAcquisition(this.Settings);
  102. }
  103. private void StopButton_Click(object sender, System.Windows.RoutedEventArgs e)
  104. {
  105. this.controller.StopAcquisition();
  106. }
  107. private void OnExperimentStarted(object sender, AcquisitionStartedEventArgs<IEdMapAcquisitionData> e)
  108. {
  109. this.Spectrum = e.Value.EdSpectrum;
  110. }
  111. private void OnExperimentFinished(object sender, AcquisitionFinishedEventArgs<IEdMapAcquisitionData> e)
  112. {
  113. var edMap = e.Value?.EdMap;
  114. if (edMap != null)
  115. {
  116. this.Dispatcher.BeginInvoke(() =>
  117. {
  118. this.acquiredMaps.Add(edMap);
  119. this.SelectedMap = edMap;
  120. });
  121. }
  122. if (e.Success)
  123. {
  124. // Get off the acquisition thread
  125. Task.Run(() =>
  126. {
  127. this.StartFLSProcessing(e.Value);
  128. });
  129. }
  130. }
  131. public IEdSpectrum Spectrum
  132. {
  133. get
  134. {
  135. return this.spectrum;
  136. }
  137. set
  138. {
  139. this.spectrum = value;
  140. this.RaisePropertyChanged(nameof(this.Spectrum));
  141. }
  142. }
  143. public IXSyncEdMapSettings Settings { get; }
  144. public EdHardwareId PrimaryHardwareId
  145. {
  146. get
  147. {
  148. return this.primaryHardwareId;
  149. }
  150. set
  151. {
  152. if (this.primaryHardwareId == value)
  153. {
  154. return;
  155. }
  156. this.primaryHardwareId = value;
  157. this.RaisePropertyChanged(nameof(this.PrimaryHardwareId));
  158. this.SecondaryHardwareIds = this.enabledDetectors.Where(i => i.EdHardwareId != value).ToList();
  159. }
  160. }
  161. public IReadOnlyList<DetectorEnableModel> SecondaryHardwareIds
  162. {
  163. get
  164. {
  165. return this.secondaryHardwareIds;
  166. }
  167. set
  168. {
  169. this.secondaryHardwareIds = value.ToList();
  170. this.RaisePropertyChanged(nameof(this.SecondaryHardwareIds));
  171. }
  172. }
  173. #region Pause / Resume
  174. private void OnPauseRequested(object sender, PauseScanEventArgs e)
  175. {
  176. this.PauseResumeState = @"Pause requested";
  177. }
  178. private void OnResumeRequested(object sender, ResumeScanEventArgs e)
  179. {
  180. this.PauseResumeState = @"Resume requested";
  181. }
  182. /// <summary>
  183. /// Gets or sets a value indicating whether the external scan hardware is paused
  184. /// </summary>
  185. public bool IsPaused
  186. {
  187. get
  188. {
  189. return this.isPaused;
  190. }
  191. set
  192. {
  193. if (this.isPaused == value)
  194. {
  195. return;
  196. }
  197. this.isPaused = value;
  198. this.RaisePropertyChanged(nameof(this.IsPaused));
  199. this.controller.NotifyPauseResume(value);
  200. }
  201. }
  202. /// <summary>
  203. /// Gets or sets a value indicating whether a pause or resume is requested
  204. /// </summary>
  205. public string PauseResumeState
  206. {
  207. get
  208. {
  209. return this.pauseResumeState;
  210. }
  211. set
  212. {
  213. if (this.pauseResumeState == value)
  214. {
  215. return;
  216. }
  217. this.pauseResumeState = value;
  218. this.RaisePropertyChanged(nameof(this.PauseResumeState));
  219. }
  220. }
  221. #endregion
  222. private void OnFrameCompleted(object sender, FrameCompletedEventArgs e)
  223. {
  224. this.CompletedFrames = e.FrameNumber;
  225. }
  226. /// <summary>
  227. /// Gets or sets the number of completed frames
  228. /// </summary>
  229. public int CompletedFrames
  230. {
  231. get
  232. {
  233. return this.completedFrames;
  234. }
  235. set
  236. {
  237. if (this.completedFrames == value)
  238. {
  239. return;
  240. }
  241. this.completedFrames = value;
  242. this.RaisePropertyChanged(nameof(this.CompletedFrames));
  243. }
  244. }
  245. /// <summary>
  246. /// Gets the acquired maps
  247. /// </summary>
  248. public ObservableCollection<IEdMap> AcquiredMaps
  249. {
  250. get
  251. {
  252. return this.acquiredMaps;
  253. }
  254. }
  255. /// <summary>
  256. /// Gets or sets the selected map
  257. /// </summary>
  258. public IEdMap SelectedMap
  259. {
  260. get
  261. {
  262. return this.selectedMap;
  263. }
  264. set
  265. {
  266. this.selectedMap = value;
  267. this.RaisePropertyChanged(nameof(this.SelectedMap));
  268. }
  269. }
  270. /// <summary>
  271. /// Deletes the selected map
  272. /// </summary>
  273. private void DeleteMapButton_Click(object sender, RoutedEventArgs e)
  274. {
  275. // Maps should be deleted when they are no longer required as the data is saved in the
  276. // AppData\Local\Oxford Instruments NanoAnalysis\Extender\TempProject folder of the current user
  277. // Note these projects cannot be used with AZtec.
  278. var edMap = this.selectedMap;
  279. if (edMap != null)
  280. {
  281. this.controller.Delete(edMap);
  282. edMap.Dispose();
  283. this.acquiredMaps.Remove(edMap);
  284. this.SelectedMap = this.acquiredMaps.LastOrDefault();
  285. }
  286. }
  287. #region FLS Processing
  288. /// <summary>
  289. /// Starts FLS map processing
  290. /// </summary>
  291. /// <param name="mapData">The map data</param>
  292. private void StartFLSProcessing(IEdMapAcquisitionData mapData)
  293. {
  294. var autoIdSettings = ProcessingFactory.CreateAutoIdSettings();
  295. var spectrumProcessing = ProcessingFactory.CreateSpectrumProcessing();
  296. var elements = spectrumProcessing.IdentifyElements(mapData.EdSpectrum, autoIdSettings);
  297. if (elements.Any())
  298. {
  299. mapData.EdMap.SetIdentifiedElements(elements, true);
  300. this.FLSProcessor = ProcessingFactory.CreateEdMapFLSProcessor();
  301. var settings = ProcessingFactory.CreateEdMapFLSSettings();
  302. try
  303. {
  304. this.processedMapData = mapData;
  305. this.ElementMaps = this.FLSProcessor.StartProcessing(mapData, settings);
  306. }
  307. catch (Exception ex)
  308. {
  309. MessageBox.Show(ex.Message, @"Error starting processing");
  310. }
  311. }
  312. }
  313. /// <summary>
  314. /// Gets or sets the Ed Map FLS processor
  315. /// </summary>
  316. private IEdMapFLSProcessor FLSProcessor
  317. {
  318. get
  319. {
  320. return this.flsProcessor;
  321. }
  322. set
  323. {
  324. if (this.flsProcessor == value)
  325. {
  326. return;
  327. }
  328. var processor = this.flsProcessor;
  329. if (processor != null)
  330. {
  331. processor.ProgressChanged -= this.OnProcessingProgressChanged;
  332. processor.Dispose();
  333. }
  334. this.flsProcessor = value;
  335. if (value != null)
  336. {
  337. value.ProgressChanged += this.OnProcessingProgressChanged;
  338. }
  339. }
  340. }
  341. private void OnProcessingProgressChanged(object sender, ProcessingProgressEventArgs e)
  342. {
  343. this.ProgressPercentage = e.ProgressPercentage;
  344. if (e.State == ProcessingProgressState.Completed)
  345. {
  346. this.elementMaps.ToList().ForEach(i => i.AutoBrightness());
  347. // calculate total counts in the first element map
  348. var elementMap = this.elementMaps.OfType<IFLSMapImage>().FirstOrDefault();
  349. if (elementMap != null)
  350. {
  351. int pixels = elementMap.Height * elementMap.Width;
  352. float[] countsPerSecond = new float[pixels];
  353. elementMap.GetData(countsPerSecond);
  354. float[] liveTimes = new float[pixels];
  355. this.processedMapData.EdMap.GetLiveTimes(elementMap.BinFactor, liveTimes);
  356. double totalCounts = Enumerable.Range(0, pixels).Sum(i => countsPerSecond[i] * liveTimes[i]);
  357. }
  358. }
  359. }
  360. /// <summary>
  361. /// Gets or sets the processing percentage (0 - 100)
  362. /// </summary>
  363. public double ProgressPercentage
  364. {
  365. get
  366. {
  367. return this.progressPercentage;
  368. }
  369. set
  370. {
  371. this.progressPercentage = value;
  372. this.RaisePropertyChanged(nameof(this.ProgressPercentage));
  373. }
  374. }
  375. /// <summary>
  376. /// Gets or sets the element maps
  377. /// </summary>
  378. public IReadOnlyList<IImageCorrection> ElementMaps
  379. {
  380. get
  381. {
  382. return this.elementMaps;
  383. }
  384. set
  385. {
  386. if (this.elementMaps == value)
  387. {
  388. return;
  389. }
  390. var elementMaps = this.elementMaps;
  391. elementMaps?.ToList().ForEach(i => i.Dispose());
  392. this.elementMaps = value;
  393. this.RaisePropertyChanged(nameof(this.ElementMaps));
  394. }
  395. }
  396. private void CancelButton_Click(object sender, RoutedEventArgs e)
  397. {
  398. this.FLSProcessor?.CancelProcessing();
  399. }
  400. /// <summary>
  401. /// Reprocess a previously processed map
  402. /// </summary>
  403. /// <param name="sender"></param>
  404. /// <param name="e"></param>
  405. private void ReprocessButton_Click(object sender, RoutedEventArgs e)
  406. {
  407. try
  408. {
  409. if (this.processedMapData != null &&
  410. this.processedMapData.EdMap.IdentifiedElements.Any())
  411. {
  412. var settings = ProcessingFactory.CreateEdMapFLSSettings();
  413. this.ElementMaps = this.FLSProcessor.StartProcessing(this.processedMapData, settings);
  414. }
  415. }
  416. catch (Exception ex)
  417. {
  418. MessageBox.Show(ex.Message, @"Error reprocessing map");
  419. }
  420. }
  421. #endregion
  422. }
  423. }