0964953c02793d3dd48eb624c37899c613d232bf
[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.0
14
15 type EllipseScore (matchingScore: float, e: Ellipse) =
16 let mutable matchingScore = matchingScore
17
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
22
23 member this.AddMatchingScore(score: float) =
24 matchingScore <- matchingScore + score
25
26 interface KdTree.I2DCoords with
27 member this.X = e.Cx
28 member this.Y = e.Cy
29
30 type MatchingEllipses (radiusMin: float) =
31 let ellipses = List<EllipseScore>()
32
33 member this.Add (e: Ellipse) =
34 ellipses.Add(EllipseScore(0.0, e))
35
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)
39
40 // 2) Compute the matching score of each ellipses.
41 let windowSize = radiusMin
42 for e in ellipses do
43 e.Processed <- true
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
51 then
52 let areaOther = other.Ellipse.Area
53 match EEOver.EEOverlapArea e.Ellipse other.Ellipse with
54 | Some (commonArea, _, _) ->
55 let matchingScore = 2.0 * commonArea / (areaE + areaOther)
56 if matchingScore >= matchingScoreThreshold1
57 then
58 other.AddMatchingScore(matchingScore)
59 e.AddMatchingScore(matchingScore)
60 | _ -> ()
61
62 // 3) Sort ellipses by their score.
63 ellipses.Sort(fun e1 e2 -> e2.MatchingScore.CompareTo(e1.MatchingScore))
64
65 // 4) Remove ellipses wich have a low score.
66 let i = ellipses.BinarySearch(EllipseScore(matchingScoreThreshold2, Ellipse(0.0, 0.0, 0.0, 0.0, 0.0)),
67 { new IComparer<EllipseScore> with
68 member this.Compare(e1, e2) = e2.MatchingScore.CompareTo(e1.MatchingScore) }) |> abs
69 let nbToRemove = ellipses.Count - i
70 if nbToRemove > 0
71 then
72 for j in i .. nbToRemove - 1 do
73 ellipses.[j].Removed <- true
74 ellipses.RemoveRange(i, nbToRemove)
75
76 // 5) Remove ellipses whose center is into an ellipse with a better score
77 for e in ellipses do
78 if not e.Removed
79 then
80 let window = { KdTree.minX = e.Ellipse.Cx - e.Ellipse.A
81 KdTree.maxX = e.Ellipse.Cx + e.Ellipse.A
82 KdTree.minY = e.Ellipse.Cy - e.Ellipse.A
83 KdTree.maxY = e.Ellipse.Cy + e.Ellipse.A }
84 for other in KdTree.Tree.search tree window do
85 if not other.Removed && other.MatchingScore < e.MatchingScore
86 then
87 if e.Ellipse.Contains other.Ellipse.Cx other.Ellipse.Cy
88 then
89 other.Removed <- true
90 ellipses.RemoveAll(fun e -> e.Removed) |> ignore
91
92 List.ofSeq ellipses |> List.map (fun e -> e.Ellipse)
93
94
95
96
97