From 3ddaf64dc5ba6a7066a279ad75b9a1ee72194639 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Thu, 7 Jan 2016 18:34:45 +0100 Subject: [PATCH] * Add area granulometry (not used for the moment) * beginning of a little GUI. --- Parasitemia/Parasitemia.sln | 7 +- Parasitemia/Parasitemia/Classifier.fs | 1 + Parasitemia/Parasitemia/Const.fs | 4 + Parasitemia/Parasitemia/GUI/GUI.fs | 76 +++++++++ Parasitemia/Parasitemia/GUI/MainWindow.xaml | 39 +++++ .../Parasitemia/{ => GUI}/MainWindow.xaml.fs | 2 +- .../Parasitemia/{ => GUI}/NumericUpDown.xaml | 0 .../{ => GUI}/NumericUpDown.xaml.fs | 6 +- Parasitemia/Parasitemia/GUI/Pia.fs | 71 +++++++++ Parasitemia/Parasitemia/GUI/State.fs | 17 ++ Parasitemia/Parasitemia/Granulometry.fs | 34 +++- Parasitemia/Parasitemia/ImgTools.fs | 147 ++++++++++-------- Parasitemia/Parasitemia/KMeans.fs | 5 +- Parasitemia/Parasitemia/MainAnalysis.fs | 6 +- Parasitemia/Parasitemia/MainWindow.xaml | 30 ---- Parasitemia/Parasitemia/Parasitemia.fsproj | 34 +++- Parasitemia/Parasitemia/Program.fs | 40 ++--- Parasitemia/Parasitemia/Types.fs | 1 + Parasitemia/Parasitemia/packages.config | 1 + 19 files changed, 381 insertions(+), 140 deletions(-) create mode 100644 Parasitemia/Parasitemia/Const.fs create mode 100644 Parasitemia/Parasitemia/GUI/GUI.fs create mode 100644 Parasitemia/Parasitemia/GUI/MainWindow.xaml rename Parasitemia/Parasitemia/{ => GUI}/MainWindow.xaml.fs (50%) rename Parasitemia/Parasitemia/{ => GUI}/NumericUpDown.xaml (100%) rename Parasitemia/Parasitemia/{ => GUI}/NumericUpDown.xaml.fs (70%) create mode 100644 Parasitemia/Parasitemia/GUI/Pia.fs create mode 100644 Parasitemia/Parasitemia/GUI/State.fs delete mode 100644 Parasitemia/Parasitemia/MainWindow.xaml diff --git a/Parasitemia/Parasitemia.sln b/Parasitemia/Parasitemia.sln index aeabd42..ea32a4b 100644 --- a/Parasitemia/Parasitemia.sln +++ b/Parasitemia/Parasitemia.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.22823.1 +VisualStudioVersion = 14.0.24720.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Parasitemia", "Parasitemia\Parasitemia.fsproj", "{70838E65-F211-44FC-B28F-0ED1CA6E850F}" EndProject @@ -10,15 +10,20 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + DebugGUI|Any CPU = DebugGUI|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {70838E65-F211-44FC-B28F-0ED1CA6E850F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {70838E65-F211-44FC-B28F-0ED1CA6E850F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {70838E65-F211-44FC-B28F-0ED1CA6E850F}.DebugGUI|Any CPU.ActiveCfg = DebugGUI|Any CPU + {70838E65-F211-44FC-B28F-0ED1CA6E850F}.DebugGUI|Any CPU.Build.0 = DebugGUI|Any CPU {70838E65-F211-44FC-B28F-0ED1CA6E850F}.Release|Any CPU.ActiveCfg = Release|Any CPU {70838E65-F211-44FC-B28F-0ED1CA6E850F}.Release|Any CPU.Build.0 = Release|Any CPU {314FD78E-870E-4794-BB16-EA4586F2ABDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {314FD78E-870E-4794-BB16-EA4586F2ABDB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {314FD78E-870E-4794-BB16-EA4586F2ABDB}.DebugGUI|Any CPU.ActiveCfg = Debug|Any CPU + {314FD78E-870E-4794-BB16-EA4586F2ABDB}.DebugGUI|Any CPU.Build.0 = Debug|Any CPU {314FD78E-870E-4794-BB16-EA4586F2ABDB}.Release|Any CPU.ActiveCfg = Release|Any CPU {314FD78E-870E-4794-BB16-EA4586F2ABDB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection diff --git a/Parasitemia/Parasitemia/Classifier.fs b/Parasitemia/Parasitemia/Classifier.fs index 341f7c9..3a679e7 100644 --- a/Parasitemia/Parasitemia/Classifier.fs +++ b/Parasitemia/Parasitemia/Classifier.fs @@ -229,4 +229,5 @@ let findCells (ellipses: Ellipse list) (parasites: ParasitesMarker.Result) (img: Some { cellClass = cellClass center = Point(roundInt e.Cx, roundInt e.Cy) + stainArea = stainPixels elements = elements }) diff --git a/Parasitemia/Parasitemia/Const.fs b/Parasitemia/Parasitemia/Const.fs new file mode 100644 index 0000000..0d2e52e --- /dev/null +++ b/Parasitemia/Parasitemia/Const.fs @@ -0,0 +1,4 @@ +module Const + +// TODO: try with a literal and check performance. +let PI = float32 System.Math.PI \ No newline at end of file diff --git a/Parasitemia/Parasitemia/GUI/GUI.fs b/Parasitemia/Parasitemia/GUI/GUI.fs new file mode 100644 index 0000000..cf7ed67 --- /dev/null +++ b/Parasitemia/Parasitemia/GUI/GUI.fs @@ -0,0 +1,76 @@ +module Parasitemia.GUI + +open System.IO +open System.Windows +open System.Windows.Media +open System.Windows.Markup +open System.Windows.Shapes +open System.Windows.Controls +open System.Drawing +open System.Diagnostics +open Microsoft.Win32 // For the common dialogs. + +open Emgu.CV +open Emgu.CV.Structure +open Emgu.CV.WPF + +open Config + +let run (defaultConfig: Config) = + let app = new Application() + let mainWindow = Views.MainWindow() + let ctrl (name: string): 'a = + mainWindow.Root.FindName(name) :?> 'a + + // Utils.log <- (fun m -> log mainWindow m) + + let state = State.State() + + let exit: Controls.MenuItem = ctrl "menuExit" + let save: Controls.MenuItem = ctrl "menuSave" + let load: Controls.MenuItem = ctrl "menuOpen" + + let txtPatient: Controls.TextBox = ctrl "txtPatient" + + + let synchronizeState () = + state.PatientID <- txtPatient.Text + + let synchronizeView () = + txtPatient.Text <- state.PatientID + + exit.Click.AddHandler(fun obj args -> mainWindow.Root.Close()) + save.Click.AddHandler(fun obj args -> + synchronizeState () + if state.FilePath = "" + then + let dialog = SaveFileDialog(AddExtension = true, DefaultExt = Pia.extension, Filter = Pia.filter); + let res = dialog.ShowDialog() + if res.HasValue && res.Value + then + state.FilePath <- dialog.FileName + state.Save() + else + state.Save()) + + load.Click.AddHandler(fun obj args -> + // TODO: if current state not saved and not empty, ask to save it. + let dialog = OpenFileDialog(Filter = Pia.filter) + let res = dialog.ShowDialog() + if res.HasValue && res.Value + then + state.FilePath <- dialog.FileName + state.Load() + synchronizeView ()) + + (*let txtPatient: Controls.TextBox = ctrl "txtPatient" + txtPatient.TextChanged.AddHandler(fun obj args -> + state.PatientID <- txtPatient.Text)*) + + (*saveFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*" ; + saveFileDialog1.FilterIndex = 2 ; + saveFileDialog1.RestoreDirectory = true ;*) + + // display mainWindow img + mainWindow.Root.Show() + app.Run() \ No newline at end of file diff --git a/Parasitemia/Parasitemia/GUI/MainWindow.xaml b/Parasitemia/Parasitemia/GUI/MainWindow.xaml new file mode 100644 index 0000000..5b7a3c5 --- /dev/null +++ b/Parasitemia/Parasitemia/GUI/MainWindow.xaml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Parasitemia/Parasitemia/MainWindow.xaml.fs b/Parasitemia/Parasitemia/GUI/MainWindow.xaml.fs similarity index 50% rename from Parasitemia/Parasitemia/MainWindow.xaml.fs rename to Parasitemia/Parasitemia/GUI/MainWindow.xaml.fs index 26d30c9..62c35a4 100644 --- a/Parasitemia/Parasitemia/MainWindow.xaml.fs +++ b/Parasitemia/Parasitemia/GUI/MainWindow.xaml.fs @@ -2,5 +2,5 @@ open FsXaml -type MainWindow = XAML<"MainWindow.xaml"> +type MainWindow = XAML<"GUI/MainWindow.xaml"> diff --git a/Parasitemia/Parasitemia/NumericUpDown.xaml b/Parasitemia/Parasitemia/GUI/NumericUpDown.xaml similarity index 100% rename from Parasitemia/Parasitemia/NumericUpDown.xaml rename to Parasitemia/Parasitemia/GUI/NumericUpDown.xaml diff --git a/Parasitemia/Parasitemia/NumericUpDown.xaml.fs b/Parasitemia/Parasitemia/GUI/NumericUpDown.xaml.fs similarity index 70% rename from Parasitemia/Parasitemia/NumericUpDown.xaml.fs rename to Parasitemia/Parasitemia/GUI/NumericUpDown.xaml.fs index b30e59a..6f91924 100644 --- a/Parasitemia/Parasitemia/NumericUpDown.xaml.fs +++ b/Parasitemia/Parasitemia/GUI/NumericUpDown.xaml.fs @@ -7,11 +7,11 @@ open System.Windows.Input open FsXaml -type NumericUpDown = XAML<"NumericUpDown.xaml", true> - +type NumericUpDown = XAML<"GUI/NumericUpDown.xaml", true> + type NumericUpDownEvents = Up | Down -type NumericUpDownController() = +type NumericUpDownController() = inherit UserControlViewController() diff --git a/Parasitemia/Parasitemia/GUI/Pia.fs b/Parasitemia/Parasitemia/GUI/Pia.fs new file mode 100644 index 0000000..9ddd063 --- /dev/null +++ b/Parasitemia/Parasitemia/GUI/Pia.fs @@ -0,0 +1,71 @@ +// ParasitemIA file format. +module Pia + +open System.Drawing +open System.IO +open System.IO.Compression + +open FSharp.Data + +open Emgu.CV +open Emgu.CV.Structure + +let extension = ".pia" +let filter = "PIA|*.pia" + +type RBC = { + infected: bool + addedManually: bool + removed: bool + + center: Point + size: Size + stainArea: int } + +type ImageSource = { + img: Image + rbcs: RBC list } + +type FileData = { + sources: ImageSource list + patientID: string } + +// The json type associated to a source image. +type JSONSourceImage = JsonProvider<""" + { + "rbcs": [ + { "infected": true, "addedManually": false, "removed": false, "posX" : 42, "posY" : 42, "width" : 10, "height" : 10, "stainArea" : 10 } + ] + } +"""> + +// The json type associated to a file. +type JSONMainInformation = JsonProvider<""" + { + "patientID": "1234abcd" + } +"""> + +let mainFilename = "info.json" + +let save (filePath: string) (data: FileData) = + use file = ZipFile.Open(filePath, ZipArchiveMode.Update) + + let mainJSON = JSONMainInformation.Root(data.patientID) + + let mainFile = + match file.GetEntry(mainFilename) with + | null -> file.CreateEntry(mainFilename) + | entry -> entry + + use mainFileWriter = new StreamWriter(mainFile.Open()) + mainJSON.JsonValue.WriteTo(mainFileWriter, JsonSaveOptions.None) + + +let load (filePath: string) : FileData = + use file = ZipFile.Open(filePath, ZipArchiveMode.Read) + + let mainFile = file.GetEntry(mainFilename) + let mainJSON = JSONMainInformation.Load(mainFile.Open()) + + { sources = []; patientID = mainJSON.PatientId } \ No newline at end of file diff --git a/Parasitemia/Parasitemia/GUI/State.fs b/Parasitemia/Parasitemia/GUI/State.fs new file mode 100644 index 0000000..a4a1773 --- /dev/null +++ b/Parasitemia/Parasitemia/GUI/State.fs @@ -0,0 +1,17 @@ +module State + +open System.Collections.Generic + +type State () = + let cells = List() + + member val FilePath: string = "" with get, set + member val PatientID: string = "" with get, set + + member this.Save () = + let data = { Pia.sources = []; Pia.patientID = this.PatientID } + Pia.save this.FilePath data + + member this.Load () = + let data = Pia.load this.FilePath + this.PatientID <- data.patientID \ No newline at end of file diff --git a/Parasitemia/Parasitemia/Granulometry.fs b/Parasitemia/Parasitemia/Granulometry.fs index 0ef862b..7886043 100644 --- a/Parasitemia/Parasitemia/Granulometry.fs +++ b/Parasitemia/Parasitemia/Granulometry.fs @@ -10,7 +10,7 @@ open Utils // 'range': a minimum and maximum radius. // 'scale': <= 1.0, to speed up the process. -let findRadius (img: Image) (range: int * int) (scale: float) : int = +let findRadiusByClosing (img: Image) (range: int * int) (scale: float) : int = use scaledImg = if scale = 1. then img else img.Resize(scale, CvEnum.Inter.Area) let r1, r2 = range @@ -19,9 +19,26 @@ let findRadius (img: Image) (range: int * int) (scale: float) : i let patternSpectrum = Array.zeroCreate (r2' - r1') let intensityImg = scaledImg.GetSum().Intensity + // 's' must be odd. + let octagon (s: int) : Matrix = + if s % 2 = 0 then failwith "s must be odd" + let m = new Matrix(Array2D.create s s 1uy) + let r = (float s) / (Math.Sqrt 2. + 2.) |> roundInt + for i in 0 .. r - 1 do + for j in 0 .. r - 1 do + if i + j < r + then + m.[i, j] <- 0uy + m.[s - i - 1, j] <- 0uy + m.[i, s - j - 1] <- 0uy + m.[s - i - 1, s - j - 1] <- 0uy + m + let mutable previous_n = Double.NaN for r in r1' .. r2' do let se = CvInvoke.GetStructuringElement(CvEnum.ElementShape.Ellipse, Size(2 * r, 2 * r), Point(-1, -1)) + //let se = octagon (2 * r - 1) + use closed = scaledImg.MorphologyEx(CvEnum.MorphOp.Close, se, Point(-1, -1), 1, CvEnum.BorderType.Replicate, MCvScalar(0.0)) let n = closed.GetSum().Intensity @@ -36,3 +53,18 @@ let findRadius (img: Image) (range: int * int) (scale: float) : i float (max + r1') / scale |> roundInt +let findRadiusByAreaClosing (img: Image) (range: int * int) : int = + let r1, r2 = range + + use imgCopy = img.Copy() + + let mutable maxDiff = 0.f + let mutable max_r = r1 + + ImgTools.areaCloseFWithFun imgCopy [ for r in r1 .. r2 -> Math.PI * float r ** 2. |> roundInt, r ] (fun r diff -> + if r <> r1 && diff > maxDiff + then + maxDiff <- diff + max_r <- r - 1 ) + max_r + diff --git a/Parasitemia/Parasitemia/ImgTools.fs b/Parasitemia/Parasitemia/ImgTools.fs index 3cfdc89..23c9aee 100644 --- a/Parasitemia/Parasitemia/ImgTools.fs +++ b/Parasitemia/Parasitemia/ImgTools.fs @@ -198,9 +198,7 @@ let findEdges (img: Image) : Matrix * Image let sensibilityHigh = 0.1f let sensibilityLow = 0.0f use magnitudesByte = magnitudes.Convert() - let threshold = float32 <| CvInvoke.Threshold(magnitudesByte, magnitudesByte, 0.0, 1.0, CvEnum.ThresholdType.Otsu ||| CvEnum.ThresholdType.Binary) let threshold, _, _ = otsu (histogramMat magnitudes 300) - threshold + (sensibilityHigh * threshold), threshold - (sensibilityLow * threshold) // Non-maximum suppression. @@ -556,9 +554,9 @@ let private areaOperation (img: Image) (area: int) (op: AreaOperatio nextElements.Add(p) |> ignore else - let m' = pixels.[p.Y, p.X] - if m' <> null - then + match pixels.[p.Y, p.X] with + | null -> () + | m' -> if m'.Elements.Count + m.Elements.Count <= area then m'.State <- AreaState.Removed @@ -628,7 +626,7 @@ type Island (cmp: IComparer) = member val Surface = 0 with get, set -let private areaOperationF (img: Image) (area: int) (op: AreaOperation) = +let private areaOperationF (img: Image) (areas: (int * 'a) list) (f: ('a -> float32 -> unit) option) (op: AreaOperation) = let w = img.Width let h = img.Height let earth = img.Data @@ -655,82 +653,97 @@ let private areaOperationF (img: Image) (area: int) (op: AreaOper let ni = i + p.Y let nj = j + p.X let neighbor = Point(nj, ni) - if ni >= 0 && ni < h && nj >= 0 && nj < w && ownership.[ni, nj] = null && not (shorePoints.Contains(neighbor)) + if ni >= 0 && ni < h && nj >= 0 && nj < w && Object.ReferenceEquals(ownership.[ni, nj], null) && not (shorePoints.Contains(neighbor)) then shorePoints.Add(neighbor) |> ignore island.Shore.Add earth.[ni, nj, 0] neighbor - for island in islands do - let mutable stop = island.Shore.IsEmpty - - // 'true' if 'p' is owned or adjacent to 'island'. - let ownedOrAdjacent (p: Point) : bool = - ownership.[p.Y, p.X] = island || - (p.Y > 0 && ownership.[p.Y - 1, p.X] = island) || - (p.Y < h - 1 && ownership.[p.Y + 1, p.X] = island) || - (p.X > 0 && ownership.[p.Y, p.X - 1] = island) || - (p.X < w - 1 && ownership.[p.Y, p.X + 1] = island) - - while not stop && island.Surface < area do - let level, next = island.Shore.Max - let other = ownership.[next.Y, next.X] - if other = island // During merging, some points on the shore may be owned by the island itself -> ignored. - then - island.Shore.RemoveNext () - else - if other <> null - then // We touching another island. - if island.Surface + other.Surface >= area - then - stop <- true - else // We can merge 'other' into 'surface'. - island.Surface <- island.Surface + other.Surface - island.Level <- if comparer.Compare(island.Level, other.Level) > 0 then island.Level else other.Level - for l, p in other.Shore do - let mutable currentY = p.Y + 1 - while currentY < h && ownership.[currentY, p.X] = other do - ownership.[currentY, p.X] <- island - currentY <- currentY + 1 - island.Shore.Add l p - other.Shore.Clear() - - elif comparer.Compare(level, island.Level) > 0 + for area, obj in areas do + for island in islands do + let mutable stop = island.Shore.IsEmpty + + // 'true' if 'p' is owned or adjacent to 'island'. + let inline ownedOrAdjacent (p: Point) : bool = + ownership.[p.Y, p.X] = island || + (p.Y > 0 && ownership.[p.Y - 1, p.X] = island) || + (p.Y < h - 1 && ownership.[p.Y + 1, p.X] = island) || + (p.X > 0 && ownership.[p.Y, p.X - 1] = island) || + (p.X < w - 1 && ownership.[p.Y, p.X + 1] = island) + + while not stop && island.Surface < area do + let level, next = island.Shore.Max + let other = ownership.[next.Y, next.X] + if other = island // During merging, some points on the shore may be owned by the island itself -> ignored. then - stop <- true - else island.Shore.RemoveNext () - for i, j in se do - let ni = i + next.Y - let nj = j + next.X - if ni < 0 || ni >= h || nj < 0 || nj >= w + else + if not <| Object.ReferenceEquals(other, null) + then // We touching another island. + if island.Surface + other.Surface >= area then - island.Surface <- Int32.MaxValue stop <- true - else - let neighbor = Point(nj, ni) - if not <| ownedOrAdjacent neighbor - then - island.Shore.Add earth.[ni, nj, 0] neighbor - if not stop + else // We can merge 'other' into 'surface'. + island.Surface <- island.Surface + other.Surface + island.Level <- if comparer.Compare(island.Level, other.Level) > 0 then island.Level else other.Level + for l, p in other.Shore do + let mutable currentY = p.Y + 1 + while currentY < h && ownership.[currentY, p.X] = other do + ownership.[currentY, p.X] <- island + currentY <- currentY + 1 + island.Shore.Add l p + other.Shore.Clear() + + elif comparer.Compare(level, island.Level) > 0 then - ownership.[next.Y, next.X] <- island - island.Level <- level - island.Surface <- island.Surface + 1 - - for i in 0 .. h - 1 do - for j in 0 .. w - 1 do - let island = ownership.[i, j] - if island <> null - then - earth.[i, j, 0] <- island.Level + stop <- true + else + island.Shore.RemoveNext () + for i, j in se do + let ni = i + next.Y + let nj = j + next.X + if ni < 0 || ni >= h || nj < 0 || nj >= w + then + island.Surface <- Int32.MaxValue + stop <- true + else + let neighbor = Point(nj, ni) + if not <| ownedOrAdjacent neighbor + then + island.Shore.Add earth.[ni, nj, 0] neighbor + if not stop + then + ownership.[next.Y, next.X] <- island + island.Level <- level + island.Surface <- island.Surface + 1 + + let mutable diff = 0.f + + for i in 0 .. h - 1 do + for j in 0 .. w - 1 do + match ownership.[i, j] with + | null -> () + | island -> + let l = island.Level + diff <- diff + l - earth.[i, j, 0] + earth.[i, j, 0] <- l + + match f with + | Some f' -> f' obj diff + | _ -> () () let areaOpenF (img: Image) (area: int) = - areaOperationF img area AreaOperation.Opening + areaOperationF img [ area, () ] None AreaOperation.Opening let areaCloseF (img: Image) (area: int) = - areaOperationF img area AreaOperation.Closing + areaOperationF img [ area, () ] None AreaOperation.Closing + +let areaOpenFWithFun (img: Image) (areas: (int * 'a) list) (f: 'a -> float32 -> unit) = + areaOperationF img areas (Some f) AreaOperation.Opening + +let areaCloseFWithFun (img: Image) (areas: (int * 'a) list) (f: 'a -> float32 -> unit) = + areaOperationF img areas (Some f) AreaOperation.Closing // A simpler algorithm than 'areaOpen' but slower. let areaOpen2 (img: Image) (area: int) = diff --git a/Parasitemia/Parasitemia/KMeans.fs b/Parasitemia/Parasitemia/KMeans.fs index 55b899d..afb6daf 100644 --- a/Parasitemia/Parasitemia/KMeans.fs +++ b/Parasitemia/Parasitemia/KMeans.fs @@ -37,8 +37,9 @@ let kmeans (img: Image) : Result = let fgData = fg.Data for i in 1 .. nbIteration do - if d_bg <> null - then + match d_bg with + | null -> () + | _ -> d_bg.Dispose() d_fg.Dispose() diff --git a/Parasitemia/Parasitemia/MainAnalysis.fs b/Parasitemia/Parasitemia/MainAnalysis.fs index 9f91a6d..043eb73 100644 --- a/Parasitemia/Parasitemia/MainAnalysis.fs +++ b/Parasitemia/Parasitemia/MainAnalysis.fs @@ -19,9 +19,13 @@ let doAnalysis (img: Image) (name: string) (config: Config) : Cell li logTime "areaOpen 1" (fun () -> ImgTools.areaOpenF filteredGreen config.Parameters.initialAreaOpen) - config.RBCRadius <- logTime "Granulometry" (fun() -> Granulometry.findRadius (filteredGreen.Convert()) (10, 100) 0.3 |> float32) + let r1 = logTime "Granulometry (morpho)" (fun() -> Granulometry.findRadiusByClosing (filteredGreen.Convert()) (10, 80) 0.5 |> float32) + // let r2 = logTime "Granulometry (area)" (fun() -> Granulometry.findRadiusByAreaClosing filteredGreen (10, 80) |> float32) + // log (sprintf "r1: %A, r2: %A" r1 r2) + config.RBCRadius <- r1 let secondAreaOpen = int <| config.RBCArea / 3.f + if secondAreaOpen > config.Parameters.initialAreaOpen then logTime "areaOpen 2" (fun () -> ImgTools.areaOpenF filteredGreen secondAreaOpen) diff --git a/Parasitemia/Parasitemia/MainWindow.xaml b/Parasitemia/Parasitemia/MainWindow.xaml deleted file mode 100644 index 4d1a8b0..0000000 --- a/Parasitemia/Parasitemia/MainWindow.xaml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Parasitemia/Parasitemia/Parasitemia.fsproj b/Parasitemia/Parasitemia/Parasitemia.fsproj index 14e1c11..abdb475 100644 --- a/Parasitemia/Parasitemia/Parasitemia.fsproj +++ b/Parasitemia/Parasitemia/Parasitemia.fsproj @@ -30,6 +30,20 @@ false --folder "../../../Images/debug" --output "../../../Images/output" --debug + + true + full + false + false + DEBUG;TRACE + 3 + x64 + bin\Debug\Parasitemia.XML + false + + + bin\DebugGUI\ + pdbonly true @@ -60,10 +74,6 @@ - - - - @@ -77,9 +87,16 @@ - + + + + + + + + @@ -99,6 +116,10 @@ ..\packages\FSharp.Core.4.0.0.1\lib\net40\FSharp.Core.dll True + + ..\packages\FSharp.Data.2.2.5\lib\net40\FSharp.Data.dll + True + ..\packages\FSharp.ViewModule.Core.0.9.9.2\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\FSharp.ViewModule.dll True @@ -131,6 +152,8 @@ + + ..\packages\Expression.Blend.Sdk.1.0.2\lib\net45\System.Windows.Interactivity.dll @@ -138,6 +161,7 @@ + diff --git a/Parasitemia/Parasitemia/Program.fs b/Parasitemia/Parasitemia/Program.fs index f477cfe..f0e2748 100644 --- a/Parasitemia/Parasitemia/Program.fs +++ b/Parasitemia/Parasitemia/Program.fs @@ -2,32 +2,15 @@ open System open System.IO -open System.Windows -open System.Windows.Media -open System.Windows.Markup -open System.Windows.Shapes -open System.Windows.Controls -open System.Drawing -open System.Diagnostics open System.Threading open FSharp.Collections.ParallelSeq open Emgu.CV open Emgu.CV.Structure -open Emgu.CV.WPF open Config -let display (window : Views.MainWindow) (img : IImage) = - let imgControl = window.Root.FindName("img") :?> Controls.Image - imgControl.Source <- BitmapSourceConvert.ToBitmapSource(img) - -let log (window : Views.MainWindow) (mess : string) = - let txtLog = window.Root.FindName("txtLog") :?> Controls.TextBlock - txtLog.Text <- txtLog.Text + mess + "\n" - - type Input = | File of string | Dir of string @@ -57,6 +40,7 @@ let parseArgs (args: string[]) : Arguments = [] +[] let main args = match parseArgs args with | mode, debug -> @@ -65,8 +49,8 @@ let main args = { initialAreaOpen = 2000 - minRbcRadius = -0.32f - maxRbcRadius = 0.32f + minRbcRadius = -0.3f + maxRbcRadius = 0.3f preFilterSigma = 1.7 // 1.5 @@ -125,15 +109,13 @@ let main args = 0 | Window -> - let app = new Application() - let mainWindow = Views.MainWindow() - - if debug - then - config.Debug <- DebugOn "." + (*let display (window : Views.MainWindow) (img : IImage) = + let imgControl = window.Root.FindName("img") :?> Controls.Image + imgControl.Source <- BitmapSourceConvert.ToBitmapSource(img) - Utils.log <- (fun m -> log mainWindow m) + let log (window : Views.MainWindow) (mess : string) = + let txtLog = window.Root.FindName("txtLog") :?> Controls.TextBlock + txtLog.Text <- txtLog.Text + mess + "\n"*) - //display mainWindow img - mainWindow.Root.Show() - app.Run() + if debug then config.Debug <- DebugOn "." + GUI.run config diff --git a/Parasitemia/Parasitemia/Types.fs b/Parasitemia/Parasitemia/Types.fs index 6240519..872844b 100644 --- a/Parasitemia/Parasitemia/Types.fs +++ b/Parasitemia/Parasitemia/Types.fs @@ -48,6 +48,7 @@ type CellClass = HealthyRBC | InfectedRBC | Peculiar type Cell = { cellClass: CellClass center: Point + stainArea: int elements: Matrix } [] diff --git a/Parasitemia/Parasitemia/packages.config b/Parasitemia/Parasitemia/packages.config index d6eabef..da70217 100644 --- a/Parasitemia/Parasitemia/packages.config +++ b/Parasitemia/Parasitemia/packages.config @@ -4,6 +4,7 @@ + -- 2.43.0