First commit of the f# source code.
[master-thesis.git] / Parasitemia / Parasitemia / ImgTools.fs
diff --git a/Parasitemia/Parasitemia/ImgTools.fs b/Parasitemia/Parasitemia/ImgTools.fs
new file mode 100644 (file)
index 0000000..cc09405
--- /dev/null
@@ -0,0 +1,177 @@
+module ImgTools
+
+open System
+open System.Drawing
+open System.Collections.Generic
+
+open Emgu.CV
+open Emgu.CV.Structure
+
+open Utils
+
+let gaussianFilter (img : Image<'TColor, 'TDepth>) (standardDeviation : float) : Image<'TColor, 'TDepth> =
+    let size = 2 * int (ceil (4.0 * standardDeviation)) + 1
+    img.SmoothGaussian(size, size, standardDeviation, standardDeviation)
+
+// Zhang and Suen algorithm. 
+// Modify 'mat' in place.
+let thin (mat: Matrix<byte>) =    
+    let neighbors = [| 
+        (-1,  0) // p2
+        (-1,  1) // p3
+        ( 0,  1) // p4
+        ( 1,  1) // p5
+        ( 1,  0) // p6
+        ( 1, -1) // p7
+        ( 0, -1) // p8
+        (-1, -1) |] // p9
+
+    let w = mat.Width
+    let h = mat.Height
+    let mutable data1 = mat.Data
+    let mutable data2 = Array2D.zeroCreate<byte> h w
+
+    // Return the list of neighbor values.
+    let neighborsValues (p1i, p1j) = 
+        Array.map (fun (ni, nj) -> 
+            let pi = p1i + ni
+            let pj = p1j + nj
+            if pi < 0 || pi >= h || pj < 0 || pj >= w then 0uy else data1.[pi, pj]
+            ) neighbors
+
+    // Return the number of 01 pattern in 'values' in a circular way.
+    let pattern01 (values: byte[]) = 
+        let mutable nb = 0
+        let mutable lastValue = 255uy
+        for v in values do
+            if lastValue = 0uy && v = 1uy
+            then
+                nb <- nb + 1
+            lastValue <- v
+        if lastValue = 0uy && values.[0] = 1uy
+        then
+            nb <- nb + 1
+        nb
+         
+    let mutable pixelChanged = true
+    let mutable oddIteration = true
+    while pixelChanged do
+        pixelChanged <- false
+        for i in 0..h-1 do
+            for j in 0..w-1 do
+                if data1.[i, j] = 1uy
+                then
+                    let values = neighborsValues (i, j)
+                    let s = Array.reduce (+) values
+                    if s >= 2uy && s <= 6uy &&
+                        pattern01 values = 1 &&
+                        (not oddIteration || (values.[0] * values.[2] * values.[4] = 0uy && values.[2] * values.[4] * values.[6] = 0uy)) && // Odd iteration.
+                        (oddIteration || (values.[0] * values.[2] * values.[6] = 0uy && values.[0] * values.[4] * values.[6] = 0uy)) // Even iterations.
+                    then
+                        data2.[i, j] <- 0uy
+                        pixelChanged <- true
+                    else
+                        data2.[i, j] <- 1uy
+                else
+                    data2.[i, j] <- 0uy
+
+        oddIteration <- not oddIteration                  
+        let tmp = data1
+        data1 <- data2
+        data2 <- tmp
+        
+
+// Remove all 8-connected pixels with an area equal or greater than 'areaSize'.
+// Modify 'mat' in place.
+let removeArea (mat: Matrix<byte>) (areaSize: int) =
+    let neighbors = [| 
+        (-1,  0) // p2
+        (-1,  1) // p3
+        ( 0,  1) // p4
+        ( 1,  1) // p5
+        ( 1,  0) // p6
+        ( 1, -1) // p7
+        ( 0, -1) // p8
+        (-1, -1) |] // p9
+    
+    let mat' = new Matrix<byte>(mat.Size)
+    let w = mat'.Width
+    let h = mat'.Height
+    mat.CopyTo(mat')   
+     
+    let data = mat.Data
+    let data' = mat'.Data
+
+    for i in 0..h-1 do
+        for j in 0..w-1 do
+            if data'.[i, j] = 1uy 
+            then
+                let neighborhood = List<(int*int)>()
+                let neighborsToCheck = List<(int*int)>()
+                neighborsToCheck.Add((i, j))          
+                data'.[i, j] <- 0uy
+
+                let pop (l: List<'a>) : 'a = 
+                    let n = l.[l.Count - 1]
+                    l.RemoveAt(l.Count - 1)
+                    n
+
+                while neighborsToCheck.Count > 0 do
+                    let (ci, cj) = pop neighborsToCheck
+                    neighborhood.Add((ci, cj))
+                    for (ni, nj) in neighbors do
+                        let pi = ci + ni
+                        let pj = cj + nj
+                        if pi >= 0 && pi < h && pj >= 0 && pj < w && data'.[pi, pj] = 1uy
+                        then
+                            neighborsToCheck.Add((pi, pj))
+                            data'.[pi, pj] <- 0uy
+                if neighborhood.Count <= areaSize
+                then
+                    for (ni, nj) in neighborhood do
+                        data.[ni, nj] <- 0uy
+
+
+let saveImg (img: Image<'TColor, 'TDepth>) (name: string) = 
+    img.Save("output/" + name)
+    
+
+let saveMat (mat: Matrix<'TDepth>) (name: string) = 
+    use img = new Image<Gray, 'TDeph>(mat.Size)
+    mat.CopyTo(img)
+    saveImg img name
+    
+(*let drawEllipse (img: Image<'TColor, 'TDepth>) (e: Types.Ellipse) (color: 'TColor) =
+    let e' = Ellipse(PointF(float32 e.cx, float32 e.cy), SizeF(2.0f * float32 e.a, 2.0f * float32 e.b), float32 e.alpha)
+    img.Draw(e', color)*)
+
+let drawLine (img: Image<'TColor, 'TDepth>) (color: 'TColor) (x0: float) (y0: float) (x1: float) (y1: float) =
+    let x0, y0, x1, y1 = roundInt(x0), roundInt(y0), roundInt(x1), roundInt(y1)
+
+    img.Draw(LineSegment2D(Point(x0, y0), Point(x1, y1)), color, 1);
+
+let drawEllipse (img: Image<'TColor, 'TDepth>) (e: Types.Ellipse) (color: 'TColor) =    
+    let cosAlpha = cos e.alpha
+    let sinAlpha = sin e.alpha
+        
+    let mutable x0 = 0.0
+    let mutable y0 = 0.0
+    let mutable first_iteration = true
+        
+    let n = 40
+    let thetaIncrement = 2.0 * Math.PI / (float n)
+        
+    for theta in 0.0 .. thetaIncrement .. 2.0 * Math.PI do
+        let cosTheta = cos theta
+        let sinTheta = sin theta
+        let x = e.cx + cosAlpha * e.a * cosTheta - sinAlpha * e.b * sinTheta
+        let y = e.cy + sinAlpha * e.a * cosTheta + cosAlpha * e.b * sinTheta
+
+        if not first_iteration
+        then
+            drawLine img color x0 y0 x y
+        else
+            first_iteration <- false
+
+        x0 <- x
+        y0 <- y
\ No newline at end of file