dfd2593b132bc7ca82762733581095d34ad712e9
[master-thesis.git] / Parasitemia / ParasitemiaCore / KMeans.fs
1 module ParasitemiaCore.KMeans
2
3 open System.Collections.Generic
4 open System.Drawing
5
6 open Emgu.CV
7 open Emgu.CV.Structure
8
9 type Result =
10 {
11 fg : Image<Gray, byte>
12 mean_bg : float32
13 mean_fg : float32
14 d_fg : Image<Gray, float32> // Euclidean distances of the foreground to mean_fg.
15 }
16
17 let kmeans (img : Image<Gray, float32>) : Result =
18 let nbIteration = 4
19 let w = img.Width
20 let h = img.Height
21
22 let min = ref [| 0.0 |]
23 let minLocation = ref <| [| Point() |]
24 let max = ref [| 0.0 |]
25 let maxLocation = ref <| [| Point() |]
26 img.MinMax(min, max, minLocation, maxLocation)
27
28 let minf = float32 (!min).[0]
29 let maxf = float32 (!max).[0]
30
31 let mutable mean_bg = maxf - (maxf - minf) / 4.f
32 let mutable mean_fg = minf + (maxf - minf) / 4.f
33 use mutable d_bg : Image<Gray, float32> = null
34 let mutable d_fg : Image<Gray, float32> = null
35 let fg = new Image<Gray, byte>(img.Size)
36
37 let imgData = img.Data
38 let fgData = fg.Data
39
40 for i = 1 to nbIteration do
41 match d_bg with
42 | null -> ()
43 | _ ->
44 d_bg.Dispose()
45 d_fg.Dispose()
46
47 // EmGu doesn't import the in-place version of 'AbsDiff' so we have to create two images for each iteration.
48 d_bg <- img.AbsDiff(Gray(float mean_bg))
49 d_fg <- img.AbsDiff(Gray(float mean_fg))
50
51 CvInvoke.Compare(d_fg, d_bg, fg, CvEnum.CmpType.LessThan)
52
53 let mutable bg_total = 0.f
54 let mutable bg_nb = 0
55
56 let mutable fg_total = 0.f
57 let mutable fg_nb = 0
58
59 for i = 0 to h - 1 do
60 for j = 0 to w - 1 do
61 if fgData.[i, j, 0] > 0uy then
62 fg_total <- fg_total + imgData.[i, j, 0]
63 fg_nb <- fg_nb + 1
64 else
65 bg_total <- bg_total + imgData.[i, j, 0]
66 bg_nb <- bg_nb + 1
67
68 mean_bg <- bg_total / float32 bg_nb
69 mean_fg <- fg_total / float32 fg_nb
70
71 { fg = fg; mean_bg = mean_bg; mean_fg = mean_fg; d_fg = d_fg }