afc4ab7b10c0cb4954c2206cf07238ae905ab1a8
1
module MatchingEllipses
5 open System.Collections
6 open System.Collections.Generic
12 let matchingScoreThreshold1 = 0.6
13 let matchingScoreThreshold2 = 1.0
15 type EllipseScore (matchingScore
: float, e
: Ellipse) =
16 let mutable matchingScore = matchingScore
18 member this
.MatchingScore = matchingScore
19 member this
.Ellipse = e
20 member val Processed = false with get
, set
21 member val Removed = false with get
, set
23 member this
.AddMatchingScore(score
: float) =
24 matchingScore <- matchingScore + score
26 interface KdTree.I2DCoords with
30 type MatchingEllipses (radiusMin
: float) =
31 let ellipses = List<EllipseScore>()
33 member this
.Add (e
: Ellipse) =
34 ellipses.Add(EllipseScore(0.0, e
))
36 member this
.Ellipses : Ellipse list =
37 // 1) Create a kd-tree from the ellipses list.
38 let tree = KdTree.Tree.buildTree
(List.ofSeq
ellipses)
40 // 2) Compute the matching score of each ellipses.
41 let windowSize = radiusMin
44 let areaE = e
.Ellipse.Area
45 let window = { KdTree.minX
= e
.Ellipse.Cx - windowSize / 2.0
46 KdTree.maxX
= e
.Ellipse.Cx + windowSize / 2.0
47 KdTree.minY
= e
.Ellipse.Cy - windowSize / 2.0
48 KdTree.maxY
= e
.Ellipse.Cy + windowSize / 2.0 }
49 for other
in KdTree.Tree.search
tree window do
50 if not
other.Processed
52 let areaOther = other.Ellipse.Area
53 let commonArea = EEOver.EEOverlapArea e
.Ellipse other.Ellipse
54 let matchingScore = 2.0 * commonArea / (areaE + areaOther)
55 if matchingScore >= matchingScoreThreshold1
57 other.AddMatchingScore(matchingScore)
58 e
.AddMatchingScore(matchingScore)
60 // 3) Sort ellipses by their score.
61 ellipses.Sort(fun e1 e2
-> e2
.MatchingScore.CompareTo(e1
.MatchingScore))
63 // 4) Remove ellipses wich have a low score.
64 let i = ellipses.BinarySearch(EllipseScore(matchingScoreThreshold2, Ellipse(0.0, 0.0, 0.0, 0.0, 0.0)),
65 { new IComparer<EllipseScore> with
66 member this
.Compare(e1
, e2
) = e2
.MatchingScore.CompareTo(e1
.MatchingScore) }) |> abs
67 let nbToRemove = ellipses.Count - i
70 for j
in i .. nbToRemove - 1 do
71 ellipses.[j
].Removed <- true
72 ellipses.RemoveRange(i, nbToRemove)
74 // 5) Remove ellipses whose center is into an ellipse with a better score
78 let window = { KdTree.minX
= e.Ellipse.Cx - e.Ellipse.A
79 KdTree.maxX
= e.Ellipse.Cx + e.Ellipse.A
80 KdTree.minY
= e.Ellipse.Cy - e.Ellipse.A
81 KdTree.maxY
= e.Ellipse.Cy + e.Ellipse.A }
82 for other in KdTree.Tree.search
tree window do
83 if not
other.Removed && other.MatchingScore < e.MatchingScore
85 if e.Ellipse.Contains other.Ellipse.Cx other.Ellipse.Cy
88 ellipses.RemoveAll(fun e -> e.Removed) |> ignore
90 dprintfn
"Number of ellipse: %A" ellipses.Count
92 List.ofSeq
ellipses |> List.map
(fun e -> e.Ellipse)