Change the way the dark stain is marked.
authorGreg Burri <greg.burri@gmail.com>
Mon, 1 Feb 2016 09:02:08 +0000 (10:02 +0100)
committerGreg Burri <greg.burri@gmail.com>
Mon, 1 Feb 2016 09:02:08 +0000 (10:02 +0100)
Parasitemia/ParasitemiaCore/Config.fs
Parasitemia/ParasitemiaCore/MatchingEllipses.fs
Parasitemia/ParasitemiaCore/ParasitesMarker.fs
Parasitemia/ParasitemiaUI/State.fs

index d50ab0e..21a36f9 100644 (file)
@@ -35,6 +35,7 @@ type Parameters = {
     parasiteRadiusRatio: float32 // The ratio of the parasite radius of the RBC radius.
     minimumParasiteAreaRatio: float32 // Factor of a RBC area. 0.5 means the half of RBC area.
 
+    cytoplasmSizeRatio: float32
     cytoplasmSensitivity: float // between 0 (the least sensitive) and 1 (the most sensitive).
 
     nucleusAreaRatio: float32 // Factor of a RBC area. 0.5 means the half of RBC area.
@@ -61,12 +62,13 @@ let defaultParameters = {
     factorNbValidPick = 0.06 //1.0
     factorNbMaxPick = 4.
 
-    darkStainLevel = 0.25
+    darkStainLevel = 1.1
     maxDarkStainRatio = 0.1 // 10 %
 
-    parasiteRadiusRatio = 0.5f // 40 %
-
+    parasiteRadiusRatio = 0.5f // 50 %
     minimumParasiteAreaRatio = 0.02f // 2 %
+
+    cytoplasmSizeRatio = 1.f / 5.f
     cytoplasmSensitivity = 0.96
 
     nucleusAreaRatio = 0.01f // 1.0 %
@@ -87,6 +89,7 @@ type RBCRadius (radius: float32, parameters: Parameters) =
     member this.MinArea = parameters.minimumCellAreaFactor * this.Area
 
     member this.ParasiteRadius = parameters.parasiteRadiusRatio * radius
+    member this.CytoplasmSize = parameters.cytoplasmSizeRatio * radius
 
     member this.NucleusArea = parameters.nucleusAreaRatio * this.Area
     member this.MinimumParasiteArea = parameters.minimumParasiteAreaRatio * this.Area
index af72e57..d4a6a41 100644 (file)
@@ -12,8 +12,9 @@ open Utils
 // All ellipses with a score below this are removed.
 let matchingScoreThresholdPerRadiusUnit = 0.07f // For a radius of 1. // 0.25
 let matchingScorePower = 20.f
-let windowSizeRadiusFactor = 1.f / 2.f
+let windowSizeRadiusFactor = 1.f / 2.f // Used when searching for neighbor ellipses.
 let minimumDistanceFromCenterRadiusFactor = 1.f / 3.f
+let minimumAreaFactor = 1.1f;
 
 type private EllipseScoreFlaggedKd (matchingScore: float32, e: Ellipse) =
     let mutable matchingScore = matchingScore
@@ -92,7 +93,7 @@ type MatchingEllipses (radius: float32) =
                             else
                                 // Case where ellipses are overlapped.
                                 match EEOver.EEOverlapArea e.Ellipse other.Ellipse with
-                                | Some (overlapArea, _, _) when e.Ellipse.Area < 1.1f * overlapArea || other.Ellipse.Area < 1.1f * overlapArea ->
+                                | Some (overlapArea, _, _) when e.Ellipse.Area < minimumAreaFactor * overlapArea || other.Ellipse.Area < minimumAreaFactor * overlapArea ->
                                     other.Removed <- true
                                 | _ ->
                                     ()
index 0d7c7ae..2b70682 100644 (file)
@@ -27,7 +27,7 @@ let find (img: Image<Gray, float32>) (config: Config.Config) : Result * Image<Gr
         let _, mean_fg, mean_bg =
             let hist = histogramImg imgWithoutNucleus 300
             otsu hist
-        imgWithoutNucleus.Cmp(-(float mean_bg) * config.Parameters.darkStainLevel + (float mean_fg), CvEnum.CmpType.LessThan)
+        imgWithoutNucleus.Cmp(float mean_fg - config.Parameters.darkStainLevel * float (mean_bg - mean_fg), CvEnum.CmpType.LessThan)
 
     let marker (img: Image<Gray, float32>) (closed: Image<Gray, float32>) (level: float) : Image<Gray, byte> =
         let diff = img.Copy()
@@ -36,11 +36,13 @@ let find (img: Image<Gray, float32>) (config: Config.Config) : Result * Image<Gr
         diff._ThresholdBinary(Gray(0.0), Gray(255.))
         diff.Convert<Gray, byte>()
 
+    // Nucleus.
     let nucleusMarker = marker img imgWithoutNucleus (1. / config.Parameters.infectionSensitivity)
 
+    // Cytoplasm.
     let imgWithoutParasite = img.CopyBlank()
     let kernelSize =
-        let size = roundInt (config.RBCRadius.Pixel / 5.f)
+        let size = roundInt config.RBCRadius.CytoplasmSize
         if size % 2 = 0 then size + 1 else size
     use kernel =
         if kernelSize <= 3
index 5b6a91c..69662d5 100644 (file)
@@ -136,7 +136,7 @@ type State (defaultConfig: ParasitemiaCore.Config.Config) =
         // To match with previously manually altered RBC.
         let manuallyAlteredPreviousRBCS = sourceImage.rbcs |> List.filter (fun rbc -> rbc.setManually)
         let tolerance = (float sourceImage.config.RBCRadius.Pixel) * 0.5 // +/-.
-        let getPreviousRBC (center: Point) : RBC option =
+        let getPreviousManuallyAlteredRBC (center: Point) : RBC option =
             manuallyAlteredPreviousRBCS |> List.tryFind (fun rbc -> rbc.center.X > center.X - tolerance && rbc.center.X < center.X + tolerance &&
                                                                     rbc.center.Y > center.Y - tolerance && rbc.center.Y < center.Y + tolerance)
 
@@ -146,9 +146,10 @@ type State (defaultConfig: ParasitemiaCore.Config.Config) =
             |> List.mapi (fun i cell ->
                 let center = Point(float cell.center.X, float cell.center.Y)
                 let infected, setManually =
-                    match getPreviousRBC center with
-                    | Some rbc -> rbc.infected, true
-                    | _ -> cell.cellClass = ParasitemiaCore.Types.InfectedRBC, false
+                    let infected = cell.cellClass = ParasitemiaCore.Types.InfectedRBC
+                    match getPreviousManuallyAlteredRBC center with
+                    | Some rbc when rbc.infected <> infected -> rbc.infected, true // If it has been previously manually changed and now match the result, the manually flag is removed.
+                    | _ -> infected, false
 
                 { num = i + 1
                   infected = infected