module Parasitemia.Main open System open System.IO open System.Windows open System.Windows.Media open System.Windows.Markup open System.Windows.Shapes open System.Windows.Controls open System.Drawing open System.Diagnostics open System.Threading open FSharp.Collections.ParallelSeq open Emgu.CV open Emgu.CV.Structure open Emgu.CV.WPF open Config let display (window : Views.MainWindow) (img : IImage) = let imgControl = window.Root.FindName("img") :?> Controls.Image imgControl.Source <- BitmapSourceConvert.ToBitmapSource(img) let log (window : Views.MainWindow) (mess : string) = let txtLog = window.Root.FindName("txtLog") :?> Controls.TextBlock txtLog.Text <- txtLog.Text + mess + "\n" type Input = | File of string | Dir of string type RunningMode = | CmdLine of Input * string | Window type Arguments = RunningMode * bool let parseArgs (args: string[]) : Arguments = let output = Array.tryFindIndex ((=) "--output") args let runningMode = match Array.tryFindIndex ((=) "--folder") args, output with | Some i, Some i_output when i < args.Length - 2 && i_output < args.Length - 2 -> CmdLine ((Dir args.[i+1]), args.[i_output + 1]) | _ -> match Array.tryFindIndex ((=) "--file") args, output with | Some i, Some i_output when i < args.Length - 2 && i_output < args.Length - 2 -> CmdLine ((File args.[i+1]), args.[i_output + 1]) |_ -> Window runningMode, Array.exists ((=) "--debug") args [] let main args = match parseArgs args with | mode, debug -> let config = Config( { scale = 1. initialAreaOpen = 2000 minRbcRadius = -0.32f maxRbcRadius = 0.32f preFilterSigma = 1.7 // 1.5 factorNbPick = 1.0 darkStainLevel = 0.22 // Lower -> more sensitive. 0.3. Careful about illumination on the borders. maxDarkStainRatio = 0.1 // 10 % infectionArea = 0.012f // 1.2 % infectionLevel = 1.12 // Lower -> more sensitive. stainArea = 0.08f // 8 % stainLevel = 1.1 // Lower -> more sensitive. maxStainRatio = 0.12 // 12 % standardDeviationMaxRatio = 0.5 // 0.55 minimumCellArea = 0.5f }) match mode with | CmdLine (input, output) -> if debug then config.Debug <- DebugOn output Directory.CreateDirectory output |> ignore use logFile = new StreamWriter(new FileStream(Path.Combine(output, "log.txt"), FileMode.Append, FileAccess.Write)) Utils.log <- (fun m -> logFile.WriteLine(m)) Utils.log (sprintf "=== New run : %A %A ===" DateTime.Now (if debug then "[DEBUG]" else "[RELEASE]")) let files = match input with | File file -> [ file ] | Dir dir -> Directory.EnumerateFiles dir |> List.ofSeq use resultFile = new StreamWriter(new FileStream(Path.Combine(output, "results.txt"), FileMode.Append, FileAccess.Write)) //try let images = seq { for file in files -> Path.GetFileNameWithoutExtension(FileInfo(file).Name), new Image(file) } let nbConcurrentTaskLimit = 4 let n = Environment.ProcessorCount Utils.logTime "Whole analyze" (fun () -> let results = images |> PSeq.map (fun (id, img) -> id, ImageAnalysis.doAnalysis img id (config.Copy())) |> PSeq.withDegreeOfParallelism (if n > nbConcurrentTaskLimit then nbConcurrentTaskLimit else n) for id, cells in results do let total, infected = Utils.countCells cells fprintf resultFile "File: %s %d %d %.2f\n" id total infected (100. * (float infected) / (float total))) //Utils.log (sprintf "== File: %A" file) //with //| :? IOException as ex -> Utils.log (sprintf "Unable to open the image '%A': %A" file ex) 0 | Window -> let app = new Application() let mainWindow = Views.MainWindow() if debug then config.Debug <- DebugOn "." Utils.log <- (fun m -> log mainWindow m) //display mainWindow img mainWindow.Root.Show() app.Run()