X-Git-Url: http://git.euphorik.ch/?p=master-thesis.git;a=blobdiff_plain;f=Parasitemia%2FParasitemia%2FImgTools.fs;fp=Parasitemia%2FParasitemia%2FImgTools.fs;h=cc09405b3477005646cf8f560eea32016e54dbcf;hp=0000000000000000000000000000000000000000;hb=ba64921fb9a0c36cd8cf802cbf1b2c0f79bc25f6;hpb=0ff8fb82457bd5a858b2218ab07f69c81323537e diff --git a/Parasitemia/Parasitemia/ImgTools.fs b/Parasitemia/Parasitemia/ImgTools.fs new file mode 100644 index 0000000..cc09405 --- /dev/null +++ b/Parasitemia/Parasitemia/ImgTools.fs @@ -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) = + 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 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) (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(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(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