From 04d4504e7b248a82ddfc1a41d325e59d24146590 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Fri, 29 Jan 2016 22:58:21 +0100 Subject: [PATCH] Cleaning and some little tweaks. --- Parasitemia/ParasitemiaCore/Analysis.fs | 6 ++-- Parasitemia/ParasitemiaCore/Config.fs | 8 ++--- Parasitemia/ParasitemiaCore/Ellipse.fs | 30 +++++++------------ Parasitemia/ParasitemiaCore/Granulometry.fs | 7 +++-- Parasitemia/ParasitemiaCore/ImgTools/Edges.fs | 25 +++++++--------- .../ParasitemiaCore/ParasitemiaCore.fsproj | 4 +-- Parasitemia/ParasitemiaUI/Analysis.fs | 4 +-- Parasitemia/ParasitemiaUI/DPICalculator.fs | 4 +-- .../ParasitemiaUI/ParasitemiaUI.fsproj | 4 +-- .../XAML/DPICalculatorWindow.xaml.fs | 6 ---- .../XAML/ImageSourceSelection.xaml | 2 +- ...orWindow.xaml => PPICalculatorWindow.xaml} | 4 +-- .../XAML/PPICalculatorWindow.xaml.fs | 6 ++++ 13 files changed, 51 insertions(+), 59 deletions(-) delete mode 100644 Parasitemia/ParasitemiaUI/XAML/DPICalculatorWindow.xaml.fs rename Parasitemia/ParasitemiaUI/XAML/{DPICalculatorWindow.xaml => PPICalculatorWindow.xaml} (93%) create mode 100644 Parasitemia/ParasitemiaUI/XAML/PPICalculatorWindow.xaml.fs diff --git a/Parasitemia/ParasitemiaCore/Analysis.fs b/Parasitemia/ParasitemiaCore/Analysis.fs index bad0daf..7f58463 100644 --- a/Parasitemia/ParasitemiaCore/Analysis.fs +++ b/Parasitemia/ParasitemiaCore/Analysis.fs @@ -67,7 +67,9 @@ let doAnalysis (img: Image) (name: string) (config: Config) (reportPr let range = let delta = config.Parameters.granulometryRange * config.RBCRadiusByResolution.Pixel int <| config.RBCRadiusByResolution.Pixel - delta, int <| config.RBCRadiusByResolution.Pixel + delta + let! radius = logTimeWithName "Granulometry (area)" (fun() -> reportWithVal 10 (Granulometry.findRadiusByAreaClosing img_RBC_filtered range |> float32)) + //let! radius = logTimeWithName "Granulometry (morpho)" (fun() -> reportWithVal 10 (Granulometry.findRadiusByClosing img_RBC_filtered range 1. true |> float32)) config.SetRBCRadius <| radius logWithName (sprintf "Found erythrocyte diameter: %A" config.RBCRadius) @@ -119,8 +121,8 @@ let doAnalysis (img: Image) (name: string) (config: Config) (reportPr IO.saveImg parasites.parasite (buildFileName " - parasites - stain.png") IO.saveImg parasites.nucleus (buildFileName " - parasites - infection.png") - let imgAllEllipses = img.Copy() - Drawing.drawEllipses imgAllEllipses matchingEllipses.Ellipses (Bgr(255.0, 255.0, 255.0)) 0.04 + let imgAllEllipses = img_RBC_filtered.Copy() + Drawing.drawEllipses imgAllEllipses matchingEllipses.Ellipses (Gray(200.0)) 0.04 IO.saveImg imgAllEllipses (buildFileName " - ellipses - all.png") let imgEllipses = img_RBC_filtered.Convert() diff --git a/Parasitemia/ParasitemiaCore/Config.fs b/Parasitemia/ParasitemiaCore/Config.fs index 385b7d4..5e3280c 100644 --- a/Parasitemia/ParasitemiaCore/Config.fs +++ b/Parasitemia/ParasitemiaCore/Config.fs @@ -43,17 +43,17 @@ type Parameters = { let defaultParameters = { rbcDiameter = 7.5<μm> - resolution = 220.e3 // 220.e3 Correspond to 50X. + resolution = 230.e3 // 230.e3 Correspond to 50X. ratioAreaPaleCenter = 2.f / 5.f // The ratio between an RBC area and the area of the its pale center. granulometryRange = 0.5f - minRbcRadius = -0.3f - maxRbcRadius = 0.3f + minRbcRadius = -0.23f + maxRbcRadius = 0.23f LPFStandardDeviationParasite = 0.15<μm> - LPFStandardDeviationRBC = 0.2<μm> + LPFStandardDeviationRBC = 0.22<μm> factorNbPick = 1.0 diff --git a/Parasitemia/ParasitemiaCore/Ellipse.fs b/Parasitemia/ParasitemiaCore/Ellipse.fs index 4e48230..db23ece 100644 --- a/Parasitemia/ParasitemiaCore/Ellipse.fs +++ b/Parasitemia/ParasitemiaCore/Ellipse.fs @@ -14,6 +14,9 @@ open Config open MatchingEllipses open Const +// This is a ratio of the biggest radius. +let minimumDistanceBetweenDrawnPoints = 0.6 + /// /// Try to build an ellipse from three points and two tangents passing by the first and the second point. /// 'Ellipse.A' is always equal or greater than Ellipse.B. @@ -76,28 +79,17 @@ let ellipse (p1x: float) (p1y: float) (m1: float) (p2x: float) (p2y: float) (m2: let private vectorRotation (p1x: float32) (p1y: float32) (v1x: float32) (v1y: float32) (px: float32) (py: float32) : float32 = - let mutable rotation = 1.f if p1y > py then - if v1x > 0.f - then - rotation <- -1.f + if v1x > 0.f then -1.f else 1.f elif p1y < py then - if v1x < 0.f - then - rotation <- -1.f + if v1x < 0.f then -1.f else 1.f elif p1x > px then - if v1y < 0.f - then - rotation <- -1.f - elif p1x < px - then - if v1y > 0.f - then - rotation <- -1.f - rotation + if v1y < 0.f then -1.f else 1.f + else // p1x < px + if v1y > 0.f then -1.f else 1.f let private areVectorsValid (p1x: float32) (p1y: float32) (p2x: float32) (p2y: float32) (v1x: float32) (v1y: float32) (v2x: float32) (v2y: float32) : (float32 * float32) option = let m1 = -v1x / v1y @@ -125,9 +117,9 @@ let private areVectorsValid (p1x: float32) (p1y: float32) (p2x: float32) (p2y: f if diff > PI || (diff < 0.f && diff > -PI) then - None + Some (m1, m2) else - Some (m1, m2) + None let find (edges: Matrix) (xGradient: Matrix) @@ -145,7 +137,7 @@ let find (edges: Matrix) let radiusTolerance = (r2 - r1) * 0.2f - let squaredMinimumDistance = (float r2 / 1.5) ** 2. + let squaredMinimumDistance = (float config.RBCRadius.Pixel * minimumDistanceBetweenDrawnPoints) ** 2. let inline squaredDistance x1 y1 x2 y2 = (x1 - x2) ** 2. + (y1 - y2) ** 2. let h = edges.Height diff --git a/Parasitemia/ParasitemiaCore/Granulometry.fs b/Parasitemia/ParasitemiaCore/Granulometry.fs index b325534..877df99 100644 --- a/Parasitemia/ParasitemiaCore/Granulometry.fs +++ b/Parasitemia/ParasitemiaCore/Granulometry.fs @@ -1,6 +1,7 @@ module ParasitemiaCore.Granulometry open System +open System.IO open System.Drawing open Emgu.CV @@ -24,7 +25,7 @@ let findRadiusByClosing (img: Image) (range: int * int) (scale: f let intensityImg = scaledImg.GetSum().Intensity // 's' must be odd. - let octagon (s: int) : Mat = + 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 @@ -36,12 +37,12 @@ let findRadiusByClosing (img: Image) (range: int * int) (scale: f m.[s - i - 1, j] <- 0uy m.[i, s - j - 1] <- 0uy m.[s - i - 1, s - j - 1] <- 0uy - m.Mat + m let mutable previous_n = Double.NaN for r in r1' .. r2' do let se = if useOctagon - then octagon (2 * r - 1) // It doesnd't speed up the process. + then (octagon (2 * r - 1)).Mat // It doesn't speed up the process. else CvInvoke.GetStructuringElement(CvEnum.ElementShape.Ellipse, Size(2 * r, 2 * r), Point(-1, -1)) use closed = scaledImg.MorphologyEx(CvEnum.MorphOp.Close, se, Point(-1, -1), 1, CvEnum.BorderType.Replicate, MCvScalar(0.0)) diff --git a/Parasitemia/ParasitemiaCore/ImgTools/Edges.fs b/Parasitemia/ParasitemiaCore/ImgTools/Edges.fs index b174ee9..a1b6033 100644 --- a/Parasitemia/ParasitemiaCore/ImgTools/Edges.fs +++ b/Parasitemia/ParasitemiaCore/ImgTools/Edges.fs @@ -11,6 +11,10 @@ open Const open Histogram open Otsu +// Sensibilities of the hysteresis search. +let sensibilityHigh = 0.1f +let sensibilityLow = 0.0f + /// /// Find edges of an image by using the Canny approach. /// The thresholds are automatically defined with otsu on gradient magnitudes. @@ -21,9 +25,9 @@ let find (img: Image) : Matrix * Matrix * Matrix(array2D [[ 1.0f; 0.0f; -1.0f ] - [ 2.0f; 0.0f; -2.0f ] - [ 1.0f; 0.0f; -1.0f ]]) + new Matrix(array2D [[ -1.0f; 0.0f; 1.0f ] + [ -2.0f; 0.0f; 2.0f ] + [ -1.0f; 0.0f; 1.0f ]]) let xGradient = new Matrix(img.Size) let yGradient = new Matrix(img.Size) @@ -32,11 +36,9 @@ let find (img: Image) : Matrix * Matrix * Matrix(xGradient.Size) use angles = new Matrix(xGradient.Size) - CvInvoke.CartToPolar(xGradient, yGradient, magnitudes, angles) // Compute the magnitudes and angles. + CvInvoke.CartToPolar(xGradient, yGradient, magnitudes, angles) // Compute the magnitudes and angles. The angles are between 0 and 2 * pi. let thresholdHigh, thresholdLow = - let sensibilityHigh = 0.1f - let sensibilityLow = 0.0f let threshold, _, _ = otsu (histogramMat magnitudes 300) threshold + (sensibilityHigh * threshold), threshold - (sensibilityLow * threshold) @@ -49,14 +51,6 @@ let find (img: Image) : Matrix * Matrix * Matrix) : Matrix * Matrix * Matrix(xGradient.Size) let edgesData = edges.Data diff --git a/Parasitemia/ParasitemiaCore/ParasitemiaCore.fsproj b/Parasitemia/ParasitemiaCore/ParasitemiaCore.fsproj index 473f11d..1acdac0 100644 --- a/Parasitemia/ParasitemiaCore/ParasitemiaCore.fsproj +++ b/Parasitemia/ParasitemiaCore/ParasitemiaCore.fsproj @@ -54,10 +54,10 @@ - - + + diff --git a/Parasitemia/ParasitemiaUI/Analysis.fs b/Parasitemia/ParasitemiaUI/Analysis.fs index 70d9ef0..5bb3500 100644 --- a/Parasitemia/ParasitemiaUI/Analysis.fs +++ b/Parasitemia/ParasitemiaUI/Analysis.fs @@ -63,8 +63,8 @@ let showWindow (parent: Window) (state: State.State) : bool = imageSourceSelection.menuZoom50X.Click.AddHandler(fun obj args -> imageSourceSelection.txtResolution.Text <- "230000") imageSourceSelection.menuZoom100X.Click.AddHandler(fun obj args -> imageSourceSelection.txtResolution.Text <- "460000") - imageSourceSelection.butDPICalculator.Click.AddHandler(fun obj args -> - match DPICalculator.showWindow win.Root with + imageSourceSelection.butPPICalculator.Click.AddHandler(fun obj args -> + match PPICalculator.showWindow win.Root with | Some resolution -> imageSourceSelection.txtResolution.Text <- resolution.ToString() | None -> ()) diff --git a/Parasitemia/ParasitemiaUI/DPICalculator.fs b/Parasitemia/ParasitemiaUI/DPICalculator.fs index dbd7251..5e9c19b 100644 --- a/Parasitemia/ParasitemiaUI/DPICalculator.fs +++ b/Parasitemia/ParasitemiaUI/DPICalculator.fs @@ -1,4 +1,4 @@ -module ParasitemiaUI.DPICalculator +module ParasitemiaUI.PPICalculator open System open System.Windows @@ -19,7 +19,7 @@ type SensorSize = { sprintf "%g mm × %g mm%s" this.w this.h (if this.txt = "" then "" else " (" + this.txt + ")") let showWindow (parent: Window) : int option = - let win = Views.DPICalculatorWindow() + let win = Views.PPICalculatorWindow() win.Root.Owner <- parent win.Root.Left <- parent.Left + parent.ActualWidth / 2. - win.Root.Width / 2. win.Root.Top <- parent.Top + parent.ActualHeight / 2. - win.Root.Height / 2. diff --git a/Parasitemia/ParasitemiaUI/ParasitemiaUI.fsproj b/Parasitemia/ParasitemiaUI/ParasitemiaUI.fsproj index 2231bf4..a423093 100644 --- a/Parasitemia/ParasitemiaUI/ParasitemiaUI.fsproj +++ b/Parasitemia/ParasitemiaUI/ParasitemiaUI.fsproj @@ -74,8 +74,8 @@ - - + + diff --git a/Parasitemia/ParasitemiaUI/XAML/DPICalculatorWindow.xaml.fs b/Parasitemia/ParasitemiaUI/XAML/DPICalculatorWindow.xaml.fs deleted file mode 100644 index ef9cbf4..0000000 --- a/Parasitemia/ParasitemiaUI/XAML/DPICalculatorWindow.xaml.fs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ParasitemiaUI.Views - -open FsXaml - -type DPICalculatorWindow = XAML<"XAML/DPICalculatorWindow.xaml", true> - diff --git a/Parasitemia/ParasitemiaUI/XAML/ImageSourceSelection.xaml b/Parasitemia/ParasitemiaUI/XAML/ImageSourceSelection.xaml index 94ca3ed..83fa943 100644 --- a/Parasitemia/ParasitemiaUI/XAML/ImageSourceSelection.xaml +++ b/Parasitemia/ParasitemiaUI/XAML/ImageSourceSelection.xaml @@ -67,7 +67,7 @@ -