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
>) =
40 let mutable data1 = mat
.Data
41 let mutable data2 = Array2D.zeroCreate
<byte
> h w
43 // Return the list of neighbor values.
44 let neighborsValues (p1i
, p1j
) =
45 Array.map
(fun (ni
, nj
) ->
48 if pi < 0 || pi >= h || pj < 0 || pj >= w then 0uy else data1.[pi, pj]
51 // Return the number of 01 pattern in 'values' in a circular way.
52 let pattern01 (values
: byte
[]) =
54 let mutable lastValue = 255uy
56 if lastValue = 0uy && v
= 1uy
60 if lastValue = 0uy && values
.[0] = 1uy
65 let mutable pixelChanged = true
66 let mutable oddIteration = true
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.
87 oddIteration <- not
oddIteration
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) =
106 let mat' = new Matrix<byte>(mat.Size)
112 let data' = mat'.Data
116 if data'.[i, j] = 1uy
118 let neighborhood = List<(int*int)>()
119 let neighborsToCheck = List<(int*int)>()
120 neighborsToCheck.Add((i, j))
123 let pop (l
: List<'a>) : 'a
=
124 let n = l
.[l
.Count - 1]
125 l
.RemoveAt(l
.Count - 1)
128 while neighborsToCheck.Count > 0 do
129 let (ci
, cj
) = pop neighborsToCheck
130 neighborhood.Add((ci
, cj
))
131 for (ni
, nj
) in neighbors do
134 if pi >= 0 && pi < h && pj >= 0 && pj < w && data'.[pi, pj] = 1uy
136 neighborsToCheck.Add((pi, pj))
137 data'.[pi, pj] <- 0uy
138 if neighborhood.Count <= areaSize
140 for (ni
, nj
) in neighborhood do
144 let saveImg (img
: Image<'TColor, 'TDepth>) (name
: string) =
145 img
.Save("output/" + name
)
148 let saveMat (mat: Matrix<'TDepth>) (name: string) =
149 use img = new Image<Gray, 'TDeph>(mat.Size)
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)*)
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)
160 img.Draw(LineSegment2D(Point(x0, y0), Point(x1, y1)), color, 1);
162 let drawEllipse (img: Image<'TColor, 'TDepth>) (e: Types.Ellipse) (color: 'TColor) =
163 let cosAlpha = cos
e.Alpha
164 let sinAlpha = sin
e.Alpha
168 let mutable first_iteration = true
171 let thetaIncrement = 2.0 * Math.PI / (float n)
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
179 if not
first_iteration
181 drawLine img color
x0 y0 x y
183 first_iteration <- false
188 let drawEllipses (img: Image<'TColor, 'TDepth>) (ellipses
: Types.Ellipse list) (color
: 'TColor) =
189 List.iter (fun e -> drawEllipse img e color) ellipses