The main process is now complete.
[master-thesis.git] / Parasitemia / Parasitemia / ImgTools.fs
index 5278313..c34b9c7 100644 (file)
@@ -10,7 +10,7 @@ open Emgu.CV.Structure
 open Utils
 
 // Normalize image values between 0uy and 255uy.
-let normalizeAndConvert (img: Image<Gray, float32>) : Image<Gray, byte> = 
+let normalizeAndConvert (img: Image<Gray, float32>) : Image<Gray, byte> =
     let min = ref [| 0.0 |]
     let minLocation = ref <| [| Point() |]
     let max = ref [| 0.0 |]
@@ -22,10 +22,10 @@ let gaussianFilter (img : Image<'TColor, 'TDepth>) (standardDeviation : float) :
     let size = 2 * int (ceil (4.0 * standardDeviation)) + 1
     img.SmoothGaussian(size, size, standardDeviation, standardDeviation)
 
-// Zhang and Suen algorithm. 
+// Zhang and Suen algorithm.
 // Modify 'mat' in place.
-let thin (mat: Matrix<byte>) =    
-    let neighbors = [| 
+let thin (mat: Matrix<byte>) =
+    let neighbors = [|
         (-1,  0) // p2
         (-1,  1) // p3
         ( 0,  1) // p4
@@ -41,15 +41,15 @@ let thin (mat: Matrix<byte>) =
     let mutable data2 = Array2D.zeroCreate<byte> h w
 
     // Return the list of neighbor values.
-    let neighborsValues (p1i, p1j) = 
-        Array.map (fun (ni, nj) -> 
+    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 pattern01 (values: byte[]) =
         let mutable nb = 0
         let mutable lastValue = 255uy
         for v in values do
@@ -61,7 +61,7 @@ let thin (mat: Matrix<byte>) =
         then
             nb <- nb + 1
         nb
-         
+
     let mutable pixelChanged = true
     let mutable oddIteration = true
     while pixelChanged do
@@ -84,16 +84,22 @@ let thin (mat: Matrix<byte>) =
                 else
                     data2.[i, j] <- 0uy
 
-        oddIteration <- not oddIteration                  
+        oddIteration <- not oddIteration
         let tmp = data1
         data1 <- data2
         data2 <- tmp
-        
+
+
+
+let pop (l: List<'a>) : 'a =
+    let n = l.[l.Count - 1]
+    l.RemoveAt(l.Count - 1)
+    n
 
 // 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 = [| 
+    let neighbors = [|
         (-1,  0) // p2
         (-1,  1) // p3
         ( 0,  1) // p4
@@ -102,29 +108,24 @@ let removeArea (mat: Matrix<byte>) (areaSize: int) =
         ( 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')   
-     
+    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 
+            if data'.[i, j] = 1uy
             then
                 let neighborhood = List<(int*int)>()
                 let neighborsToCheck = List<(int*int)>()
-                neighborsToCheck.Add((i, j))          
+                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))
@@ -140,36 +141,61 @@ let removeArea (mat: Matrix<byte>) (areaSize: int) =
                     for (ni, nj) in neighborhood do
                         data.[ni, nj] <- 0uy
 
+let connectedComponents (img: Image<Gray, byte>) (startPoints: List<Point>) : List<Point> =
+    let w = img.Width
+    let h = img.Height
+
+    let pointChecked = HashSet<Point>()
+    let pointToCheck = List<Point>(startPoints);
+
+    let data = img.Data
+
+    while pointToCheck.Count > 0 do
+        let next = pop pointToCheck
+        pointChecked.Add(next) |> ignore
+        for ny in -1 .. 1 do
+            for nx in -1 .. 1 do
+                if ny <> 0 && nx <> 0
+                then
+                    let p = Point(next.X + nx, next.Y + ny)
+                    if p.X >= 0 && p.X < w && p.Y >= 0 && p.Y < h && data.[p.Y, p.X, 0] > 0uy && not (pointChecked.Contains p)
+                    then
+                        pointToCheck.Add(p)
+
+    List<Point>(pointChecked)
+
 
-let saveImg (img: Image<'TColor, 'TDepth>) (name: string) = 
-    img.Save("output/" + name)
-    
+let saveImg (img: Image<'TColor, 'TDepth>) (filepath: string) =
+    img.Save(filepath)
 
-let saveMat (mat: Matrix<'TDepth>) (name: string) = 
+
+let saveMat (mat: Matrix<'TDepth>) (filepath: string) =
     use img = new Image<Gray, 'TDeph>(mat.Size)
     mat.CopyTo(img)
-    saveImg img name
-    
+    saveImg img filepath
+
 (*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)
-
+let drawLine (img: Image<'TColor, 'TDepth>) (color: 'TColor) (x0: int) (y0: int) (x1: int) (y1: int) =
     img.Draw(LineSegment2D(Point(x0, y0), Point(x1, y1)), color, 1);
 
-let drawEllipse (img: Image<'TColor, 'TDepth>) (e: Types.Ellipse) (color: 'TColor) =    
+let drawLineF (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)
+    drawLine img color x0 y0 x1 y1
+
+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
@@ -178,7 +204,7 @@ let drawEllipse (img: Image<'TColor, 'TDepth>) (e: Types.Ellipse) (color: 'TColo
 
         if not first_iteration
         then
-            drawLine img color x0 y0 x y
+            drawLineF img color x0 y0 x y
         else
             first_iteration <- false
 
@@ -186,4 +212,36 @@ let drawEllipse (img: Image<'TColor, 'TDepth>) (e: Types.Ellipse) (color: 'TColo
         y0 <- y
 
 let drawEllipses (img: Image<'TColor, 'TDepth>) (ellipses: Types.Ellipse list) (color: 'TColor) =
-    List.iter (fun e -> drawEllipse img e color) ellipses
\ No newline at end of file
+    List.iter (fun e -> drawEllipse img e color) ellipses
+
+
+let rngCell =  System.Random()
+let drawCell (img: Image<Bgr, byte>) (drawCellContent: bool) (c: Types.Cell) =
+    if drawCellContent
+    then
+        let colorB = rngCell.Next(20, 70)
+        let colorG = rngCell.Next(20, 70)
+        let colorR = rngCell.Next(20, 70)
+
+        for y in 0 .. c.elements.Height - 1 do
+            for x in 0 .. c.elements.Width - 1 do
+                if c.elements.[y, x] > 0uy
+                then
+                    let dx, dy = c.center.X - c.elements.Width / 2, c.center.Y - c.elements.Height / 2
+                    let b = img.Data.[y + dy, x + dx, 0] |> int
+                    let g = img.Data.[y + dy, x + dx, 1] |> int
+                    let r = img.Data.[y + dy, x + dx, 2] |> int
+                    img.Data.[y + dy, x + dx, 0] <- if b + colorB > 255 then 255uy else byte (b + colorB)
+                    img.Data.[y + dy, x + dx, 1] <- if g + colorG > 255 then 255uy else byte (g + colorG)
+                    img.Data.[y + dy, x + dx, 2] <- if r + colorR > 255 then 255uy else byte (r + colorR)
+
+    let crossColor = match c.cellClass with
+                     | Types.HealthyRBC -> Bgr(255.0, 0.0, 0.0)
+                     | Types.InfectedRBC -> Bgr(0.0, 0.0, 255.0)
+                     | Types.Peculiar -> Bgr(0.0, 0.0, 0.0)
+
+    drawLine img crossColor (c.center.X - 3) c.center.Y (c.center.X + 3) c.center.Y
+    drawLine img crossColor c.center.X (c.center.Y - 3) c.center.X (c.center.Y + 3)
+
+let drawCells (img: Image<Bgr, byte>) (drawCellContent: bool) (cells: Types.Cell list) =
+    List.iter (fun c -> drawCell img drawCellContent c) cells
\ No newline at end of file