1
module ParasitemiaUI.Analysis
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.
16 open ParasitemiaCore.UnitsOfMeasure
17 open ParasitemiaCore.Config
21 let showWindow (parent
: Window) (state
: State.State) : bool =
22 let window = Views.AnalysisWindow()
23 window.Root.Owner <- parent
24 window.Root.Left <- parent
.Left + parent
.ActualWidth / 2. - window.Root.Width / 2.
25 window.Root.Top <- parent
.Top + parent
.ActualHeight / 2. - window.Root.Height / 2.
27 let ctrl (name
: string): 'a = window.Root.FindName(name) :?> 'a
29 let butClose: Button = ctrl "butClose"
30 let butStart: Button = ctrl "butStart"
32 let stackSourceImagesSelection: StackPanel = ctrl "stackSourceImagesSelection"
33 let progressBar: ProgressBar = ctrl "progress"
34 let textLog: TextBlock = ctrl "textLog"
35 let scrollLog: ScrollViewer = ctrl "scrollLog"
38 { new Logger.IListener with
39 member this
.NewEntry severity mess
=
40 window.Root.Dispatcher.Invoke(fun () ->
41 textLog.Inlines.Add(Documents.Run(mess
))
42 textLog.Inlines.Add(Documents.LineBreak())
43 scrollLog.ScrollToBottom()) }
45 Logger.Log.AddListener(logListener)
49 let parseAndValidatePPI (input
: string) : float option =
51 if Double.TryParse(input
, res) && !res >= minPPI && !res <= maxPPI
55 let monitor = Object()
56 let mutable atLeastOneAnalysisPerformed = false
57 let mutable analysisPerformed = false
58 let mutable analysisCancelled = false
60 let updateSourceImages () =
61 stackSourceImagesSelection.Children.Clear()
62 let width = int stackSourceImagesSelection.ActualWidth
63 for srcImg
in state
.SourceImages do
64 let imageSourceSelection = Views.ImageSourceSelection(Tag = srcImg
, Margin = Thickness(3.))
65 imageSourceSelection.Tag <- srcImg
67 imageSourceSelection.txtImageNumber
.Text <- srcImg
.num
.ToString()
68 let height = srcImg
.img
.Height * width / srcImg
.img
.Width
69 imageSourceSelection.imagePreview
.Source <- BitmapSourceConvert.ToBitmapSource(srcImg
.img
.Resize(width, height, Emgu.CV.CvEnum.Inter.Cubic))
70 imageSourceSelection.chkSelection
.IsChecked <- Nullable<bool>(srcImg
.dateLastAnalysis
.Ticks = 0L)
71 imageSourceSelection.lblDateLastAnalysis
.Content <- if srcImg
.dateLastAnalysis
.Ticks = 0L then "<Never>" else srcImg.dateLastAnalysis
.ToString()
73 imageSourceSelection.txtResolution
.Text <- if srcImg.dateLastAnalysis
.Ticks = 0L then "" else srcImg.config
.Parameters.resolution
.ToString()
74 imageSourceSelection.menuZoom50X
.Click.AddHandler(fun obj args
-> imageSourceSelection.txtResolution
.Text <- "230000")
75 imageSourceSelection.menuZoom100X
.Click.AddHandler(fun obj args
-> imageSourceSelection.txtResolution
.Text <- "460000")
77 imageSourceSelection.txtResolution
.PreviewTextInput.AddHandler(fun obj args
->
78 let text = imageSourceSelection.txtResolution
.Text + args
.Text
79 args
.Handled <- match parseAndValidatePPI text with Some _ -> false | None -> true)
81 imageSourceSelection.imagePreview
.MouseLeftButtonDown.AddHandler(fun obj args
->
82 let checkbox = imageSourceSelection.chkSelection
83 checkbox.IsChecked <- Nullable<bool>(not
(checkbox.IsChecked.HasValue && checkbox.IsChecked.Value)))
85 stackSourceImagesSelection.Children.Add(imageSourceSelection) |> ignore
87 // Get the new parameters for each image. If an error occurs then 'None' is returned and a message box is displayed.
88 // The boolean is 'true' if the image is selected (checked).
89 let getInputImagesParameters () : (SourceImage * bool * Parameters) list
option =
90 let sourceImagesControls = stackSourceImagesSelection.Children |> Seq.cast
<Views.ImageSourceSelection>
91 let parameters = seq
{
92 for srcImgCtrl
in sourceImagesControls do
93 let srcImg = srcImgCtrl
.Tag :?> SourceImage
94 let isChecked = srcImgCtrl
.chkSelection
.IsChecked
95 match parseAndValidatePPI srcImgCtrl
.txtResolution
.Text with
97 yield
Some (srcImg, isChecked.HasValue && isChecked.Value, { srcImg.config
.Parameters with resolution
= resolution
* 1.<ppi
> })
99 MessageBox.Show(sprintf
"No resolution defined for the image number %d" srcImg.num
, "No resolution defined", MessageBoxButton.OK, MessageBoxImage.Information) |> ignore
100 yield
None } |> Seq.takeWhile
(fun e
-> e
.IsSome) |> Seq.map
(fun e
-> e
.Value) |> List.ofSeq
101 if parameters.Count() <> sourceImagesControls.Count()
105 butClose.Click.AddHandler(fun obj args
-> window.Root.Close())
107 butStart.Click.AddHandler(fun obj args
->
108 match getInputImagesParameters () with
109 | Some imagesParameters
->
110 let imagesToProcess = [
111 for srcImg, selected, parameters in imagesParameters
do
112 srcImg.config
.Parameters <- parameters // Save parameters.
114 then yield
srcImg.num
.ToString(), srcImg.config
, srcImg.img
]
116 if imagesToProcess.IsEmpty
118 MessageBox.Show("No image selected", "Cannot start analysis", MessageBoxButton.OK, MessageBoxImage.Information) |> ignore
120 stackSourceImagesSelection.IsEnabled <- false
121 analysisPerformed <- false
122 butStart.IsEnabled <- false
123 butClose.Content <- "Abort"
127 ParasitemiaCore.Analysis.doMultipleAnalysis
129 (Some (fun progress
-> window.Root.Dispatcher.Invoke(fun () -> progressBar.Value <- float progress); not
analysisCancelled))
133 match maybeResults with
135 for id
, cells
in results
do
136 state
.SetResult (int id) cells
138 window.Root.Dispatcher.Invoke(fun () ->
139 stackSourceImagesSelection.IsEnabled <- true
140 butStart.IsEnabled <- true
141 butClose.Content <- "Close"
142 updateSourceImages ())
144 Logger.Log.User("All analyses terminated successfully")
145 atLeastOneAnalysisPerformed <- true
146 analysisPerformed <- true
151 window.Root.Loaded.AddHandler(fun obj args
-> updateSourceImages ())
153 window.Root.ShowDialog() |> ignore
155 Logger.Log.RmListener(logListener)
157 lock
monitor (fun () ->
158 if not
analysisPerformed
160 analysisCancelled <- true
161 atLeastOneAnalysisPerformed)