From: Greg Burri Date: Sat, 2 Jan 2016 20:42:40 +0000 (+0100) Subject: Use k-means instead of k-medians. X-Git-Tag: 1.0.11~68 X-Git-Url: http://git.euphorik.ch/?p=master-thesis.git;a=commitdiff_plain;h=dcf3645b3426991237567e90bab9806a9c111cd1 Use k-means instead of k-medians. --- diff --git a/Parasitemia/Parasitemia/Heap.fs b/Parasitemia/Parasitemia/Heap.fs index c2ab69f..39c6a4b 100644 --- a/Parasitemia/Parasitemia/Heap.fs +++ b/Parasitemia/Parasitemia/Heap.fs @@ -18,6 +18,7 @@ type Heap<'k, 'v when 'k : comparison> () = if r < a.Count && a.[r].key > a.[max].key then max <- r + if max <> i then let tmp = a.[i] diff --git a/Parasitemia/Parasitemia/ImgTools.fs b/Parasitemia/Parasitemia/ImgTools.fs index f567e68..5e32ccb 100644 --- a/Parasitemia/Parasitemia/ImgTools.fs +++ b/Parasitemia/Parasitemia/ImgTools.fs @@ -36,11 +36,13 @@ let suppressMConnections (img: Matrix) = 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) : Matrix * Image * Image = @@ -109,7 +111,8 @@ let findEdges (img: Image) : Matrix * Image * 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). @@ -120,7 +123,8 @@ let findEdges (img: Image) : Matrix * Image * let toVisit = Stack() 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 @@ -128,10 +132,12 @@ let findEdges (img: Image) : Matrix * Image * 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)) @@ -580,12 +586,6 @@ let thin (mat: Matrix) = 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) (areaSize: int) = @@ -611,37 +611,37 @@ let removeArea (mat: Matrix) (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() + let neighborsToCheck = Stack() + 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) (startPoints: List) : List = let w = img.Width let h = img.Height let pointChecked = Points() - let pointToCheck = List(startPoints); + let pointToCheck = Stack(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 @@ -650,7 +650,7 @@ let connectedComponents (img: Image) (startPoints: List) : Li 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(pointChecked) diff --git a/Parasitemia/Parasitemia/KMeans.fs b/Parasitemia/Parasitemia/KMeans.fs new file mode 100644 index 0000000..7c18120 --- /dev/null +++ b/Parasitemia/Parasitemia/KMeans.fs @@ -0,0 +1,57 @@ +module KMeans + +open System.Collections.Generic +open System.Drawing + +open Emgu.CV +open Emgu.CV.Structure + +type Result = { + fg: Image + mean_bg: float + mean_fg: float + d_fg: Image } // Euclidean distances of the foreground to mean_fg. + +let kmeans (img: Image) (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(img.Size) + let mutable d_fg = new Image(img.Size) + let mutable fg = new Image(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 diff --git a/Parasitemia/Parasitemia/MainAnalysis.fs b/Parasitemia/Parasitemia/MainAnalysis.fs index 6111f06..ff82b8b 100644 --- a/Parasitemia/Parasitemia/MainAnalysis.fs +++ b/Parasitemia/Parasitemia/MainAnalysis.fs @@ -47,6 +47,8 @@ let doAnalysis (img: Image) (name: string) (config: Config) : Cell li let filteredGreenWhitoutInfectionFloat = filteredGreenWhitoutInfection.Convert() let filteredGreenWhitoutStainFloat = filteredGreenWhitoutStain.Convert() + let canny = green.Canny(60., 40.) + (*let min = ref 0.0 let minLocation = ref <| Point() let max = ref 0.0 @@ -77,6 +79,8 @@ let doAnalysis (img: Image) (name: string) (config: Config) : Cell li let buildFileName postfix = System.IO.Path.Combine(dirPath, name + postfix) + saveImg canny (buildFileName " - canny.png") + saveMat (edges * 255.0) (buildFileName " - edges.png") saveImg parasites.darkStain (buildFileName " - parasites - dark stain.png") diff --git a/Parasitemia/Parasitemia/Parasitemia.fsproj b/Parasitemia/Parasitemia/Parasitemia.fsproj index 3282961..b4e3645 100644 --- a/Parasitemia/Parasitemia/Parasitemia.fsproj +++ b/Parasitemia/Parasitemia/Parasitemia.fsproj @@ -71,6 +71,7 @@ + diff --git a/Parasitemia/Parasitemia/ParasitesMarker.fs b/Parasitemia/Parasitemia/ParasitesMarker.fs index 20dbf4c..b50f7e9 100644 --- a/Parasitemia/Parasitemia/ParasitesMarker.fs +++ b/Parasitemia/Parasitemia/ParasitesMarker.fs @@ -59,10 +59,17 @@ let find (filteredGreen: Image) (filteredGreenFloat: Image KMedians.kmedians (filteredGreenWithoutInfection.Convert()) 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()) 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()) 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) (closed: Image) (level: float) : Image = let diff = closed - (img * level) diff --git a/Parasitemia/Parasitemia/Program.fs b/Parasitemia/Parasitemia/Program.fs index dafff56..b14e6bd 100644 --- a/Parasitemia/Parasitemia/Program.fs +++ b/Parasitemia/Parasitemia/Program.fs @@ -64,7 +64,7 @@ let main args = minRbcRadius = -0.32 maxRbcRadius = 0.32 - preFilterSigma = 1.5 + preFilterSigma = 2. // 1.5 factorNbPick = 1.0 factorWindowSize = 2.0