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