527831383b9a7c1896ade3ae0e26568c2f12ffc4
[master-thesis.git] / Parasitemia / Parasitemia / ImgTools.fs
1 module ImgTools
2
3 open System
4 open System.Drawing
5 open System.Collections.Generic
6
7 open Emgu.CV
8 open Emgu.CV.Structure
9
10 open Utils
11
12 // Normalize image values between 0uy and 255uy.
13 let normalizeAndConvert (img: Image<Gray, float32>) : Image<Gray, byte> =
14 let min = ref [| 0.0 |]
15 let minLocation = ref <| [| Point() |]
16 let max = ref [| 0.0 |]
17 let maxLocation = ref <| [| Point() |]
18 img.MinMax(min, max, minLocation, maxLocation)
19 ((img - (!min).[0]) / ((!max).[0] - (!min).[0]) * 255.0).Convert<Gray, byte>()
20
21 let gaussianFilter (img : Image<'TColor, 'TDepth>) (standardDeviation : float) : Image<'TColor, 'TDepth> =
22 let size = 2 * int (ceil (4.0 * standardDeviation)) + 1
23 img.SmoothGaussian(size, size, standardDeviation, standardDeviation)
24
25 // Zhang and Suen algorithm.
26 // Modify 'mat' in place.
27 let thin (mat: Matrix<byte>) =
28 let neighbors = [|
29 (-1, 0) // p2
30 (-1, 1) // p3
31 ( 0, 1) // p4
32 ( 1, 1) // p5
33 ( 1, 0) // p6
34 ( 1, -1) // p7
35 ( 0, -1) // p8
36 (-1, -1) |] // p9
37
38 let w = mat.Width
39 let h = mat.Height
40 let mutable data1 = mat.Data
41 let mutable data2 = Array2D.zeroCreate<byte> h w
42
43 // Return the list of neighbor values.
44 let neighborsValues (p1i, p1j) =
45 Array.map (fun (ni, nj) ->
46 let pi = p1i + ni
47 let pj = p1j + nj
48 if pi < 0 || pi >= h || pj < 0 || pj >= w then 0uy else data1.[pi, pj]
49 ) neighbors
50
51 // Return the number of 01 pattern in 'values' in a circular way.
52 let pattern01 (values: byte[]) =
53 let mutable nb = 0
54 let mutable lastValue = 255uy
55 for v in values do
56 if lastValue = 0uy && v = 1uy
57 then
58 nb <- nb + 1
59 lastValue <- v
60 if lastValue = 0uy && values.[0] = 1uy
61 then
62 nb <- nb + 1
63 nb
64
65 let mutable pixelChanged = true
66 let mutable oddIteration = true
67 while pixelChanged do
68 pixelChanged <- false
69 for i in 0..h-1 do
70 for j in 0..w-1 do
71 if data1.[i, j] = 1uy
72 then
73 let values = neighborsValues (i, j)
74 let s = Array.reduce (+) values
75 if s >= 2uy && s <= 6uy &&
76 pattern01 values = 1 &&
77 (not oddIteration || (values.[0] * values.[2] * values.[4] = 0uy && values.[2] * values.[4] * values.[6] = 0uy)) && // Odd iteration.
78 (oddIteration || (values.[0] * values.[2] * values.[6] = 0uy && values.[0] * values.[4] * values.[6] = 0uy)) // Even iterations.
79 then
80 data2.[i, j] <- 0uy
81 pixelChanged <- true
82 else
83 data2.[i, j] <- 1uy
84 else
85 data2.[i, j] <- 0uy
86
87 oddIteration <- not oddIteration
88 let tmp = data1
89 data1 <- data2
90 data2 <- tmp
91
92
93 // Remove all 8-connected pixels with an area equal or greater than 'areaSize'.
94 // Modify 'mat' in place.
95 let removeArea (mat: Matrix<byte>) (areaSize: int) =
96 let neighbors = [|
97 (-1, 0) // p2
98 (-1, 1) // p3
99 ( 0, 1) // p4
100 ( 1, 1) // p5
101 ( 1, 0) // p6
102 ( 1, -1) // p7
103 ( 0, -1) // p8
104 (-1, -1) |] // p9
105
106 let mat' = new Matrix<byte>(mat.Size)
107 let w = mat'.Width
108 let h = mat'.Height
109 mat.CopyTo(mat')
110
111 let data = mat.Data
112 let data' = mat'.Data
113
114 for i in 0..h-1 do
115 for j in 0..w-1 do
116 if data'.[i, j] = 1uy
117 then
118 let neighborhood = List<(int*int)>()
119 let neighborsToCheck = List<(int*int)>()
120 neighborsToCheck.Add((i, j))
121 data'.[i, j] <- 0uy
122
123 let pop (l: List<'a>) : 'a =
124 let n = l.[l.Count - 1]
125 l.RemoveAt(l.Count - 1)
126 n
127
128 while neighborsToCheck.Count > 0 do
129 let (ci, cj) = pop neighborsToCheck
130 neighborhood.Add((ci, cj))
131 for (ni, nj) in neighbors do
132 let pi = ci + ni
133 let pj = cj + nj
134 if pi >= 0 && pi < h && pj >= 0 && pj < w && data'.[pi, pj] = 1uy
135 then
136 neighborsToCheck.Add((pi, pj))
137 data'.[pi, pj] <- 0uy
138 if neighborhood.Count <= areaSize
139 then
140 for (ni, nj) in neighborhood do
141 data.[ni, nj] <- 0uy
142
143
144 let saveImg (img: Image<'TColor, 'TDepth>) (name: string) =
145 img.Save("output/" + name)
146
147
148 let saveMat (mat: Matrix<'TDepth>) (name: string) =
149 use img = new Image<Gray, 'TDeph>(mat.Size)
150 mat.CopyTo(img)
151 saveImg img name
152
153 (*let drawEllipse (img: Image<'TColor, 'TDepth>) (e: Types.Ellipse) (color: 'TColor) =
154 let e' = Ellipse(PointF(float32 e.cx, float32 e.cy), SizeF(2.0f * float32 e.a, 2.0f * float32 e.b), float32 e.alpha)
155 img.Draw(e', color)*)
156
157 let drawLine (img: Image<'TColor, 'TDepth>) (color: 'TColor) (x0: float) (y0: float) (x1: float) (y1: float) =
158 let x0, y0, x1, y1 = roundInt(x0), roundInt(y0), roundInt(x1), roundInt(y1)
159
160 img.Draw(LineSegment2D(Point(x0, y0), Point(x1, y1)), color, 1);
161
162 let drawEllipse (img: Image<'TColor, 'TDepth>) (e: Types.Ellipse) (color: 'TColor) =
163 let cosAlpha = cos e.Alpha
164 let sinAlpha = sin e.Alpha
165
166 let mutable x0 = 0.0
167 let mutable y0 = 0.0
168 let mutable first_iteration = true
169
170 let n = 40
171 let thetaIncrement = 2.0 * Math.PI / (float n)
172
173 for theta in 0.0 .. thetaIncrement .. 2.0 * Math.PI do
174 let cosTheta = cos theta
175 let sinTheta = sin theta
176 let x = e.Cx + cosAlpha * e.A * cosTheta - sinAlpha * e.B * sinTheta
177 let y = e.Cy + sinAlpha * e.A * cosTheta + cosAlpha * e.B * sinTheta
178
179 if not first_iteration
180 then
181 drawLine img color x0 y0 x y
182 else
183 first_iteration <- false
184
185 x0 <- x
186 y0 <- y
187
188 let drawEllipses (img: Image<'TColor, 'TDepth>) (ellipses: Types.Ellipse list) (color: 'TColor) =
189 List.iter (fun e -> drawEllipse img e color) ellipses