X-Git-Url: http://git.euphorik.ch/?p=master-thesis.git;a=blobdiff_plain;f=Parasitemia%2FParasitemia%2FImageAnalysis.fs;fp=Parasitemia%2FParasitemia%2FImageAnalysis.fs;h=1215965e961deb67086d2b339cf74f88be0199e3;hp=0000000000000000000000000000000000000000;hb=ba64921fb9a0c36cd8cf802cbf1b2c0f79bc25f6;hpb=0ff8fb82457bd5a858b2218ab07f69c81323537e diff --git a/Parasitemia/Parasitemia/ImageAnalysis.fs b/Parasitemia/Parasitemia/ImageAnalysis.fs new file mode 100644 index 0000000..1215965 --- /dev/null +++ b/Parasitemia/Parasitemia/ImageAnalysis.fs @@ -0,0 +1,121 @@ +module ImageAnalysis + +open System +open System.Drawing + +open Emgu.CV +open Emgu.CV.Structure + +open Utils +open ImgTools +open Config +open Types + +type Result = { + RBCPositions : Point list + infectedRBCPositions : Point list + img: Image +} + +let doAnalysis (img: Image) (config: Config) : Result = + + let imgFloat = img.Convert() + use scaledImg = if config.scale = 1.0 then imgFloat else imgFloat.Resize(config.scale, CvEnum.Inter.Area) + + (*use scaledImg = + if config.scale = 1.0 + then + img + else + let m = new Mat() + CvInvoke.Resize(img, m, Size(roundInt (float img.Size.Width * config.scale), roundInt (float img.Size.Height * config.scale))) + m*) + + use green = scaledImg.Item(1) + + //use green = new Matrix(scaledImg.Size) + //CvInvoke.MixChannels(scaledImg, green, [| 1; 0 |]) + + //let greenMatrix = new Matrix(green.Height, green.Width, green.DataPointer) + + //let test = greenMatrix.[10, 10] + + use filteredGreen = (gaussianFilter green config.doGSigma1) - config.doGLowFreqPercentageReduction * (gaussianFilter green config.doGSigma2) + + use sobelKernel = + new ConvolutionKernelF(array2D [[ 1.0f; 0.0f; -1.0f ] + [ 2.0f; 0.0f; -2.0f ] + [ 1.0f; 0.0f; -1.0f ]], Point(0, 0)) + + use xEdges = filteredGreen.Convolution(sobelKernel).Convert() + use yEdges = filteredGreen.Convolution(sobelKernel.Transpose()).Convert() + + let xEdgesData = xEdges.Data + let yEdgesData = yEdges.Data + for r in 0..xEdges.Rows-1 do + xEdgesData.[r, 0, 0] <- 0.0 + xEdgesData.[r, xEdges.Cols-1, 0] <- 0.0 + yEdgesData.[r, 0, 0] <- 0.0 + yEdgesData.[r, xEdges.Cols-1, 0] <- 0.0 + + for c in 0..xEdges.Cols-1 do + xEdgesData.[0, c, 0] <- 0.0 + xEdgesData.[xEdges.Rows-1, c, 0] <- 0.0 + yEdgesData.[0, c, 0] <- 0.0 + yEdgesData.[xEdges.Rows-1, c, 0] <- 0.0 + + use magnitudes = new Matrix(xEdges.Size) + CvInvoke.CartToPolar(xEdges, yEdges, magnitudes, new Mat()) // Compute the magnitudes (without angles). + + let min = ref 0.0 + let minLocation = ref <| Point() + let max = ref 0.0 + let maxLocation = ref <| Point() + magnitudes.MinMax(min, max, minLocation, maxLocation) + + use magnitudesByte = ((magnitudes / !max) * 255.0).Convert() // Otsu from OpenCV only support 'byte'. + use edges = new Matrix(xEdges.Size) + let threshold = CvInvoke.Threshold(magnitudesByte, edges, 0.0, 1.0, CvEnum.ThresholdType.Otsu ||| CvEnum.ThresholdType.Binary) + thin edges + removeArea edges 12 + + saveMat (edges * 255.0) "edges.png" + + let radiusRange = config.scale * 20.0, config.scale * 40.0 + let windowSize = roundInt (1.6 * (snd radiusRange)) + let factorNbPick = 1.0; + let ellipses = Ellipse.find edges xEdges yEdges radiusRange windowSize factorNbPick + + drawEllipse img (List.head ellipses) (Bgr(0.0, 255.0, 255.0)) + saveImg img "ellipses.png" + + { RBCPositions = []; infectedRBCPositions = []; img = img } + + // + + (*use imageHSV = scaledImage.Convert() + let H, S = match imageHSV.Split() with // Warning: H is from 0 to 179°. + | [| H; S; _|] -> H, S + | _ -> failwith "unable to split the HSV channels" + + let hueShiftValue = 175 + // Modulo operator doesn't exist on matrix thus we have to apply a function to every pixels. + let correctedH : Image = H.Convert(fun b _ _ -> + (255 - int(b) * 255 / 179 + hueShiftValue) % 256 |> byte + ) + + let correctedS : Image = S.Not() + + let filteredH = correctedH.SmoothMedian(5) + let filteredS = correctedS.SmoothMedian(5)*) + + //let greenChannel = scaledImage.Item(1) + + //let filteredImage = (gaussianFilter greenChannel config.doGSigma1) - config.doGLowFreqPercentageReduction * (gaussianFilter greenChannel config.doGSigma2) + + // let filteredImage = greenChannel.ThresholdAdaptive(Gray(255.), CvEnum.AdaptiveThresholdType.GaussianC, CvEnum.ThresholdType.Binary, 61, Gray(5.0)) + // let thresholdedImage = filteredImage.CopyBlank() + + // CvInvoke.Threshold(filteredImage, thresholdedImage, 0., 255., CvEnum.ThresholdType.Otsu ||| CvEnum.ThresholdType.BinaryInv) |> ignore + + // filteredImage <| \ No newline at end of file