a1b253f4f060d334560148fe3224aaf70c4dd934
[master-thesis.git] / Parasitemia / ParasitemiaUI / Analysis.fs
1 module ParasitemiaUI.Analysis
2
3 open System
4 open System.Linq
5 open System.Windows
6 open System.Windows.Controls
7
8 open ParasitemiaUIControls
9 open ParasitemiaCore.UnitsOfMeasure
10 open ParasitemiaCore.Config
11
12 open Types
13
14 let showWindow (parent : Window) (state : State.State) : bool =
15 let win = AnalysisWindow ()
16 win.Owner <- parent
17 win.Left <- (if parent.WindowState = WindowState.Maximized then 0. else parent.Left) + parent.ActualWidth / 2. - win.Width / 2.
18 win.Top <- (if parent.WindowState = WindowState.Maximized then 0. else parent.Top) + parent.ActualHeight / 2. - win.Height / 2.
19
20 let logListener =
21 {
22 new Logger.IListener with
23 member this.NewEntry severity _header mess =
24 win.Dispatcher.Invoke (
25 fun () ->
26 win.textLog.Inlines.Add (Documents.Run mess)
27 win.textLog.Inlines.Add (Documents.LineBreak ())
28 win.scrollLog.ScrollToBottom ()
29 )
30 }
31
32 Logger.Log.AddListener (logListener)
33
34 let minPPI = 1.
35 let maxPPI = 10e6
36 let parseAndValidatePPI (input : string) : float option =
37 match Double.TryParse input with
38 | true, value when value >= minPPI && value <= maxPPI -> Some value
39 | _ -> None
40
41 let monitor = Object ()
42 let mutable atLeastOneAnalysisPerformed = false
43 let mutable analysisPerformed = false
44 let mutable analysisCancelled = false
45
46 let updateSourceImages () =
47 win.stackSourceImagesSelection.Children.Clear ()
48 let width = int win.stackSourceImagesSelection.ActualWidth
49 for srcImg in state.SourceImages do
50 let imageSourceSelection = ImageSourceSelection (Tag = srcImg, Margin = Thickness 3.)
51 imageSourceSelection.Tag <- srcImg
52
53 imageSourceSelection.txtImageNumber.Text <- string srcImg.RomanNum
54 let height = srcImg.Img.Height * width / srcImg.Img.Width
55 imageSourceSelection.imagePreview.Source <- BitmapSourceConvert.ToBitmapSource (srcImg.Img.Resize (width, height, Emgu.CV.CvEnum.Inter.Cubic))
56 imageSourceSelection.chkSelection.IsChecked <- Nullable<bool> (srcImg.DateLastAnalysis.Ticks = 0L)
57 imageSourceSelection.lblDateLastAnalysis.Content <- if srcImg.DateLastAnalysis.Ticks = 0L then "<Never>" else string srcImg.DateLastAnalysis
58
59 imageSourceSelection.txtResolution.Text <- if srcImg.DateLastAnalysis.Ticks = 0L then "" else string srcImg.Config.Parameters.resolution
60
61 for ppi in Utils.predefinedPPI do
62 let menu = MenuItem ()
63 menu.Header <- string ppi
64 menu.Click.AddHandler (fun obj args -> imageSourceSelection.txtResolution.Text <- string ppi.ppi)
65 imageSourceSelection.predefinedValuesMenu.Items.Add menu |> ignore
66
67 imageSourceSelection.butPPICalculator.Click.AddHandler (
68 fun obj args ->
69 match PPICalculator.showWindow win with
70 | Some resolution -> imageSourceSelection.txtResolution.Text <- string resolution
71 | None -> ()
72 )
73
74 imageSourceSelection.txtResolution.PreviewTextInput.AddHandler (
75 fun obj args ->
76 let text = imageSourceSelection.txtResolution.Text + args.Text
77 args.Handled <- match parseAndValidatePPI text with Some _ -> false | None -> true
78 )
79
80 imageSourceSelection.imagePreview.MouseLeftButtonDown.AddHandler (
81 fun obj args ->
82 let checkbox = imageSourceSelection.chkSelection
83 checkbox.IsChecked <- Nullable<bool> (not (checkbox.IsChecked.HasValue && checkbox.IsChecked.Value))
84 )
85
86 win.stackSourceImagesSelection.Children.Add (imageSourceSelection) |> ignore
87
88 // Get the new parameters for each image. If an error occurs then 'None' is returned and a message box is displayed.
89 // The boolean is 'true' if the image is selected (checked).
90 let getInputImagesParameters () : (SourceImage * bool * Parameters) list option =
91 let sourceImagesControls = win.stackSourceImagesSelection.Children |> Seq.cast<ImageSourceSelection>
92 let parameters =
93 seq {
94 for srcImgCtrl in sourceImagesControls do
95 let srcImg = srcImgCtrl.Tag :?> SourceImage
96 let isChecked = srcImgCtrl.chkSelection.IsChecked
97 match parseAndValidatePPI srcImgCtrl.txtResolution.Text with
98 | Some resolution ->
99 Some (srcImg, isChecked.HasValue && isChecked.Value, { srcImg.Config.Parameters with resolution = resolution * 1.<ppi> })
100 | None ->
101 MessageBox.Show (sprintf "No resolution defined for the image number %d" srcImg.Num, "No resolution defined", MessageBoxButton.OK, MessageBoxImage.Information) |> ignore
102 None
103 } |> Seq.takeWhile (fun e -> e.IsSome) |> Seq.map (fun e -> e.Value) |> List.ofSeq
104
105 if parameters.Count () <> sourceImagesControls.Count () then
106 None
107 else
108 Some parameters
109
110 win.butSelectAll.Click.AddHandler (
111 fun obj args ->
112 for srcImgCtrl in win.stackSourceImagesSelection.Children |> Seq.cast<ImageSourceSelection> do
113 srcImgCtrl.chkSelection.IsChecked <- true
114 )
115
116 win.butUnselectAll.Click.AddHandler (
117 fun obj args ->
118 for srcImgCtrl in win.stackSourceImagesSelection.Children |> Seq.cast<ImageSourceSelection> do
119 srcImgCtrl.chkSelection.IsChecked <- false
120 )
121
122 win.butClose.Click.AddHandler (fun obj args -> win.Close ())
123
124 win.butStart.Click.AddHandler (
125 fun obj args ->
126 match getInputImagesParameters () with
127 | Some imagesParameters ->
128 let imagesToProcess =
129 [
130 for srcImg, selected, parameters in imagesParameters do
131 srcImg.Config.Parameters <- parameters // Save parameters.
132 if selected then
133 string srcImg.RomanNum, srcImg.Config, srcImg.Img
134 ]
135
136 if imagesToProcess.IsEmpty then
137 MessageBox.Show ("No image selected", "Cannot start analysis", MessageBoxButton.OK, MessageBoxImage.Information) |> ignore
138 else
139 win.stackSourceImagesSelection.IsEnabled <- false
140 win.butSelectAll.IsEnabled <- false
141 win.butUnselectAll.IsEnabled <- false
142 analysisPerformed <- false
143 win.butStart.IsEnabled <- false
144 win.textLog.Text <- ""
145 win.butClose.Content <- "Abort"
146
147 async {
148 let maybeResults =
149 ParasitemiaCore.Analysis.doMultipleAnalysis
150 imagesToProcess
151 (Some (fun progress -> win.Dispatcher.Invoke (fun () -> win.progress.Value <- float progress); not analysisCancelled))
152
153 lock monitor (
154 fun () ->
155 match maybeResults with
156 | Some results ->
157 for id, cells in results do
158 state.SetResult id cells
159 Logger.Log.Info "All analyses terminated successfully"
160 atLeastOneAnalysisPerformed <- true
161 analysisPerformed <- true
162 | None ->
163 Logger.Log.Info "Analysis aborted"
164
165 win.Dispatcher.Invoke (
166 fun () ->
167 win.progress.Value <- if maybeResults.IsSome then 100. else 0.
168 win.stackSourceImagesSelection.IsEnabled <- true
169 win.butSelectAll.IsEnabled <- true
170 win.butUnselectAll.IsEnabled <- true
171 win.butStart.IsEnabled <- true
172 win.butClose.Content <- "Close"
173 updateSourceImages ()
174 )
175 )
176 } |> Async.Start
177 | _ -> ()
178 )
179
180 win.Loaded.AddHandler (fun obj args -> updateSourceImages ())
181
182 win.ShowDialog () |> ignore
183
184 Logger.Log.RemoveListener (logListener)
185
186 lock monitor (
187 fun () ->
188 if not analysisPerformed then
189 // To cancel the current analysis if one is running on the next call to the progress function.
190 analysisCancelled <- true
191 atLeastOneAnalysisPerformed
192 )