6e571995c0548da9486d8bd2b2e3201b03e65775
1
module MatchingEllipses
5 open System.Collections
6 open System.Collections.Generic
12 // Do not take in account matching score below this when two ellipses are matched.
14 let matchingScoreThreshold1 = 0.6f
17 let scaleOverlapTest = 0.8f
19 type private EllipseScoreFlaggedKd (matchingScore
: float32
, e
: Ellipse) =
20 let mutable matchingScore = matchingScore
22 member this
.Ellipse = e
24 member this
.MatchingScore = matchingScore
26 member this
.AddMatchingScore(score
: float32
) =
27 matchingScore <- matchingScore + score
29 member val Processed = false with get
, set
30 member val Removed = false with get
, set
32 interface KdTree.I2DCoords with
33 member this
.X = this
.Ellipse.Cx
34 member this
.Y = this
.Ellipse.Cy
37 type MatchingEllipses (radiusMin
: float32
) =
38 let ellipses = List<EllipseScoreFlaggedKd>()
40 // All ellipses with a score below this are removed.
41 let matchingScoreThreshold2 = 20.f
* radiusMin
43 member this
.Add (e
: Ellipse) =
44 ellipses.Add(EllipseScoreFlaggedKd(0.f
, e
))
46 member this
.Ellipses : Ellipse list =
47 List.ofSeq
ellipses |> List.map
(fun e
-> e
.Ellipse)
49 // Process all ellipses and return ellipses ordered from the best score to the worst.
50 member this
.PrunedEllipses : Ellipse list =
55 // 1) Create a kd-tree from the ellipses list.
56 let tree = KdTree.Tree.BuildTree (List.ofSeq
ellipses)
58 // 2) Compute the matching score of each ellipses.
59 let windowSize = radiusMin
62 let areaE = e
.Ellipse.Area
63 let window = { KdTree.minX
= e
.Ellipse.Cx - windowSize / 2.f
64 KdTree.maxX
= e
.Ellipse.Cx + windowSize / 2.f
65 KdTree.minY
= e
.Ellipse.Cy - windowSize / 2.f
66 KdTree.maxY
= e
.Ellipse.Cy + windowSize / 2.f
}
67 for other
in tree.Search window do
68 if not
other.Processed
70 let areaOther = other.Ellipse.Area
71 match EEOver.EEOverlapArea e
.Ellipse other.Ellipse with
72 | Some (commonArea
, _
, _
) ->
73 let matchingScore = 2.f
* commonArea
/ (areaE + areaOther)
74 if matchingScore >= matchingScoreThreshold1
76 other.AddMatchingScore(matchingScore * e
.Ellipse.Perimeter)
77 e
.AddMatchingScore(matchingScore * other.Ellipse.Perimeter)
80 // 3) Sort ellipses by their score.
81 ellipses.Sort(fun e1 e2
-> e2
.MatchingScore.CompareTo(e1
.MatchingScore))
83 // 4) Remove ellipses with a low score.
84 let i = ellipses.BinarySearch(EllipseScoreFlaggedKd(matchingScoreThreshold2, Ellipse(0.f
, 0.f
, 0.f
, 0.f
, 0.f
)),
85 { new IComparer<EllipseScoreFlaggedKd> with
86 member this
.Compare(e1
, e2
) = e2
.MatchingScore.CompareTo(e1
.MatchingScore) }) |> abs
87 let nbToRemove = ellipses.Count - i
90 for j
in i .. nbToRemove - 1 do
91 ellipses.[j
].Removed <- true
92 ellipses.RemoveRange(i, nbToRemove)
94 // 5) Remove ellipses whose center is into an ellipse with a better score
98 let window = { KdTree.minX
= e.Ellipse.Cx - e.Ellipse.A
99 KdTree.maxX
= e.Ellipse.Cx + e.Ellipse.A
100 KdTree.minY
= e.Ellipse.Cy - e.Ellipse.A
101 KdTree.maxY
= e.Ellipse.Cy + e.Ellipse.A }
102 for other in tree.Search window do
103 if not
other.Removed && other.MatchingScore < e.MatchingScore
105 if e.Ellipse.Scale(scaleOverlapTest).Contains other.Ellipse.Cx other.Ellipse.Cy
107 other.Removed <- true
108 ellipses.RemoveAll(fun e -> e.Removed) |> ignore
110 List.ofSeq
ellipses |> List.map
(fun e -> e.Ellipse)