X-Git-Url: http://git.euphorik.ch/?p=master-thesis.git;a=blobdiff_plain;f=Parasitemia%2FParasitemia%2FMatchingEllipses.fs;h=2022c2644789f64947f0c99e3f6da33e17f94a6d;hp=9b870dcbf9c87d60b7e7fec1c416dc7450da8d50;hb=53440e757b4a4ab2a81b0f6a5dd1a2002c0133ba;hpb=06bd63d8c01100c28873dfafd59b5efccbfb67e4 diff --git a/Parasitemia/Parasitemia/MatchingEllipses.fs b/Parasitemia/Parasitemia/MatchingEllipses.fs index 9b870dc..2022c26 100644 --- a/Parasitemia/Parasitemia/MatchingEllipses.fs +++ b/Parasitemia/Parasitemia/MatchingEllipses.fs @@ -9,91 +9,103 @@ open Types open Utils +// Do not take in account matching score below this when two ellipses are matched. let matchingScoreThreshold1 = 0.6 -let matchingScoreThreshold2 = 1.0 -type EllipseScore (matchingScore: float, e: Ellipse) = +let scaleOverlapTest = 0.8 + +type private EllipseScoreFlaggedKd (matchingScore: float, e: Ellipse) = let mutable matchingScore = matchingScore - member this.MatchingScore = matchingScore member this.Ellipse = e - member val Processed = false with get, set - member val Removed = false with get, set + + member this.MatchingScore = matchingScore member this.AddMatchingScore(score: float) = matchingScore <- matchingScore + score - - interface KdTree.I2DCoords with - member this.X = e.Cx - member this.Y = e.Cy - + + member val Processed = false with get, set + member val Removed = false with get, set + + interface KdTree.I2DCoords with + member this.X = this.Ellipse.Cx + member this.Y = this.Ellipse.Cy + + type MatchingEllipses (radiusMin: float) = - let ellipses = List() - - member this.Add (e: Ellipse) = - ellipses.Add(EllipseScore(0.0, e)) + let ellipses = List() + + // All ellipses with a score below this are removed. + let matchingScoreThreshold2 = 20. * radiusMin + + member this.Add (e: Ellipse) = + ellipses.Add(EllipseScoreFlaggedKd(0.0, e)) member this.Ellipses : Ellipse list = - // 1) Create a kd-tree from the ellipses list. - let tree = KdTree.Tree.buildTree (List.ofSeq ellipses) - - // 2) Compute the matching score of each ellipses. - let windowSize = radiusMin - for e in ellipses do - e.Processed <- true - let areaE = e.Ellipse.Area - let window = { KdTree.minX = e.Ellipse.Cx - windowSize / 2.0 - KdTree.maxX = e.Ellipse.Cx + windowSize / 2.0 - KdTree.minY = e.Ellipse.Cy - windowSize / 2.0 - KdTree.maxY = e.Ellipse.Cy + windowSize / 2.0 } - for other in KdTree.Tree.search tree window do - if not other.Processed - then - let areaOther = other.Ellipse.Area - match EEOver.EEOverlapArea e.Ellipse other.Ellipse with - | Some (commonArea, _, _) -> - let matchingScore = 2.0 * commonArea / (areaE + areaOther) - if matchingScore >= matchingScoreThreshold1 - then - other.AddMatchingScore(matchingScore) - e.AddMatchingScore(matchingScore) - | _ -> () - - // 3) Sort ellipses by their score. - ellipses.Sort(fun e1 e2 -> e2.MatchingScore.CompareTo(e1.MatchingScore)) - - // 4) Remove ellipses wich have a low score. - let i = ellipses.BinarySearch(EllipseScore(matchingScoreThreshold2, Ellipse(0.0, 0.0, 0.0, 0.0, 0.0)), - { new IComparer with - member this.Compare(e1, e2) = e2.MatchingScore.CompareTo(e1.MatchingScore) }) |> abs - let nbToRemove = ellipses.Count - i - if nbToRemove > 0 - then - for j in i .. nbToRemove - 1 do - ellipses.[j].Removed <- true - ellipses.RemoveRange(i, nbToRemove) + List.ofSeq ellipses |> List.map (fun e -> e.Ellipse) - // 5) Remove ellipses whose center is into an ellipse with a better score - for e in ellipses do - if not e.Removed + // Process all ellipses and return ellipses ordered from the best score to the worst. + member this.PrunedEllipses : Ellipse list = + if ellipses.Count = 0 + then + [] + else + // 1) Create a kd-tree from the ellipses list. + let tree = KdTree.Tree.BuildTree (List.ofSeq ellipses) + + // 2) Compute the matching score of each ellipses. + let windowSize = radiusMin + for e in ellipses do + e.Processed <- true + let areaE = e.Ellipse.Area + let window = { KdTree.minX = e.Ellipse.Cx - windowSize / 2.0 + KdTree.maxX = e.Ellipse.Cx + windowSize / 2.0 + KdTree.minY = e.Ellipse.Cy - windowSize / 2.0 + KdTree.maxY = e.Ellipse.Cy + windowSize / 2.0 } + for other in tree.Search window do + if not other.Processed + then + let areaOther = other.Ellipse.Area + match EEOver.EEOverlapArea e.Ellipse other.Ellipse with + | Some (commonArea, _, _) -> + let matchingScore = 2.0 * commonArea / (areaE + areaOther) + if matchingScore >= matchingScoreThreshold1 + then + other.AddMatchingScore(matchingScore * e.Ellipse.Perimeter) + e.AddMatchingScore(matchingScore * other.Ellipse.Perimeter) + | _ -> () + + // 3) Sort ellipses by their score. + ellipses.Sort(fun e1 e2 -> e2.MatchingScore.CompareTo(e1.MatchingScore)) + + // 4) Remove ellipses with a low score. + let i = ellipses.BinarySearch(EllipseScoreFlaggedKd(matchingScoreThreshold2, Ellipse(0.0, 0.0, 0.0, 0.0, 0.0)), + { new IComparer with + member this.Compare(e1, e2) = e2.MatchingScore.CompareTo(e1.MatchingScore) }) |> abs + let nbToRemove = ellipses.Count - i + if nbToRemove > 0 then - let window = { KdTree.minX = e.Ellipse.Cx - e.Ellipse.A - KdTree.maxX = e.Ellipse.Cx + e.Ellipse.A - KdTree.minY = e.Ellipse.Cy - e.Ellipse.A - KdTree.maxY = e.Ellipse.Cy + e.Ellipse.A } - for other in KdTree.Tree.search tree window do - if not other.Removed && other.MatchingScore < e.MatchingScore - then - if e.Ellipse.Contains other.Ellipse.Cx other.Ellipse.Cy + for j in i .. nbToRemove - 1 do + ellipses.[j].Removed <- true + ellipses.RemoveRange(i, nbToRemove) + + // 5) Remove ellipses whose center is into an ellipse with a better score + for e in ellipses do + if not e.Removed + then + let window = { KdTree.minX = e.Ellipse.Cx - e.Ellipse.A + KdTree.maxX = e.Ellipse.Cx + e.Ellipse.A + KdTree.minY = e.Ellipse.Cy - e.Ellipse.A + KdTree.maxY = e.Ellipse.Cy + e.Ellipse.A } + for other in tree.Search window do + if not other.Removed && other.MatchingScore < e.MatchingScore then - other.Removed <- true - ellipses.RemoveAll(fun e -> e.Removed) |> ignore + if e.Ellipse.Scale(scaleOverlapTest).Contains other.Ellipse.Cx other.Ellipse.Cy + then + other.Removed <- true + ellipses.RemoveAll(fun e -> e.Removed) |> ignore - dprintfn "Number of ellipse: %A" ellipses.Count + List.ofSeq ellipses |> List.map (fun e -> e.Ellipse) - List.ofSeq ellipses |> List.map (fun e -> e.Ellipse) - - -