Use two radius in the configuration, one computed with the image resolution and one...
[master-thesis.git] / Parasitemia / Parasitemia / GUI / Analysis.fs
1 module Parasitemia.GUI.Analysis
2
3 open System
4 open System.IO
5 open System.Linq
6 open System.Windows
7 open System.Windows.Media
8 open System.Windows.Markup
9 open System.Windows.Shapes
10 open System.Windows.Controls
11 open System.Diagnostics
12 open Microsoft.Win32 // For the common dialogs.
13
14 open Emgu.CV.WPF
15
16 open UnitsOfMeasure
17 open Config
18 open Types
19
20 let showWindow (parent: Window) (state: State.State) : bool =
21 let window = Views.AnalysisWindow()
22 window.Root.Owner <- parent
23 window.Root.Left <- parent.Left + parent.ActualWidth / 2. - window.Root.Width / 2.
24 window.Root.Top <- parent.Top + parent.ActualHeight / 2. - window.Root.Height / 2.
25
26 let ctrl (name: string): 'a =
27 window.Root.FindName(name) :?> 'a
28
29 let butClose: Button = ctrl "butClose"
30 let butStart: Button = ctrl "butStart"
31
32 let stackImagesSourceSelection: StackPanel = ctrl "stackImagesSourceSelection"
33 let progressBar: ProgressBar = ctrl "progress"
34 let textLog: TextBlock = ctrl "textLog"
35 let scrollLog: ScrollViewer = ctrl "scrollLog"
36
37 Utils.log <- (fun mess -> window.Root.Dispatcher.Invoke(fun () ->
38 textLog.Inlines.Add(Documents.Run(mess))
39 textLog.Inlines.Add(Documents.LineBreak())
40 scrollLog.ScrollToBottom()))
41
42 let minPPI = 1.
43 let maxPPI = 10e6
44 let parseAndValidatePPI (input: string) : float option =
45 let res = ref 0.
46 if Double.TryParse(input, res) && !res >= minPPI && !res <= maxPPI
47 then Some !res
48 else None
49
50 let monitor = Object()
51 let mutable atLeastOneAnalysisPerformed = false
52 let mutable analysisPerformed = false
53 let mutable analysisCancelled = false
54
55 let updateSourceImages () =
56 stackImagesSourceSelection.Children.Clear()
57 let width = int stackImagesSourceSelection.ActualWidth
58 for srcImg in state.SourceImages do
59 let imageSourceSelection = Views.ImageSourceSelection(Tag = srcImg, Margin = Thickness(3.))
60
61 let updateResolution () =
62 match parseAndValidatePPI imageSourceSelection.txtResolution.Text with
63 | Some resolution -> srcImg.config.Parameters <- { srcImg.config.Parameters with resolution = resolution * 1.<ppi> }
64 | None -> ()
65
66 imageSourceSelection.txtImageNumber.Text <- srcImg.num.ToString()
67 let height = srcImg.img.Height * width / srcImg.img.Width
68 imageSourceSelection.imagePreview.Source <- BitmapSourceConvert.ToBitmapSource(srcImg.img.Resize(width, height, Emgu.CV.CvEnum.Inter.Cubic))
69 imageSourceSelection.chkSelection.IsChecked <- Nullable<bool>(srcImg.dateLastAnalysis.Ticks = 0L)
70 imageSourceSelection.lblDateLastAnalysis.Content <- if srcImg.dateLastAnalysis.Ticks = 0L then "<Never>" else srcImg.dateLastAnalysis.ToString()
71
72 imageSourceSelection.txtResolution.Text <- srcImg.config.Parameters.resolution.ToString()
73 imageSourceSelection.menuZoom50X.Click.AddHandler(fun obj args -> imageSourceSelection.txtResolution.Text <- "200000"; updateResolution ())
74 imageSourceSelection.menuZoom100X.Click.AddHandler(fun obj args -> imageSourceSelection.txtResolution.Text <- "400000"; updateResolution ())
75
76 imageSourceSelection.txtResolution.PreviewTextInput.AddHandler(fun obj args ->
77 let text = imageSourceSelection.txtResolution.Text + args.Text
78 args.Handled <- match parseAndValidatePPI text with Some _ -> false | None -> true)
79
80 imageSourceSelection.imagePreview.MouseLeftButtonDown.AddHandler(fun obj args ->
81 let checkbox = imageSourceSelection.chkSelection
82 checkbox.IsChecked <- Nullable<bool>(not (checkbox.IsChecked.HasValue && checkbox.IsChecked.Value)))
83
84 imageSourceSelection.txtResolution.LostFocus.AddHandler(fun obj args -> updateResolution ())
85
86 stackImagesSourceSelection.Children.Add(imageSourceSelection) |> ignore
87
88 butClose.Click.AddHandler(fun obj args -> window.Root.Close())
89
90 butStart.Click.AddHandler(fun obj args ->
91 let imagesToProcess = [
92 for imageSelection in stackImagesSourceSelection.Children |> Seq.cast<Views.ImageSourceSelection> do
93 let chk = imageSelection.chkSelection.IsChecked
94 if chk.HasValue && chk.Value
95 then
96 let srcImg = imageSelection.Tag :?> SourceImage
97 yield srcImg.num.ToString(), srcImg.config, srcImg.img ]
98
99 if imagesToProcess.IsEmpty
100 then
101 MessageBox.Show("No image selected", "Cannot start analysis", MessageBoxButton.OK, MessageBoxImage.Information) |> ignore
102 else
103 analysisPerformed <- false
104 butStart.IsEnabled <- false
105 butClose.Content <- "Abort"
106 async {
107 let results =
108 ImageAnalysis.doMultipleAnalysis
109 imagesToProcess
110 (Some (fun progress -> window.Root.Dispatcher.Invoke(fun () -> progressBar.Value <- float progress)))
111
112 lock monitor (
113 fun() ->
114 if not analysisCancelled
115 then
116 for id, cells in results do
117 state.SetResult (int id) cells
118
119 window.Root.Dispatcher.Invoke(fun () ->
120 butStart.IsEnabled <- true
121 butClose.Content <- "Close"
122 updateSourceImages ())
123
124 Utils.log "All analyses terminated successfully"
125 atLeastOneAnalysisPerformed <- true
126 analysisPerformed <- true)
127 } |> Async.Start)
128
129 window.Root.Loaded.AddHandler(fun obj args -> updateSourceImages ())
130
131 window.Root.ShowDialog() |> ignore
132
133 lock monitor (fun () ->
134 if not analysisPerformed
135 then
136 analysisCancelled <- true
137 atLeastOneAnalysisPerformed)