2aadefef86e0ace0ea6dd03a3992a1f18423f163
1
module Parasitemia.GUI.Main
6 open System.Windows.Media
7 open System.Windows.Markup
8 open System.Windows.Shapes
9 open System.Windows.Controls
10 open System.Diagnostics
11 open Microsoft.Win32 // For the common dialogs.
18 let run (defaultConfig
: Config) =
19 let app = new Application()
20 let mainWindow = Views.MainWindow()
21 let ctrl (name
: string): 'a =
22 mainWindow.Root.FindName(name) :?> 'a
24 // Utils.log <- (fun m -> log mainWindow m)
26 let colorRBCHealthy = Brushes.YellowGreen
27 let colorRBCInfected = Brushes.Red
29 let state = State.State()
31 let exit: MenuItem = ctrl "menuExit"
32 let saveFile: MenuItem = ctrl "menuSave"
33 let loadFile: MenuItem = ctrl "menuOpen"
34 let newFile: MenuItem = ctrl "menuNew"
36 let addSourceImage: MenuItem = ctrl "menuAddSourceImage"
37 let txtPatient: TextBox = ctrl "txtPatient"
38 let stackPreviews: StackPanel = ctrl "stackPreviews"
39 let butStartAnalysis: Button = ctrl "butStartAnalysis"
41 let scrollViewCurrentImage: ScrollViewer = ctrl "scrollViewCurrentImage"
42 let borderCurrentImage: Border = ctrl "borderCurrentImage"
43 let canvasCurrentImage: Canvas = ctrl "canvasCurrentImage"
48 let synchronizeState () =
49 state.PatientID <- txtPatient.Text
51 let setCurrentImage (srcImg
: SourceImage) =
52 state.CurrentImage <- Some srcImg
54 // Highlight the preview.
55 stackPreviews.Children
56 |> Seq.cast
<Views.ImageSourcePreview>
57 |> Seq.iter
(fun preview
-> preview
.border
.BorderThickness <- Thickness(if preview
.lblImageNumber
.Content = box
srcImg.num
then 3. else 0.))
59 canvasCurrentImage.Height <- float srcImg.img
.Height
60 canvasCurrentImage.Width <- float srcImg.img
.Width
61 canvasCurrentImage.Background <- ImageBrush(BitmapSourceConvert.ToBitmapSource(srcImg.img
))
63 // Remove all image canvas children and add the RBC.
64 canvasCurrentImage.Children.Clear()
65 for rbc
in srcImg.rbcs
do
68 Height = rbc
.size
.Height,
69 Width = rbc
.size
.Width,
70 Stroke = (if rbc
.infected
then colorRBCInfected else colorRBCHealthy),
72 Fill = SolidColorBrush(Color.FromArgb(0uy, 0uy, 0uy, 0uy)),
74 Opacity = if rbc
.infected
then 1. else 0.)
75 Canvas.SetLeft(rectangle, rbc
.center
.X - rbc
.size
.Width / 2.)
76 Canvas.SetTop(rectangle, rbc
.center
.Y - rbc
.size
.Height / 2.)
77 canvasCurrentImage.Children.Add(rectangle) |> ignore
78 rectangle.MouseEnter.AddHandler(
79 fun obj args
-> match obj
with
80 | :? Rectangle as r
->
81 r
.StrokeThickness <- 3.
82 if not
(r
.Tag :?> RBC).infected
then r
.Opacity <- 1.
84 rectangle.MouseLeave.AddHandler(
85 fun obj args
-> match obj
with
86 | :? Rectangle as r
->
87 r
.StrokeThickness <- 1.
88 if not
(r
.Tag :?> RBC).infected
then r
.Opacity <- 0.
91 let addPreview (srcImg: SourceImage) =
92 let imgCtrl = Views.ImageSourcePreview(Margin = Thickness(3.))
93 imgCtrl.lblImageNumber
.Content <- srcImg.num
95 let height = srcImg.img
.Height * width / srcImg.img
.Width
96 imgCtrl.imagePreview
.Source <- BitmapSourceConvert.ToBitmapSource(srcImg.img
.Resize(width, height, Emgu.CV.CvEnum.Inter.Cubic))
97 stackPreviews.Children.Add(imgCtrl) |> ignore
98 imgCtrl.MouseLeftButtonUp.AddHandler(fun obj args
-> setCurrentImage (state.SourceImages |> Seq.find
(fun i
-> box i
.num
= (obj
:?> Views.ImageSourcePreview).lblImageNumber
.Content)))
100 let updatePreviews () =
101 stackPreviews.Children.Clear ()
102 if state.SourceImages.Count() > 0
104 for srcImg in state.SourceImages do
106 setCurrentImage (state.SourceImages.First())
109 txtPatient.Text <- state.PatientID
112 exit.Click.AddHandler(fun obj args
-> mainWindow.Root.Close())
113 saveFile.Click.AddHandler(fun obj args
->
115 if state.FilePath = ""
117 let dialog = SaveFileDialog(AddExtension = true, DefaultExt = PiaZ.extension
, Filter = PiaZ.filter
);
118 let res = dialog.ShowDialog()
119 if res.HasValue && res.Value
121 state.FilePath <- dialog.FileName
126 loadFile.Click.AddHandler(fun obj args
->
127 // TODO: if current state not saved and not empty, ask to save it.
128 let dialog = OpenFileDialog(Filter = PiaZ.filter
)
129 let res = dialog.ShowDialog()
130 if res.HasValue && res.Value
132 state.FilePath <- dialog.FileName
136 newFile.Click.AddHandler(fun obj args
->
137 // TODO: if current state not saved and not empty, ask to save it.
141 addSourceImage.Click.AddHandler(fun obj args
->
142 let dialog = OpenFileDialog(Filter = "Image Files|*.png;*.jpg;*.tif;*.tiff")
143 let res = dialog.ShowDialog()
144 if res.HasValue && res.Value
146 let srcImg = state.AddSourceImage(dialog.FileName)
148 if state.SourceImages.Count() = 1
150 setCurrentImage srcImg)
152 butStartAnalysis.Click.AddHandler(fun obj args
->
153 let results = ImageAnalysis.doMultipleAnalysis
(state.SourceImages |> Seq.map
(fun srcImg -> string srcImg.num
, srcImg.img
) |> Seq.toList
) defaultConfig
154 for id
, cells
in results do
155 state.SetResult (int id) cells
158 // Zoom on the current image.
159 let adjustCurrentImageBorders (deltaX
: float) (deltaY
: float) =
160 borderCurrentImage.BorderThickness <-
162 (scrollViewCurrentImage.ViewportWidth + deltaX
) / 2.,
163 (scrollViewCurrentImage.ViewportHeight + deltaY
) / 2.,
164 (scrollViewCurrentImage.ViewportWidth + deltaX
) / 2.,
165 (scrollViewCurrentImage.ViewportHeight + deltaY
) / 2.)
167 canvasCurrentImage.SizeChanged.AddHandler(fun obj args
->
168 let deltaX = args
.NewSize.Width - args
.PreviousSize.Width
169 let deltaY = args
.NewSize.Height - args
.PreviousSize.Height
170 if deltaX > 0.5 || deltaY > 0.5
172 adjustCurrentImageBorders 0.0
0.0
173 // Center the view at the center of the image initialy.
174 scrollViewCurrentImage.UpdateLayout()
175 scrollViewCurrentImage.ScrollToHorizontalOffset(borderCurrentImage.ActualWidth / 2. - scrollViewCurrentImage.ViewportWidth / 2.)
176 scrollViewCurrentImage.ScrollToVerticalOffset(borderCurrentImage.ActualHeight / 2. - scrollViewCurrentImage.ViewportHeight / 2.))
178 scrollViewCurrentImage.SizeChanged.AddHandler(fun obj args
->
179 let deltaX = args
.NewSize.Width - args
.PreviousSize.Width
180 let deltaY = args
.NewSize.Height - args
.PreviousSize.Height
181 adjustCurrentImageBorders deltaX deltaY
182 scrollViewCurrentImage.ScrollToHorizontalOffset(scrollViewCurrentImage.HorizontalOffset + deltaX / 8.)
183 scrollViewCurrentImage.ScrollToVerticalOffset(scrollViewCurrentImage.VerticalOffset + deltaY / 8.))
185 let mutable currentScale = 1.
186 let mutable maxScale = 4.
187 let mutable minScale = 0.25
188 let currentImageScaleTransform = ScaleTransform()
189 canvasCurrentImage.LayoutTransform <- currentImageScaleTransform
190 borderCurrentImage.PreviewMouseWheel.AddHandler(fun obj args
->
191 let scaleFactor = if args
.Delta > 0 then 2.0 else 0.5
192 if scaleFactor > 1. && currentScale < maxScale || scaleFactor < 1. && currentScale > minScale
194 let previousScale = currentScale
196 let newScale = currentScale * scaleFactor
197 if newScale > maxScale then maxScale elif newScale < minScale then minScale else newScale
198 let realScaleFactor = currentScale / previousScale
200 let centerX = scrollViewCurrentImage.HorizontalOffset + scrollViewCurrentImage.ViewportWidth / 2. - borderCurrentImage.BorderThickness.Left
201 let centerY = scrollViewCurrentImage.VerticalOffset + scrollViewCurrentImage.ViewportHeight / 2. - borderCurrentImage.BorderThickness.Top
203 //canvasCurrentImage.Margin <- Thickness(canvasCurrentImage.Margin.Top * realScaleFactor)
204 currentImageScaleTransform.ScaleX <- currentScale
205 currentImageScaleTransform.ScaleY <- currentScale
207 scrollViewCurrentImage.ScrollToHorizontalOffset(centerX * realScaleFactor - scrollViewCurrentImage.ViewportWidth / 2. + borderCurrentImage.BorderThickness.Left)
208 scrollViewCurrentImage.ScrollToVerticalOffset(centerY * realScaleFactor - scrollViewCurrentImage.ViewportHeight / 2. + borderCurrentImage.BorderThickness.Top)
209 args
.Handled <- true)
211 // Pan on the current image.
212 let mutable scrollStartPosition = Point(0., 0.)
213 let mutable scrollStartOffsetX = 0.
214 let mutable scrollStartOffsetY = 0.
215 borderCurrentImage.PreviewMouseLeftButtonDown.AddHandler(fun obj args
->
216 scrollStartPosition <- args
.GetPosition(scrollViewCurrentImage)
217 scrollStartOffsetX <- scrollViewCurrentImage.HorizontalOffset
218 scrollStartOffsetY <- scrollViewCurrentImage.VerticalOffset
219 borderCurrentImage.Cursor <- Input.Cursors.ScrollAll
220 borderCurrentImage.CaptureMouse() |> ignore
221 args
.Handled <- true)
223 borderCurrentImage.PreviewMouseMove.AddHandler(fun obj args
->
224 if borderCurrentImage.IsMouseCaptured
226 let position = args
.GetPosition(scrollViewCurrentImage)
227 let deltaX = scrollStartPosition.X - position.X
228 let deltaY = scrollStartPosition.Y - position.Y
229 scrollViewCurrentImage.ScrollToHorizontalOffset(deltaX + scrollStartOffsetX)
230 scrollViewCurrentImage.ScrollToVerticalOffset(deltaY + scrollStartOffsetY)
231 args
.Handled <- true)
233 borderCurrentImage.PreviewMouseLeftButtonUp.AddHandler(fun obj args
->
234 if borderCurrentImage.IsMouseCaptured
236 borderCurrentImage.Cursor <- Input.Cursors.Arrow
237 borderCurrentImage.ReleaseMouseCapture()
238 args
.Handled <- true)
240 // display mainWindow img
241 mainWindow.Root.Show()