module Parasitemia.GUI.Analysis open System open System.IO open System.Linq open System.Windows open System.Windows.Media open System.Windows.Markup open System.Windows.Shapes open System.Windows.Controls open System.Diagnostics open Microsoft.Win32 // For the common dialogs. open Emgu.CV.WPF open UnitsOfMeasure open Config open Types let showWindow (parent: Window) (state: State.State) : bool = let window = Views.AnalysisWindow() window.Root.Owner <- parent window.Root.Left <- parent.Left + parent.ActualWidth / 2. - window.Root.Width / 2. window.Root.Top <- parent.Top + parent.ActualHeight / 2. - window.Root.Height / 2. let ctrl (name: string): 'a = window.Root.FindName(name) :?> 'a let butClose: Button = ctrl "butClose" let butStart: Button = ctrl "butStart" let stackImagesSourceSelection: StackPanel = ctrl "stackImagesSourceSelection" let progressBar: ProgressBar = ctrl "progress" let textLog: TextBlock = ctrl "textLog" let scrollLog: ScrollViewer = ctrl "scrollLog" Utils.log <- (fun mess -> window.Root.Dispatcher.Invoke(fun () -> textLog.Inlines.Add(Documents.Run(mess)) textLog.Inlines.Add(Documents.LineBreak()) scrollLog.ScrollToBottom())) let minPPI = 1. let maxPPI = 10e6 let parseAndValidatePPI (input: string) : float option = let res = ref 0. if Double.TryParse(input, res) && !res >= minPPI && !res <= maxPPI then Some !res else None let monitor = Object() let mutable atLeastOneAnalysisPerformed = false let mutable analysisPerformed = false let mutable analysisCancelled = false let updateSourceImages () = stackImagesSourceSelection.Children.Clear() let width = int stackImagesSourceSelection.ActualWidth for srcImg in state.SourceImages do let imageSourceSelection = Views.ImageSourceSelection(Tag = srcImg, Margin = Thickness(3.)) let updateResolution () = match parseAndValidatePPI imageSourceSelection.txtResolution.Text with | Some resolution -> srcImg.config.Parameters <- { srcImg.config.Parameters with resolution = resolution * 1. } | None -> () imageSourceSelection.txtImageNumber.Text <- srcImg.num.ToString() let height = srcImg.img.Height * width / srcImg.img.Width imageSourceSelection.imagePreview.Source <- BitmapSourceConvert.ToBitmapSource(srcImg.img.Resize(width, height, Emgu.CV.CvEnum.Inter.Cubic)) imageSourceSelection.chkSelection.IsChecked <- Nullable(srcImg.dateLastAnalysis.Ticks = 0L) imageSourceSelection.lblDateLastAnalysis.Content <- if srcImg.dateLastAnalysis.Ticks = 0L then "" else srcImg.dateLastAnalysis.ToString() imageSourceSelection.txtResolution.Text <- srcImg.config.Parameters.resolution.ToString() imageSourceSelection.menuZoom50X.Click.AddHandler(fun obj args -> imageSourceSelection.txtResolution.Text <- "200000"; updateResolution ()) imageSourceSelection.menuZoom100X.Click.AddHandler(fun obj args -> imageSourceSelection.txtResolution.Text <- "400000"; updateResolution ()) imageSourceSelection.txtResolution.PreviewTextInput.AddHandler(fun obj args -> let text = imageSourceSelection.txtResolution.Text + args.Text args.Handled <- match parseAndValidatePPI text with Some _ -> false | None -> true) imageSourceSelection.imagePreview.MouseLeftButtonDown.AddHandler(fun obj args -> let checkbox = imageSourceSelection.chkSelection checkbox.IsChecked <- Nullable(not (checkbox.IsChecked.HasValue && checkbox.IsChecked.Value))) imageSourceSelection.txtResolution.LostFocus.AddHandler(fun obj args -> updateResolution ()) stackImagesSourceSelection.Children.Add(imageSourceSelection) |> ignore butClose.Click.AddHandler(fun obj args -> window.Root.Close()) butStart.Click.AddHandler(fun obj args -> let imagesToProcess = [ for imageSelection in stackImagesSourceSelection.Children |> Seq.cast do let chk = imageSelection.chkSelection.IsChecked if chk.HasValue && chk.Value then let srcImg = imageSelection.Tag :?> SourceImage yield srcImg.num.ToString(), srcImg.config, srcImg.img ] if imagesToProcess.IsEmpty then MessageBox.Show("No image selected", "Cannot start analysis", MessageBoxButton.OK, MessageBoxImage.Information) |> ignore else analysisPerformed <- false butStart.IsEnabled <- false butClose.Content <- "Abort" async { let results = ImageAnalysis.doMultipleAnalysis imagesToProcess (Some (fun progress -> window.Root.Dispatcher.Invoke(fun () -> progressBar.Value <- float progress))) lock monitor ( fun() -> if not analysisCancelled then for id, cells in results do state.SetResult (int id) cells window.Root.Dispatcher.Invoke(fun () -> butStart.IsEnabled <- true butClose.Content <- "Close" updateSourceImages ()) Utils.log "All analyses terminated successfully" atLeastOneAnalysisPerformed <- true analysisPerformed <- true) } |> Async.Start) window.Root.Loaded.AddHandler(fun obj args -> updateSourceImages ()) window.Root.ShowDialog() |> ignore lock monitor (fun () -> if not analysisPerformed then analysisCancelled <- true atLeastOneAnalysisPerformed)