let h = img.Height
     for i in 1 .. h - 2 do
         for j in 1 .. w - 2 do
-            if img.[i, j] > 0uy && img.Data.[i + 1, j] > 0uy && (img.Data.[i, j - 1] > 0uy && img.Data.[i - 1, j + 1] = 0uy || img.Data.[i, j + 1] > 0uy && img.Data.[i - 1, j - 1] = 0uy) then
+            if img.[i, j] > 0uy && img.Data.[i + 1, j] > 0uy && (img.Data.[i, j - 1] > 0uy && img.Data.[i - 1, j + 1] = 0uy || img.Data.[i, j + 1] > 0uy && img.Data.[i - 1, j - 1] = 0uy)
+            then
                 img.[i, j] <- 0uy
     for i in 1 .. h - 2 do
         for j in 1 .. w - 2 do
-            if img.[i, j] > 0uy && img.Data.[i - 1, j] > 0uy && (img.Data.[i, j - 1] > 0uy && img.Data.[i + 1, j + 1] = 0uy || img.Data.[i, j + 1] > 0uy && img.Data.[i + 1, j - 1] = 0uy) then
+            if img.[i, j] > 0uy && img.Data.[i - 1, j] > 0uy && (img.Data.[i, j - 1] > 0uy && img.Data.[i + 1, j + 1] = 0uy || img.Data.[i, j + 1] > 0uy && img.Data.[i + 1, j - 1] = 0uy)
+            then
                 img.[i, j] <- 0uy
 
 let findEdges (img: Image<Gray, float32>) : Matrix<byte> * Image<Gray, float> * Image<Gray, float> =
                 else magnitudes.Data.[i - sign, j + sign]
 
             let m = magnitudes.Data.[i, j]
-            if m < mNeigbors 1 || m < mNeigbors -1 || m < thresholdLow then
+            if m < mNeigbors 1 || m < mNeigbors -1 || m < thresholdLow
+            then
                 nms.Data.[i, j] <- 0uy
 
     // suppressMConnections nms // It's not usefull for the rest of the process (ellipse detection).
     let toVisit = Stack<Point>()
     for i in 0 .. h - 1 do
         for j in 0 .. w - 1 do
-            if nms.Data.[i, j] = 1uy && magnitudes.Data.[i, j] >= thresholdHigh then
+            if nms.Data.[i, j] = 1uy && magnitudes.Data.[i, j] >= thresholdHigh
+            then
                 nms.Data.[i, j] <- 0uy
                 toVisit.Push(Point(j, i))
                 while toVisit.Count > 0 do
                     edges.Data.[p.Y, p.X] <- 1uy
                     for i' in -1 .. 1  do
                         for j' in -1 .. 1 do
-                            if i' <> 0 || j' <> 0 then
+                            if i' <> 0 || j' <> 0
+                            then
                                 let ni = p.Y + i'
                                 let nj = p.X + j'
-                                if ni >= 0 && ni < h && nj >= 0 && nj < w && nms.Data.[ni, nj] = 1uy then
+                                if ni >= 0 && ni < h && nj >= 0 && nj < w && nms.Data.[ni, nj] = 1uy
+                                then
                                     nms.Data.[ni, nj] <- 0uy
                                     toVisit.Push(Point(nj, ni))
 
         data2 <- tmp
 
 
-// FIXME: replace by a queue or stack.
-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) =
         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))
+                let neighborhood = List<Point>()
+                let neighborsToCheck = Stack<Point>()
+                neighborsToCheck.Push(Point(j, i))
                 data'.[i, j] <- 0uy
 
                 while neighborsToCheck.Count > 0 do
-                    let (ci, cj) = pop neighborsToCheck
-                    neighborhood.Add((ci, cj))
+                    let n = neighborsToCheck.Pop()
+                    neighborhood.Add(n)
                     for (ni, nj) in neighbors do
-                        let pi = ci + ni
-                        let pj = cj + nj
+                        let pi = n.Y + ni
+                        let pj = n.X + nj
                         if pi >= 0 && pi < h && pj >= 0 && pj < w && data'.[pi, pj] = 1uy
                         then
-                            neighborsToCheck.Add((pi, pj))
+                            neighborsToCheck.Push(Point(pj, pi))
                             data'.[pi, pj] <- 0uy
                 if neighborhood.Count <= areaSize
                 then
-                    for (ni, nj) in neighborhood do
-                        data.[ni, nj] <- 0uy
+                    for n in neighborhood do
+                        data.[n.Y, n.X] <- 0uy
 
 let connectedComponents (img: Image<Gray, byte>) (startPoints: List<Point>) : List<Point> =
     let w = img.Width
     let h = img.Height
 
     let pointChecked = Points()
-    let pointToCheck = List<Point>(startPoints);
+    let pointToCheck = Stack<Point>(startPoints);
 
     let data = img.Data
 
     while pointToCheck.Count > 0 do
-        let next = pop pointToCheck
+        let next = pointToCheck.Pop()
         pointChecked.Add(next) |> ignore
         for ny in -1 .. 1 do
             for nx in -1 .. 1 do
                     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)
+                        pointToCheck.Push(p)
 
     List<Point>(pointChecked)
 
 
--- /dev/null
+module KMeans
+
+open System.Collections.Generic
+open System.Drawing
+
+open Emgu.CV
+open Emgu.CV.Structure
+
+type Result = {
+    fg: Image<Gray, byte>
+    mean_bg: float
+    mean_fg: float
+    d_fg: Image<Gray, float32> } // Euclidean distances of the foreground to mean_fg.
+
+let kmeans (img: Image<Gray, float32>) (fgFactor: float) : Result =
+    let nbIteration = 3
+    let w = img.Width
+    let h = img.Height
+
+    let min = ref [| 0.0 |]
+    let minLocation = ref <| [| Point() |]
+    let max = ref [| 0.0 |]
+    let maxLocation = ref <| [| Point() |]
+    img.MinMax(min, max, minLocation, maxLocation)
+
+    let mutable mean_bg = (!max).[0] - ((!max).[0] - (!min).[0]) / 4.0
+    let mutable mean_fg = (!min).[0] + ((!max).[0] - (!min).[0]) / 4.0
+    use mutable d_bg = new Image<Gray, float32>(img.Size)
+    let mutable d_fg = new Image<Gray, float32>(img.Size)
+    let mutable fg = new Image<Gray, byte>(img.Size)
+
+    for i in 1 .. nbIteration do
+        d_bg <- img.AbsDiff(Gray(mean_bg))
+        d_fg <- img.AbsDiff(Gray(mean_fg))
+
+        CvInvoke.Compare(d_fg, d_bg, fg, CvEnum.CmpType.LessThan)
+
+        let mutable bg_total = 0.0
+        let mutable bg_nb = 0
+
+        let mutable fg_total = 0.0
+        let mutable fg_nb = 0
+
+        for i in 0 .. h - 1 do
+            for j in 0 .. w - 1 do
+                if fg.Data.[i, j, 0] > 0uy
+                then
+                    fg_total <- fg_total + float img.Data.[i, j, 0]
+                    fg_nb <- fg_nb + 1
+                else
+                    bg_total <- bg_total + float img.Data.[i, j, 0]
+                    bg_nb <- bg_nb + 1
+
+        mean_bg <- bg_total / float bg_nb
+        mean_fg <- fg_total / float fg_nb
+
+    { fg = fg; mean_bg = mean_bg; mean_fg = mean_fg; d_fg = d_fg }
\ No newline at end of file
 
     ImgTools.areaClose filteredGreenWithoutStain (int config.StainArea)
 
     // We use the filtered image to find the dark stain.
-    let kmediansResults = logTime "Finding fg/bg (k-medians)" (fun () -> KMedians.kmedians (filteredGreenWithoutInfection.Convert<Gray, float32>()) 1.0) // FIXME: avoid converting again this in MainAnalysis
-    let { KMedians.fg = fg; KMedians.median_bg = median_bg; KMedians.median_fg = median_fg; KMedians.d_fg = d_fg } = kmediansResults
-    let darkStain = d_fg.Cmp(median_bg * config.Parameters.darkStainLevel, CvEnum.CmpType.GreaterThan)
-    darkStain._And(filteredGreenWithoutInfection.Cmp(median_fg, CvEnum.CmpType.LessThan))
+
+    // With K-Means.
+    let kmeansResults = logTime "Finding fg/bg (k-means)" (fun () -> KMeans.kmeans (filteredGreenWithoutInfection.Convert<Gray, float32>()) 1.0)
+    let { KMeans.mean_bg = value_bg; KMeans.mean_fg = value_fg; KMeans.d_fg = d_fg } = kmeansResults
+
+    // With K-Medians.
+    (* let kmediansResults = logTime "Finding fg/bg (k-medians)" (fun () -> KMedians.kmedians (filteredGreenWithoutInfection.Convert<Gray, float32>()) 1.0) // FIXME: avoid converting this again in MainAnalysis
+    let { KMedians.median_bg = value_bg; KMedians.median_fg = value_fg; KMedians.d_fg = d_fg } = kmediansResults *)
+
+    let darkStain = d_fg.Cmp(value_bg * config.Parameters.darkStainLevel, CvEnum.CmpType.GreaterThan)
+    darkStain._And(filteredGreenWithoutInfection.Cmp(value_fg, CvEnum.CmpType.LessThan))
 
     let marker (img: Image<Gray, byte>) (closed: Image<Gray, byte>) (level: float) : Image<Gray, byte> =
         let diff = closed - (img * level)