afc4ab7b10c0cb4954c2206cf07238ae905ab1a8
[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 let commonArea = EEOver.EEOverlapArea e.Ellipse other.Ellipse
54 let matchingScore = 2.0 * commonArea / (areaE + areaOther)
55 if matchingScore >= matchingScoreThreshold1
56 then
57 other.AddMatchingScore(matchingScore)
58 e.AddMatchingScore(matchingScore)
59
60 // 3) Sort ellipses by their score.
61 ellipses.Sort(fun e1 e2 -> e2.MatchingScore.CompareTo(e1.MatchingScore))
62
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
68 if nbToRemove > 0
69 then
70 for j in i .. nbToRemove - 1 do
71 ellipses.[j].Removed <- true
72 ellipses.RemoveRange(i, nbToRemove)
73
74 // 5) Remove ellipses whose center is into an ellipse with a better score
75 for e in ellipses do
76 if not e.Removed
77 then
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
84 then
85 if e.Ellipse.Contains other.Ellipse.Cx other.Ellipse.Cy
86 then
87 other.Removed <- true
88 ellipses.RemoveAll(fun e -> e.Removed) |> ignore
89
90 dprintfn "Number of ellipse: %A" ellipses.Count
91
92 List.ofSeq ellipses |> List.map (fun e -> e.Ellipse)
93
94
95
96
97