da74c65655c396bba8a4bd241ccee4ddf2283ddb
[master-thesis.git] / Parasitemia / Parasitemia / MatchingEllipses.fs
1 module MatchingEllipses
2
3 open System
4 open System.Linq
5 open System.Collections
6 open System.Collections.Generic
7
8 open Types
9 open Utils
10
11
12 let matchingScoreThreshold1 = 0.6
13 let matchingScoreThreshold2 = 1.
14
15 type private EllipseScoreFlaggedKd (matchingScore: float, e: Ellipse) =
16 let mutable matchingScore = matchingScore
17
18 member this.Ellipse = e
19
20 member this.MatchingScore = matchingScore
21 member this.AddMatchingScore(score: float) =
22 matchingScore <- matchingScore + score
23
24 member val Processed = false with get, set
25 member val Removed = false with get, set
26
27 interface KdTree.I2DCoords with
28 member this.X = this.Ellipse.Cx
29 member this.Y = this.Ellipse.Cy
30
31
32 type MatchingEllipses (radiusMin: float) =
33 let ellipses = List<EllipseScoreFlaggedKd>()
34
35 member this.Add (e: Ellipse) =
36 ellipses.Add(EllipseScoreFlaggedKd(0.0, e))
37
38 member this.Ellipses : Ellipse list =
39 List.ofSeq ellipses |> List.map (fun e -> e.Ellipse)
40
41 member this.PrunedEllipses : Ellipse list =
42 if ellipses.Count = 0
43 then
44 []
45 else
46 // 1) Create a kd-tree from the ellipses list.
47 let tree = KdTree.Tree.BuildTree (List.ofSeq ellipses)
48
49 // 2) Compute the matching score of each ellipses.
50 let windowSize = radiusMin
51 for e in ellipses do
52 e.Processed <- true
53 let areaE = e.Ellipse.Area
54 let window = { KdTree.minX = e.Ellipse.Cx - windowSize / 2.0
55 KdTree.maxX = e.Ellipse.Cx + windowSize / 2.0
56 KdTree.minY = e.Ellipse.Cy - windowSize / 2.0
57 KdTree.maxY = e.Ellipse.Cy + windowSize / 2.0 }
58 for other in tree.Search window do
59 if not other.Processed
60 then
61 let areaOther = other.Ellipse.Area
62 match EEOver.EEOverlapArea e.Ellipse other.Ellipse with
63 | Some (commonArea, _, _) ->
64 let matchingScore = 2.0 * commonArea / (areaE + areaOther)
65 if matchingScore >= matchingScoreThreshold1
66 then
67 other.AddMatchingScore(matchingScore)
68 e.AddMatchingScore(matchingScore)
69 | _ -> ()
70
71 // 3) Sort ellipses by their score.
72 ellipses.Sort(fun e1 e2 -> e2.MatchingScore.CompareTo(e1.MatchingScore))
73
74 // 4) Remove ellipses wich have a low score.
75 let i = ellipses.BinarySearch(EllipseScoreFlaggedKd(matchingScoreThreshold2, Ellipse(0.0, 0.0, 0.0, 0.0, 0.0)),
76 { new IComparer<EllipseScoreFlaggedKd> with
77 member this.Compare(e1, e2) = e2.MatchingScore.CompareTo(e1.MatchingScore) }) |> abs
78 let nbToRemove = ellipses.Count - i
79 if nbToRemove > 0
80 then
81 for j in i .. nbToRemove - 1 do
82 ellipses.[j].Removed <- true
83 ellipses.RemoveRange(i, nbToRemove)
84
85 // 5) Remove ellipses whose center is into an ellipse with a better score
86 for e in ellipses do
87 if not e.Removed
88 then
89 let window = { KdTree.minX = e.Ellipse.Cx - e.Ellipse.A
90 KdTree.maxX = e.Ellipse.Cx + e.Ellipse.A
91 KdTree.minY = e.Ellipse.Cy - e.Ellipse.A
92 KdTree.maxY = e.Ellipse.Cy + e.Ellipse.A }
93 for other in tree.Search window do
94 if not other.Removed && other.MatchingScore < e.MatchingScore
95 then
96 if e.Ellipse.Contains other.Ellipse.Cx other.Ellipse.Cy
97 then
98 other.Removed <- true
99 ellipses.RemoveAll(fun e -> e.Removed) |> ignore
100
101 List.ofSeq ellipses |> List.map (fun e -> e.Ellipse)
102
103
104