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