f7e5a4af45a969c27d5fe69abdcc5240ffb86d5b
5 open System.Collections.Generic
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
>()
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
)
25 // Zhang and Suen algorithm.
26 // Modify 'mat' in place.
27 let thin (mat
: Matrix<byte
>) =
30 let mutable data1 = mat
.Data
31 let mutable data2 = Array2D.copy
data1
33 let mutable pixelChanged = true
34 let mutable oddIteration = true
42 let p2 = if i
= 0 then 0uy else data1.[i
-1, j
]
43 let p3 = if i
= 0 || j = w-1 then 0uy else data1.[i
-1, j+1]
44 let p4 = if j = w-1 then 0uy else data1.[i
, j+1]
45 let p5 = if i
= h-1 || j = w-1 then 0uy else data1.[i
+1, j+1]
46 let p6 = if i
= h-1 then 0uy else data1.[i
+1, j]
47 let p7 = if i
= h-1 || j = 0 then 0uy else data1.[i
+1, j-1]
48 let p8 = if j = 0 then 0uy else data1.[i
, j-1]
49 let p9 = if i
= 0 || j = 0 then 0uy else data1.[i
-1, j-1]
51 let sumNeighbors = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9
52 if sumNeighbors >= 2uy && sumNeighbors <= 6uy &&
53 (if p2 = 0uy && p3 = 1uy then 1 else 0) +
54 (if p3 = 0uy && p4 = 1uy then 1 else 0) +
55 (if p4 = 0uy && p5 = 1uy then 1 else 0) +
56 (if p5 = 0uy && p6 = 1uy then 1 else 0) +
57 (if p6 = 0uy && p7 = 1uy then 1 else 0) +
58 (if p7 = 0uy && p8 = 1uy then 1 else 0) +
59 (if p8 = 0uy && p9 = 1uy then 1 else 0) +
60 (if p9 = 0uy && p2 = 1uy then 1 else 0) = 1 &&
62 then p2 * p4 * p6 = 0uy && p4 * p6 * p8 = 0uy
63 else p2 * p4 * p8 = 0uy && p2 * p6 * p8 = 0uy
70 oddIteration <- not
oddIteration
76 let pop (l
: List<'a>) : 'a
=
77 let n = l
.[l
.Count - 1]
78 l
.RemoveAt(l
.Count - 1)
81 // Remove all 8-connected pixels with an area equal or greater than 'areaSize'.
82 // Modify 'mat' in place.
83 let removeArea (mat
: Matrix<byte
>) (areaSize
: int) =
94 let mat' = new Matrix<byte>(mat.Size)
100 let data' = mat'.Data
104 if data'.[i, j] = 1uy
106 let neighborhood = List<(int*int)>()
107 let neighborsToCheck = List<(int*int)>()
108 neighborsToCheck.Add((i, j))
111 while neighborsToCheck.Count > 0 do
112 let (ci
, cj
) = pop neighborsToCheck
113 neighborhood.Add((ci
, cj
))
114 for (ni
, nj
) in neighbors do
117 if pi >= 0 && pi < h && pj >= 0 && pj < w && data'.[pi, pj] = 1uy
119 neighborsToCheck.Add((pi, pj))
120 data'.[pi, pj] <- 0uy
121 if neighborhood.Count <= areaSize
123 for (ni
, nj
) in neighborhood do
126 let connectedComponents (img
: Image<Gray, byte
>) (startPoints
: List<Point>) : List<Point> =
130 let pointChecked = HashSet<Point>()
131 let pointToCheck = List<Point>(startPoints
);
135 while pointToCheck.Count > 0 do
136 let next = pop pointToCheck
137 pointChecked.Add(next) |> ignore
140 if ny
<> 0 && nx
<> 0
142 let p = Point(next.X + nx
, next.Y + ny
)
143 if p.X >= 0 && p.X < w && p.Y >= 0 && p.Y < h && data.[p.Y, p.X, 0] > 0uy && not
(pointChecked.Contains p)
147 List<Point>(pointChecked)
150 let saveImg (img
: Image<'TColor, 'TDepth>) (filepath
: string) =
154 let saveMat (mat: Matrix<'TDepth>) (filepath: string) =
155 use img = new Image<Gray, 'TDeph>(mat.Size)
159 let drawLine (img: Image<'TColor, 'TDepth>) (color
: 'TColor) (x0: int) (y0: int) (x1: int) (y1: int) =
160 img.Draw(LineSegment2D(Point(x0, y0), Point(x1, y1)), color, 1);
162 let drawLineF (img: Image<'TColor, 'TDepth>) (color: 'TColor) (x0
: float) (y0
: float) (x1
: float) (y1
: float) =
163 let x0, y0
, x1
, y1
= roundInt
(x0), roundInt
(y0
), roundInt
(x1
), roundInt
(y1
)
164 drawLine img color
x0 y0 x1 y1
166 let drawEllipse (img: Image<'TColor, 'TDepth>) (e
: Types.Ellipse) (color
: 'TColor) =
167 let cosAlpha = cos e.Alpha
168 let sinAlpha = sin e.Alpha
172 let mutable first_iteration = true
175 let thetaIncrement = 2.0 * Math.PI / (float n)
177 for theta in 0.0 .. thetaIncrement .. 2.0 * Math.PI do
178 let cosTheta = cos theta
179 let sinTheta = sin theta
180 let x = e.Cx + cosAlpha * e.A * cosTheta - sinAlpha * e.B * sinTheta
181 let y = e.Cy + sinAlpha * e.A * cosTheta + cosAlpha * e.B * sinTheta
183 if not first_iteration
185 drawLineF img color x0 y0 x y
187 first_iteration <- false
192 let drawEllipses (img: Image<'TColor, 'TDepth>) (ellipses: Types.Ellipse list) (color: 'TColor) =
193 List.iter
(fun e -> drawEllipse img e color) ellipses
196 let rngCell = System.Random()
197 let drawCell (img: Image<Bgr, byte
>) (drawCellContent
: bool) (c
: Types.Cell) =
200 let colorB = rngCell.Next(20, 70)
201 let colorG = rngCell.Next(20, 70)
202 let colorR = rngCell.Next(20, 70)
204 for y in 0 .. c
.elements
.Height - 1 do
205 for x in 0 .. c
.elements
.Width - 1 do
206 if c
.elements
.[y, x] > 0uy
208 let dx, dy
= c
.center
.X - c
.elements
.Width / 2, c
.center
.Y - c
.elements
.Height / 2
209 let b = img.Data.[y + dy
, x + dx, 0] |> int
210 let g = img.Data.[y + dy
, x + dx, 1] |> int
211 let r = img.Data.[y + dy
, x + dx, 2] |> int
212 img.Data.[y + dy
, x + dx, 0] <- if b + colorB > 255 then 255uy else byte (b + colorB)
213 img.Data.[y + dy
, x + dx, 1] <- if g + colorG > 255 then 255uy else byte (g + colorG)
214 img.Data.[y + dy
, x + dx, 2] <- if r + colorR > 255 then 255uy else byte (r + colorR)
216 let crossColor = match c
.cellClass
with
217 | Types.HealthyRBC -> Bgr(255.0, 0.0, 0.0)
218 | Types.InfectedRBC -> Bgr(0.0, 0.0, 255.0)
219 | Types.Peculiar -> Bgr(0.0, 0.0, 0.0)
221 drawLine img crossColor (c
.center
.X - 3) c
.center
.Y (c
.center
.X + 3) c
.center
.Y
222 drawLine img crossColor c
.center
.X (c
.center
.Y - 3) c
.center
.X (c
.center
.Y + 3)
224 let drawCells (img: Image<Bgr, byte>) (drawCellContent
: bool) (cells
: Types.Cell list) =
225 List.iter
(fun c
-> drawCell img drawCellContent
c) cells