X-Git-Url: http://git.euphorik.ch/?a=blobdiff_plain;ds=sidebyside;f=Parasitemia%2FParasitemiaCore%2FMatchingEllipses.fs;fp=Parasitemia%2FParasitemiaCore%2FMatchingEllipses.fs;h=b9b4b83197446ef151598bfa07fda09d25135d11;hb=4bfa3cbdc6145e6944f02e24829ab2ef3a851ac1;hp=0000000000000000000000000000000000000000;hpb=48ecdfc43001c444eff6ad442986049384674af2;p=master-thesis.git diff --git a/Parasitemia/ParasitemiaCore/MatchingEllipses.fs b/Parasitemia/ParasitemiaCore/MatchingEllipses.fs new file mode 100644 index 0000000..b9b4b83 --- /dev/null +++ b/Parasitemia/ParasitemiaCore/MatchingEllipses.fs @@ -0,0 +1,100 @@ +module ParasitemiaCore.MatchingEllipses + +open System +open System.Linq +open System.Collections +open System.Collections.Generic + +open Types +open Utils + +type private EllipseScoreFlaggedKd (matchingScore: float32, e: Ellipse) = + let mutable matchingScore = matchingScore + + member this.Ellipse = e + + member this.MatchingScore = matchingScore + + member this.AddMatchingScore (score: float32) = + matchingScore <- matchingScore + score + + 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 (radius: float32) = + let ellipses = List() + + // All ellipses with a score below this are removed. + let matchingScoreThreshold = 0.8f + + member this.Add (e: Ellipse) = + ellipses.Add(EllipseScoreFlaggedKd(0.f, e)) + + member this.Ellipses : Ellipse list = + List.ofSeq ellipses |> List.map (fun e -> e.Ellipse) + + 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 = radius / 2.f + for e in ellipses do + e.Processed <- true + let areaE = e.Ellipse.Area + let window = { KdTree.minX = e.Ellipse.Cx - windowSize / 2.f + KdTree.maxX = e.Ellipse.Cx + windowSize / 2.f + KdTree.minY = e.Ellipse.Cy - windowSize / 2.f + KdTree.maxY = e.Ellipse.Cy + windowSize / 2.f } + 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 (overlapArea, _, _) -> + let matchingScore = (2.f * overlapArea / (areaE + areaOther)) ** 30.f + if matchingScore <= 1.f // For approximation error. + then + other.AddMatchingScore(matchingScore) + e.AddMatchingScore(matchingScore) + | _ -> () + + // 3) Remove ellipses whose center is near the center of another ellipse with a better score. + for e in ellipses do + if e.MatchingScore < matchingScoreThreshold + then + e.Removed <- true + else + 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 && e.MatchingScore > other.MatchingScore + then + // Case where ellipses are too close. + if distanceTwoPoints (PointD(e.Ellipse.Cx, e.Ellipse.Cy)) (PointD(other.Ellipse.Cx, other.Ellipse.Cy)) < 0.3f * e.Ellipse.B + then + other.Removed <- true + 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 -> + other.Removed <- true + | _ -> + () + + ellipses + |> List.ofSeq + |> List.filter (fun e -> not e.Removed) + |> List.sortWith (fun e1 e2 -> e2.MatchingScore.CompareTo(e1.MatchingScore)) + |> List.map (fun e -> e.Ellipse) +