// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
-[<assembly: AssemblyTitle("Logger")>]
-[<assembly: AssemblyDescription("")>]
-[<assembly: AssemblyConfiguration("")>]
-[<assembly: AssemblyCompany("")>]
-[<assembly: AssemblyProduct("Logger")>]
-[<assembly: AssemblyCopyright("Copyright © 2016")>]
-[<assembly: AssemblyTrademark("")>]
-[<assembly: AssemblyCulture("")>]
+[<assembly: AssemblyTitle "Logger">]
+[<assembly: AssemblyDescription "">]
+[<assembly: AssemblyConfiguration "">]
+[<assembly: AssemblyCompany "">]
+[<assembly: AssemblyProduct "Logger">]
+[<assembly: AssemblyCopyright "Copyright © 2016">]
+[<assembly: AssemblyTrademark "">]
+[<assembly: AssemblyCulture "">]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
-[<assembly: ComVisible(false)>]
+[<assembly: ComVisible false>]
// The following GUID is for the ID of the typelib if this project is exposed to COM
-[<assembly: Guid("a4f183ae-562a-4bad-88e6-658b4ce15dc3")>]
+[<assembly: Guid "a4f183ae-562a-4bad-88e6-658b4ce15dc3">]
// Version information for an assembly consists of the following four values:
//
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-// [<assembly: AssemblyVersion("1.0.*")>]
-[<assembly: AssemblyVersion("1.0.0.0")>]
-[<assembly: AssemblyFileVersion("1.0.0.0")>]
+// [<assembly: AssemblyVersion "1.0.*">]
+[<assembly: AssemblyVersion "1.0.0.0">]
+[<assembly: AssemblyFileVersion "1.0.0.0">]
do
()
\ No newline at end of file
if isNull path then
None
else
- let filename = path.Substring(path.LastIndexOf(Path.DirectorySeparatorChar) + 1)
- let filenameWithoutExtension = filename.Remove(filename.IndexOf('.'))
- match Int32.TryParse(filenameWithoutExtension) with
+ let filename = path.Substring (path.LastIndexOf Path.DirectorySeparatorChar + 1)
+ let filenameWithoutExtension = filename.Remove (filename.IndexOf '.')
+ match Int32.TryParse filenameWithoutExtension with
| (true, n) -> Some n
| _ -> None
let [<Literal>] COMPRESS_ARCHIVED_FILES = true
let [<Literal>] FILENAME_FORMAT = "{0:D4}.log"
let [<Literal>] COMPRESSED_FILE_POSTFIX = ".gzip"
- let encoding = Encoding.GetEncoding("UTF-8")
+ let encoding = Encoding.GetEncoding "UTF-8"
let compress (filename : string) =
- use inputStream = new FileStream(filename, FileMode.Open, FileAccess.Read)
+ use inputStream = new FileStream (filename, FileMode.Open, FileAccess.Read)
let filenameCompressed = filename + COMPRESSED_FILE_POSTFIX
- use compressedStream = new GZipStream(new FileStream(filenameCompressed, FileMode.Create, FileAccess.Write), CompressionLevel.Optimal)
- inputStream.CopyTo(compressedStream)
+ use compressedStream = new GZipStream (new FileStream (filenameCompressed, FileMode.Create, FileAccess.Write), CompressionLevel.Optimal)
+ inputStream.CopyTo compressedStream
let moduleName = System.Diagnostics.StackFrame(1).GetMethod().Module.Name
let mutable logDir : string = null
- let monitor = Object()
+ let monitor = Object ()
- let listeners = List<IListener>()
+ let listeners = List<IListener> ()
let debug =
#if DEBUG
false
#endif
- static let instance = new Log()
+ static let instance = new Log ()
let openLogFile (entryNumber : int64) =
if not (isNull logDir) then
then
if not (isNull stream)
then
- stream.Close()
+ stream.Close ()
if COMPRESS_ARCHIVED_FILES then
compress filename
- File.Delete(filename)
+ File.Delete filename
// Search the last id among the log files.
let mutable n = 1
- for existingFile in Directory.GetFiles(logDir) do
+ for existingFile in Directory.GetFiles logDir do
match extractNumberFromLogfilepath existingFile with
| Some n' when n' > n -> n <- n'
| _ -> ()
- filename <- Path.Combine(logDir, String.Format(FILENAME_FORMAT, n))
+ filename <- Path.Combine (logDir, String.Format (FILENAME_FORMAT, n))
try
- if File.Exists(filename + COMPRESSED_FILE_POSTFIX) || FileInfo(filename).Length > MAX_SIZE_FILE
+ if File.Exists (filename + COMPRESSED_FILE_POSTFIX) || FileInfo(filename).Length > MAX_SIZE_FILE
then
- filename <- Path.Combine(logDir, String.Format(FILENAME_FORMAT, n + 1))
+ filename <- Path.Combine (logDir, String.Format (FILENAME_FORMAT, n + 1))
with
| :? FileNotFoundException -> () // The file may not exist.
- stream <- new StreamWriter(filename, true, encoding)
+ stream <- new StreamWriter (filename, true, encoding)
with
- | ex -> Console.Error.WriteLine("Can't open the file log: {0}", ex)
+ | ex -> Console.Error.WriteLine ("Can't open the file log: {0}", ex)
let write (msg : Message) (entryNumber : int64) =
openLogFile entryNumber
let header =
- String.Format(
+ String.Format (
"{0:yyyy-MM-dd HH:mm:ss.fff} [{1}] {{{2}}} ({3})",
- TimeZone.CurrentTimeZone.ToLocalTime(DateTime.UtcNow),
+ TimeZone.CurrentTimeZone.ToLocalTime DateTime.UtcNow,
string msg.Severity,
msg.ModuleCaller,
- (if String.IsNullOrEmpty(msg.ThreadName) then string msg.ThreadId else sprintf "%s-%i" msg.ThreadName msg.ThreadId)
+ (if String.IsNullOrEmpty msg.ThreadName then string msg.ThreadId else sprintf "%s-%i" msg.ThreadName msg.ThreadId)
)
for listener in listeners do
if not (isNull stream)
then
try
- stream.WriteLine("{0} : {1}", header, msg.Message)
- stream.Flush()
+ stream.WriteLine ("{0} : {1}", header, msg.Message)
+ stream.Flush ()
with
- | :? IOException as ex -> Console.Error.WriteLine("Unable to write to the log file: {0}", ex)
+ | :? IOException as ex -> Console.Error.WriteLine ("Unable to write to the log file: {0}", ex)
let writeAgent =
- new MailboxProcessor<Command>(
+ new MailboxProcessor<Command> (
fun inbox ->
let rec loop (nbEntries : int64) =
async {
- let! command = inbox.Receive()
+ let! command = inbox.Receive ()
match command with
| Write message ->
write message nbEntries
)
do
- writeAgent.Start()
+ writeAgent.Start ()
let setLogDirectory (dir : string) =
- lock monitor (fun () ->
- logDir <- dir
+ lock monitor (
+ fun () ->
+ logDir <- dir
- if not <| isNull stream then
- stream.Close()
- stream <- null
+ if not <| isNull stream then
+ stream.Close ()
+ stream <- null
- try
- if not <| Directory.Exists(logDir)
- then
- Directory.CreateDirectory(logDir) |> ignore
- with
- | _ -> Console.Error.WriteLine("Unable to create the log directory: {0}", logDir))
+ try
+ if not <| Directory.Exists logDir
+ then
+ Directory.CreateDirectory logDir |> ignore
+ with
+ | _ -> Console.Error.WriteLine ("Unable to create the log directory: {0}", logDir)
+ )
interface IDisposable with
member this.Dispose () =
if not (isNull stream)
then
- stream.Dispose()
- (writeAgent :> IDisposable).Dispose()
+ stream.Dispose ()
+ (writeAgent :> IDisposable).Dispose ()
member private this.Write (message : string) (severity : Severity) =
let moduleNameCaller =
/// Will stop and wait a reply. Used to flush the remaining messages.
/// </summary>
member private this.Stop () =
- writeAgent.PostAndReply(
+ writeAgent.PostAndReply (
fun replyChannel ->
Stop replyChannel
)
instance.LogDirectory <- dir
member this.AddListener (listener : IListener) =
- lock monitor (fun () ->
- if not <| listeners.Contains(listener)
- then
- listeners.Add(listener))
+ lock monitor (
+ fun () ->
+ if not <| listeners.Contains listener
+ then
+ listeners.Add listener
+ )
member this.RmListener (listener : IListener) =
- lock monitor (fun () ->
- listeners.Remove(listener) |> ignore)
+ lock monitor (fun () -> listeners.Remove listener |> ignore)
- static member AddListener (listener : IListener) = instance.AddListener(listener)
- static member RmListener (listener : IListener) = instance.RmListener(listener)
+ static member AddListener (listener : IListener) = instance.AddListener listener
+ static member RmListener (listener : IListener) = instance.RmListener listener
static member LogWithTime (severity : Severity) (f : unit -> 'a) (format : Printf.StringFormat<'b, 'a>) : 'b =
- let sw = Stopwatch()
- sw.Start()
+ let sw = Stopwatch ()
+ sw.Start ()
let res = f ()
- sw.Stop()
+ sw.Stop ()
Printf.kprintf (fun s -> instance.Write (s + sprintf " (time: %d ms)" sw.ElapsedMilliseconds) severity; res) format
static member Debug format =
Printf.kprintf (fun s -> instance.Write s Severity.FATAL) format
static member Shutdown () =
- instance.Stop()
+ instance.Stop ()
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
-VisualStudioVersion = 15.0.26403.7
+VisualStudioVersion = 15.0.26430.6
MinimumVisualStudioVersion = 10.0.40219.1
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "ParasitemiaUI", "ParasitemiaUI\ParasitemiaUI.fsproj", "{70838E65-F211-44FC-B28F-0ED1CA6E850F}"
EndProject
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
+ GlobalSection(Performance) = preSolution
+ HasPerformanceSessions = true
+ EndGlobalSection
EndGlobal
logWithName "Starting analysis ..."
- use img_float = img.Convert<Bgr, float32>()
+ use img_float = img.Convert<Bgr, float32> ()
use img_RBC = img_float.[1] // Green.
use img_RBC_filtered = gaussianFilter img_RBC config.LPFStandardDeviationRBC
let delta = config.Parameters.granulometryRange * config.RBCRadiusByResolution.Pixel
int <| config.RBCRadiusByResolution.Pixel - delta, int <| config.RBCRadiusByResolution.Pixel + delta
- let! radius = logTimeWithName "Granulometry (area)" (fun() -> reportWithVal 10 (Granulometry.findRadiusByAreaClosing img_RBC_filtered range |> float32))
- //let! radius = logTimeWithName "Granulometry (morpho)" (fun() -> reportWithVal 10 (Granulometry.findRadiusByClosing img_RBC_filtered range 1. true |> float32))
+ let! radius = logTimeWithName "Granulometry (area)" (fun () -> reportWithVal 10 (Granulometry.findRadiusByAreaClosing img_RBC_filtered range |> float32))
+ //let! radius = logTimeWithName "Granulometry (morpho)" (fun () -> reportWithVal 10 (Granulometry.findRadiusByClosing img_RBC_filtered range 1. true |> float32))
config.SetRBCRadius <| radius
logWithName (sprintf "Found erythrocyte diameter: %O" config.RBCRadius)
let! parasites, imgWhitoutParasite, imgWithoutNucleus =
logTimeWithName "Parasites segmentation" (fun () -> reportWithVal 40 (ParasitesMarker.find img_parasites_filtered config))
- let! edges, xGradient, yGradient = logTimeWithName "Finding edges" (fun () ->
- let edges, xGradient, yGradient = Edges.find img_RBC_filtered
- removeArea edges (config.RBCRadius.Pixel ** 2.f / 50.f |> int)
- reportWithVal 50 (edges, xGradient, yGradient))
+ let! edges, xGradient, yGradient =
+ logTimeWithName "Finding edges" (
+ fun () ->
+ let edges, xGradient, yGradient = Edges.find img_RBC_filtered
+ removeArea edges (config.RBCRadius.Pixel ** 2.f / 50.f |> int)
+ reportWithVal 50 (edges, xGradient, yGradient)
+ )
let! matchingEllipses = logTimeWithName "Finding ellipses" (fun () -> reportWithVal 60 (Ellipse.find edges xGradient yGradient config))
// Output pictures if debug flag is set.
match config.Debug with
| DebugOn output ->
- let dirPath = System.IO.Path.Combine(output, name)
+ let dirPath = System.IO.Path.Combine (output, name)
System.IO.Directory.CreateDirectory dirPath |> ignore
- let buildFileName postfix = System.IO.Path.Combine(dirPath, name + postfix)
+ let buildFileName postfix = System.IO.Path.Combine (dirPath, name + postfix)
IO.saveMat (edges * 255.0) (buildFileName " - edges.png")
IO.saveImg parasites.parasite (buildFileName " - parasites - stain.png")
IO.saveImg parasites.nucleus (buildFileName " - parasites - infection.png")
- let imgAllEllipses = img_RBC_filtered.Copy()
- Drawing.drawEllipses imgAllEllipses matchingEllipses.Ellipses (Gray(200.0)) 0.04
+ let imgAllEllipses = img_RBC_filtered.Copy ()
+ Drawing.drawEllipses imgAllEllipses matchingEllipses.Ellipses (Gray 200.0) 0.04
IO.saveImg imgAllEllipses (buildFileName " - ellipses - all.png")
- let imgEllipses = img_RBC_filtered.Convert<Bgr, byte>()
- Drawing.drawEllipses imgEllipses prunedEllipses (Bgr(0.0, 240.0, 240.0)) 1.0
+ let imgEllipses = img_RBC_filtered.Convert<Bgr, byte> ()
+ Drawing.drawEllipses imgEllipses prunedEllipses (Bgr (0.0, 240.0, 240.0)) 1.0
IO.saveImg imgEllipses (buildFileName " - ellipses.png")
- let imgCells = img.Copy()
+ let imgCells = img.Copy ()
Drawing.drawCells imgCells false cells
IO.saveImg imgCells (buildFileName " - cells.png")
- let imgCells' = img.Copy()
+ let imgCells' = img.Copy ()
Drawing.drawCells imgCells' true cells
IO.saveImg imgCells' (buildFileName " - cells - full.png")
| Some f -> f percent
| _ -> true
- let progressPerAnalysis = System.Collections.Concurrent.ConcurrentDictionary<string, int>()
+ let progressPerAnalysis = System.Collections.Concurrent.ConcurrentDictionary<string, int> ()
let nbImgs = List.length imgs
let reportProgressImg (id : string) (progress : int) =
- progressPerAnalysis.AddOrUpdate(id, progress, (fun _ _ -> progress)) |> ignore
- report (progressPerAnalysis.Values.Sum() / nbImgs)
+ progressPerAnalysis.AddOrUpdate (id, progress, (fun _ _ -> progress)) |> ignore
+ report (progressPerAnalysis.Values.Sum () / nbImgs)
let n = Environment.ProcessorCount
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
-[<assembly: AssemblyTitle("ParasitemiaCore")>]
-[<assembly: AssemblyDescription("")>]
-[<assembly: AssemblyConfiguration("")>]
-[<assembly: AssemblyCompany("HES-SO / CHUV / Grégory Burri")>]
-[<assembly: AssemblyProduct("ParasitemiaCore")>]
-[<assembly: AssemblyCopyright("Copyright © 2015-2016")>]
-[<assembly: AssemblyTrademark("")>]
-[<assembly: AssemblyCulture("")>]
+[<assembly: AssemblyTitle "ParasitemiaCore">]
+[<assembly: AssemblyDescription "">]
+[<assembly: AssemblyConfiguration "">]
+[<assembly: AssemblyCompany "HES-SO / CHUV / Grégory Burri">]
+[<assembly: AssemblyProduct "ParasitemiaCore">]
+[<assembly: AssemblyCopyright "Copyright © 2015-2016">]
+[<assembly: AssemblyTrademark "">]
+[<assembly: AssemblyCulture "">]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
-[<assembly: ComVisible(false)>]
+[<assembly: ComVisible false>]
// The following GUID is for the ID of the typelib if this project is exposed to COM
-[<assembly: Guid("0f8a85f4-9328-40c3-b8ff-44fb39ceb01f")>]
+[<assembly: Guid "0f8a85f4-9328-40c3-b8ff-44fb39ceb01f">]
// Version information for an assembly consists of the following four values:
//
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-// [<assembly: AssemblyVersion("1.0.*")>]
-[<assembly: AssemblyVersion("1.0.0.10")>]
-[<assembly: AssemblyFileVersion("1.0.0.10")>]
+// [<assembly: AssemblyVersion "1.0.*">]
+[<assembly: AssemblyVersion "1.0.0.10">]
+[<assembly: AssemblyFileVersion "1.0.0.10">]
do
()
\ No newline at end of file
let pixelOwnedByE (p : PointF) (e : EllipseFlaggedKd) (neighbors : (EllipseFlaggedKd * PointF * PointF) list) =
e.Contains p.X p.Y &&
seq {
- let c = PointF(e.Cx, e.Cy)
+ let c = PointF (e.Cx, e.Cy)
for e', d1 in
(neighbors
)) do
if e'.State = e.State then // Peculiar vs peculiar or RBC vs RBC.
let d2 = lineFromTwoPoints c p
- let c' = PointF(e'.Cx, e'.Cy)
+ let c' = PointF (e'.Cx, e'.Cy)
let v = pointFromTwoLines d1 (lineFromTwoPoints c c')
let case1 = sign (v.X - c.X) <> sign (v.X - c'.X) || Utils.squaredDistanceTwoPoints v c > Utils.squaredDistanceTwoPoints v c'
if not (Single.IsInfinity d2.A) then
if e.State <> CellState.Removed then
tree.Search (searchRegion e)
// We only keep the ellipses touching 'e'.
- |> List.choose (fun otherE ->
- if e <> otherE then
- match EEOver.EEOverlapArea e otherE with
- | Some (_, px, _) when px.Length > 2 ->
- otherE.State <- CellState.Removed
- None
- | Some (area, px, py) when area > 0.f && px.Length = 2 ->
- Some (otherE, PointF(px.[0], py.[0]), PointF(px.[1], py.[1]))
- | _ ->
+ |> List.choose (
+ fun otherE ->
+ if e <> otherE then
+ match EEOver.EEOverlapArea e otherE with
+ | Some (_, px, _) when px.Length > 2 ->
+ otherE.State <- CellState.Removed
+ None
+ | Some (area, px, py) when area > 0.f && px.Length = 2 ->
+ Some (otherE, PointF (px.[0], py.[0]), PointF (px.[1], py.[1]))
+ | _ ->
+ None
+ else
None
- else
- None
)
else
[]
// 3) Remove ellipses with a high standard deviation (high contrast).
// Obsolete. It was useful when the ellipses result quality wasn't good.
(* let imgData = img.Data
- let globalStdDeviation = MathNet.Numerics.Statistics.Statistics.PopulationStandardDeviation(seq {
+ let globalStdDeviation = MathNet.Numerics.Statistics.Statistics.PopulationStandardDeviation (seq {
for y in 0 .. h - 1 do
for x in 0 .. w - 1 do
yield float imgData.[y, x, 0] })
let mutable area = 0
for y = (if minY < 0 then 0 else minY) to (if maxY >= height then height - 1 else maxY) do
for x = (if minX < 0 then 0 else minX) to (if maxX >= width then width - 1 else maxX) do
- let p = PointF(float32 x, float32 y)
+ let p = PointF (float32 x, float32 y)
if pixelOwnedByE p e neighbors then
area <- area + 1
// 5) Define non-rbc (peculiar) cells.
let darkStainData = parasites.darkStain.Data
ellipsesWithNeigbors
- |> List.choose (fun (e, neighbors) ->
- if e.State = CellState.Removed then
- None
- else
- let mutable darkStainPixels = 0
- let mutable nbElement = 0
- let minX, minY, maxX, maxY = ellipseWindow e
- for y = minY to maxY do
- for x = minX to maxX do
- let p = PointF(float32 x, float32 y)
- if pixelOwnedByE p e neighbors then
- nbElement <- nbElement + 1
- if darkStainData.[y, x, 0] > 0uy then
- darkStainPixels <- darkStainPixels + 1
+ |> List.choose (
+ fun (e, neighbors) ->
+ if e.State = CellState.Removed then
+ None
+ else
+ let mutable darkStainPixels = 0
+ let mutable nbElement = 0
+ let minX, minY, maxX, maxY = ellipseWindow e
+ for y = minY to maxY do
+ for x = minX to maxX do
+ let p = PointF (float32 x, float32 y)
+ if pixelOwnedByE p e neighbors then
+ nbElement <- nbElement + 1
+ if darkStainData.[y, x, 0] > 0uy then
+ darkStainPixels <- darkStainPixels + 1
- if float darkStainPixels > config.Parameters.maxDarkStainRatio * (float nbElement) then Some e else None)
+ if float darkStainPixels > config.Parameters.maxDarkStainRatio * (float nbElement) then Some e else None
+ )
// We do not change the state during the process to avoid to have peculiar neighbors which change the behavior of 'pixelOwnedByE'.
|> List.iter (fun e -> e.State <- CellState.Peculiar)
else
let minX, minY, maxX, maxY = ellipseWindow e
- let nucleusPixels = List<Point>()
- let parasitePixels = List<Point>()
+ let nucleusPixels = List<Point> ()
+ let parasitePixels = List<Point> ()
let mutable nbElement = 0
- let elements = new Matrix<byte>(maxY - minY + 1, maxX - minX + 1)
+ let elements = new Matrix<byte> (maxY - minY + 1, maxX - minX + 1)
for y = minY to maxY do
for x = minX to maxX do
- let p = PointF(float32 x, float32 y)
+ let p = PointF (float32 x, float32 y)
if pixelOwnedByE p e neighbors then
elements.[y - minY, x - minX] <- 1uy
nbElement <- nbElement + 1
if nucleusData.[y, x, 0] > 0uy then
- nucleusPixels.Add(Point(x, y))
+ nucleusPixels.Add (Point (x, y))
if parasiteData.[y, x, 0] > 0uy then
- parasitePixels.Add(Point(x, y))
+ parasitePixels.Add (Point (x, y))
let parasiteArea =
if nucleusPixels.Count > 0 then
seq {
for parasitePixel in parasitePixels do
- if nucleusPixels.Exists(fun p -> pown (p.X - parasitePixel.X) 2 + pown (p.Y - parasitePixel.Y) 2 <= diameterParasiteSquared) then
+ if nucleusPixels.Exists (fun p -> pown (p.X - parasitePixel.X) 2 + pown (p.Y - parasitePixel.Y) 2 <= diameterParasiteSquared) then
yield 1
} |> Seq.sum
else
Some
{
cellClass = cellClass
- center = Point(roundInt e.Cx, roundInt e.Cy)
+ center = Point (roundInt e.Cx, roundInt e.Cy)
nucleusArea = if cellClass = InfectedRBC then nucleusPixels.Count else 0
parasiteArea = parasiteArea
elements = elements
member this.NucleusArea = parameters.nucleusAreaRatio * this.Area
member this.MinimumParasiteArea = parameters.minimumParasiteAreaRatio * this.Area
- override this.ToString() =
+ override this.ToString () =
sprintf "%d px (%.1f μm)" (Utils.roundInt <| 2.f * radius) (2. * this.μm)
type Config (param : Parameters) =
float32 rbcRadiusPx
let mutable parameters : Parameters = param
- let mutable rbcRadiusByResolution = RBCRadius(RBCadiusInPixels parameters.rbcDiameter parameters.resolution, parameters)
- let mutable rbcRadius = RBCRadius(0.f, parameters)
+ let mutable rbcRadiusByResolution = RBCRadius (RBCadiusInPixels parameters.rbcDiameter parameters.resolution, parameters)
+ let mutable rbcRadius = RBCRadius (0.f, parameters)
- new () = Config(defaultParameters)
+ new () = Config defaultParameters
member this.Parameters
- with get() = parameters
- and set(param) =
+ with get () = parameters
+ and set param =
parameters <- param
- rbcRadiusByResolution <- RBCRadius(RBCadiusInPixels parameters.rbcDiameter parameters.resolution, param)
- rbcRadius <- RBCRadius(rbcRadius.Pixel, param)
+ rbcRadiusByResolution <- RBCRadius (RBCadiusInPixels parameters.rbcDiameter parameters.resolution, param)
+ rbcRadius <- RBCRadius (rbcRadius.Pixel, param)
member val Debug = DebugOff with get, set
member this.RBCRadius = rbcRadius
member this.SetRBCRadius (radiusPixel : float32) =
- rbcRadius <- RBCRadius(radiusPixel, parameters)
+ rbcRadius <- RBCRadius (radiusPixel, parameters)
member this.Copy () =
- this.MemberwiseClone() :?> Config
+ this.MemberwiseClone () :?> Config
else
b <- d
c <- t / b
- d <- sqrt(0.75) * (b - c)
+ d <- sqrt 0.75 * (b - c)
r.[2, 2] <- d
b <- b + c
c <- -0.5 * b - s
let x2 = -x1
#if DEBUG_LOG
- printf "\n\tx1=%f, y1=%f, A=%f. B=%f ---> ellipse2tr(x1)= %f\n" x1 ychk.[i] a1 b1 (ellipse2tr x1 ychk.[i] aa bb cc dd ee ff)
- printf "\tx2=%f, y1=%f, A=%f. B=%f ---> ellipse2tr(x2)= %f\n" x2 ychk.[i] a1 b1 (ellipse2tr x2 ychk.[i] aa bb cc dd ee ff)
+ printf "\n\tx1=%f, y1=%f, A=%f. B=%f ---> ellipse2tr (x1)= %f\n" x1 ychk.[i] a1 b1 (ellipse2tr x1 ychk.[i] aa bb cc dd ee ff)
+ printf "\tx2=%f, y1=%f, A=%f. B=%f ---> ellipse2tr (x2)= %f\n" x2 ychk.[i] a1 b1 (ellipse2tr x2 ychk.[i] aa bb cc dd ee ff)
#endif
if abs (ellipse2tr x1 ychk.[i] aa bb cc dd ee ff) < EPS then
/// 'Ellipse.Alpha' is between 0 and Pi.
/// </summary>
let ellipse (p1x : float) (p1y : float) (m1 : float) (p2x : float) (p2y : float) (m2 : float) (p3x : float) (p3y : float) : Types.Ellipse option =
- let p0 = pointFromTwoLines (Types.Line(float32 m1, float32 (p1y - m1 * p1x))) (Types.Line(float32 m2, float32(p2y - m2 * p2x)))
+ let p0 = pointFromTwoLines (Types.Line (float32 m1, float32 (p1y - m1 * p1x))) (Types.Line (float32 m2, float32(p2y - m2 * p2x)))
let p0x, p0y = float p0.X, float p0.Y
let s =
let v2 = matrix [[ 1.; p2x; p2y ]]
let v3 = matrix [[ 1.; p3x; p3y ]]
- let p = (v3.Stack(v1).Stack(v2).Determinant() * v0).Stack(v0.Stack(v3).Stack(v2).Determinant() * v1).Stack(v0.Stack(v1).Stack(v3).Determinant() * v2).Transpose()
- let conicMat = p * s.Inverse() * p.Transpose()
+ let p = (v3.Stack(v1).Stack(v2).Determinant () * v0).Stack(v0.Stack(v3).Stack(v2).Determinant () * v1).Stack(v0.Stack(v1).Stack(v3).Determinant () * v2).Transpose ()
+ let conicMat = p * s.Inverse () * p.Transpose ()
let a = conicMat.[0, 0]
let b = conicMat.[0, 1]
let c = conicMat.[1, 1]
None
else
let q = (-1. / at) * (matrix [[ a * f - d ** 2.0; b * d - a * e ]; [ b * d - a * e; a * c - b ** 2.0 ]])
- let eigen = q.Evd()
+ let eigen = q.Evd ()
let eigenValues = eigen.EigenValues
let lambda = eigenValues.[1].Real
let mu = eigenValues.[0].Real
let phi' = if phi < 0. then phi + Math.PI else phi
let majorAxis, minorAxis = if r1 > r2 then r1, r2 else r2, r1
- Some (Types.Ellipse(float32 cx, float32 cy, float32 majorAxis, float32 minorAxis, float32 phi'))
+ Some (Types.Ellipse (float32 cx, float32 cy, float32 majorAxis, float32 minorAxis, float32 phi'))
let inline private vectorRotation (px : float32) (py : float32) (vx : float32) (vy : float32) (p0x : float32) (p0y : float32) : float32 =
if py > p0y then
let mutable last_i, last_j = Int32.MaxValue, Int32.MaxValue
- let currentElements = List<Point>()
+ let currentElements = List<Point> ()
let edgesData = edges.Data
let xDirData = xGradient.Data
let yDirData = yGradient.Data
- let rng = Random(42)
+ let rng = Random 42
- let ellipses = MatchingEllipses(config.RBCRadius.Pixel)
+ let ellipses = MatchingEllipses config.RBCRadius.Pixel
for window_i in -windowSize + increment .. increment .. h - increment do
for window_j in -windowSize + increment .. increment .. w - increment do
let window_j_end = if window_j + windowSize - 1 >= w then w - 1 else window_j + windowSize - 1
// Remove old elements.
- let indexFirstElement = currentElements.FindIndex(fun p -> p.X >= window_j_begin)
+ let indexFirstElement = currentElements.FindIndex (fun p -> p.X >= window_j_begin)
if indexFirstElement > 0 then
- currentElements.RemoveRange(0, indexFirstElement)
+ currentElements.RemoveRange (0, indexFirstElement)
// Add the new elements.
let newElemsBegin_j = window_j + windowSize - increment
for j = (if newElemsBegin_j < 0 then 0 else newElemsBegin_j) to (if newElemsEnd_j >= w then w - 1 else newElemsEnd_j) do
for i = window_i_begin to window_i_end do
if edgesData.[i, j] = 1uy then
- currentElements.Add(Point(j, i))
+ currentElements.Add (Point (j, i))
if currentElements.Count >= nbPickElementsMin then
let mutable nbOfPicks = (float currentElements.Count) * factorNbMaxPick |> int
let mutable nbOfValidPicks = (float currentElements.Count) * factorNbValidPick |> int
while nbOfPicks > 0 && nbOfValidPicks > 0 do
- let p1 = currentElements.[rng.Next(currentElements.Count)]
- let p2 = currentElements.[rng.Next(currentElements.Count)]
- let p3 = currentElements.[rng.Next(currentElements.Count)]
+ let p1 = currentElements.[rng.Next currentElements.Count]
+ let p2 = currentElements.[rng.Next currentElements.Count]
+ let p3 = currentElements.[rng.Next currentElements.Count]
if p1 <> p2 && p1 <> p3 && p2 <> p3 then
nbOfPicks <- nbOfPicks - 1
let p1yf, p1xf = float p1.Y, float p1.X
| _ -> ()
| _ -> ()
- currentElements.Clear()
+ currentElements.Clear ()
ellipses
/// <param name="range">Minimum radius * maximum radius</param>
/// <param name="scale">le 1.0, to speed up the process.</param>
let findRadiusByClosing (img : Image<Gray, 'TDepth>) (range : int * int) (scale : float) (useOctagon : bool) : int =
- use scaledImg = if scale = 1. then img else img.Resize(scale, CvEnum.Inter.Area)
+ use scaledImg = if scale = 1. then img else img.Resize (scale, CvEnum.Inter.Area)
let r1, r2 = range
let r1', r2' = roundInt (float r1 * scale), roundInt (float r2 * scale)
// 's' must be odd.
let octagon (s : int) : Matrix<byte> =
if s % 2 = 0 then failwith "s must be odd"
- let m = new Matrix<byte>(Array2D.create s s 1uy)
+ let m = new Matrix<byte> (Array2D.create s s 1uy)
let r = (float s) / (Math.Sqrt 2. + 2.) |> roundInt
for i = 0 to r - 1 do
for j = 0 to r - 1 do
if useOctagon then
(octagon (2 * r - 1)).Mat // It doesn't speed up the process.
else
- CvInvoke.GetStructuringElement(CvEnum.ElementShape.Ellipse, Size(2 * r, 2 * r), Point(-1, -1))
+ CvInvoke.GetStructuringElement (CvEnum.ElementShape.Ellipse, Size (2 * r, 2 * r), Point (-1, -1))
- use closed = scaledImg.MorphologyEx(CvEnum.MorphOp.Close, se, Point(-1, -1), 1, CvEnum.BorderType.Replicate, MCvScalar(0.0))
+ use closed = scaledImg.MorphologyEx (CvEnum.MorphOp.Close, se, Point (-1, -1), 1, CvEnum.BorderType.Replicate, MCvScalar (0.0))
let n = closed.GetSum().Intensity
if r1 > r2 then
failwithf "'radiusRange' invalid : %O" radiusRange
- use imgCopy = img.Copy()
+ use imgCopy = img.Copy ()
let mutable maxDiff = 0.f
let mutable max_r = r1
- Morpho.areaCloseFWithFun imgCopy [ for r in r1 .. r2 -> Math.PI * float r ** 2. |> roundInt, r ] (fun r diff ->
- if r <> r1 && diff > maxDiff then
- maxDiff <- diff
- max_r <- r - 1)
+ Morpho.areaCloseFWithFun imgCopy [ for r in r1 .. r2 -> Math.PI * float r ** 2. |> roundInt, r ] (
+ fun r diff ->
+ if r <> r1 && diff > maxDiff then
+ maxDiff <- diff
+ max_r <- r - 1
+ )
+
max_r
/// The goal is to have a set of data and be able to get the value associated with the min (or max) key value.
/// </summary>
type Heap<'k, 'v> (kComparer : IComparer<'k>) =
- let a = List<Node<'k, 'v>>()
+ let a = List<Node<'k, 'v>> ()
let rec heapUp (i : int) =
let l, r = left i, right i
// Is the left child greater than the parent?
- let mutable max = if l < a.Count && kComparer.Compare(a.[l].key, a.[i].key) > 0 then l else i
+ let mutable max = if l < a.Count && kComparer.Compare (a.[l].key, a.[i].key) > 0 then l else i
// Is the right child greater than the parent and the left child?
- if r < a.Count && kComparer.Compare(a.[r].key, a.[max].key) > 0 then
+ if r < a.Count && kComparer.Compare (a.[r].key, a.[max].key) > 0 then
max <- r
// If a child is greater than the parent.
let l, r = left i, right i
let leftIntegrity =
if l < a.Count then
- if kComparer.Compare(a.[l].key, a.[i].key) > 0 then false else checkIntegrity l
+ if kComparer.Compare (a.[l].key, a.[i].key) > 0 then false else checkIntegrity l
else
true
let rightIntegrity =
if r < a.Count then
- if kComparer.Compare(a.[r].key, a.[i].key) > 0 then false else checkIntegrity r
+ if kComparer.Compare (a.[r].key, a.[i].key) > 0 then false else checkIntegrity r
else
true
leftIntegrity && rightIntegrity
interface IEnumerable<'k * 'v> with
member this.GetEnumerator () : IEnumerator<'k * 'v> =
- (seq { for e in a -> e.key, e.value }).GetEnumerator()
+ (seq { for e in a -> e.key, e.value }).GetEnumerator ()
interface System.Collections.IEnumerable with
member this.GetEnumerator () : System.Collections.IEnumerator =
- (this :> IEnumerable<'k * 'v>).GetEnumerator() :> System.Collections.IEnumerator
+ (this :> IEnumerable<'k * 'v>).GetEnumerator () :> System.Collections.IEnumerator
member this.Next () : 'k * 'v =
let node = a.[0]
a.[0] <- a.[a.Count - 1]
- a.RemoveAt(a.Count - 1)
+ a.RemoveAt (a.Count - 1)
heapUp 0
node.key, node.value
member this.RemoveNext () =
a.[0] <- a.[a.Count - 1]
- a.RemoveAt(a.Count - 1)
+ a.RemoveAt (a.Count - 1)
heapUp 0
member this.Add (key : 'k) (value : 'v) =
- a.Add(Node(key, value))
+ a.Add (Node (key, value))
let mutable i = a.Count - 1
- while i > 0 && kComparer.Compare(a.[parent i].key, a.[i].key) < 0 do
+ while i > 0 && kComparer.Compare (a.[parent i].key, a.[i].key) < 0 do
let tmp = a.[parent i]
a.[parent i] <- a.[i]
a.[i] <- tmp
let max = a.[0]
max.key, max.value
- member this.Clear () = a.Clear()
+ member this.Clear () = a.Clear ()
img.Data.[p.Y, p.X, 0] <- intensity
let drawLine (img : Image<'TColor, 'TDepth>) (color : 'TColor) (x0 : int) (y0 : int) (x1 : int) (y1 : int) (thickness : int) =
- img.Draw(LineSegment2D(Point(x0, y0), Point(x1, y1)), color, thickness);
+ img.Draw (LineSegment2D (Point (x0, y0), Point (x1, y1)), color, thickness);
let drawLineF (img : Image<'TColor, 'TDepth>) (color : 'TColor) (x0 : float) (y0 : float) (x1 : float) (y1 : float) (thickness : int) =
- img.Draw(LineSegment2DF(PointF(float32 x0, float32 y0), PointF(float32 x1, float32 y1)), color, thickness, CvEnum.LineType.AntiAlias);
+ img.Draw (LineSegment2DF (PointF (float32 x0, float32 y0), PointF (float32 x1, float32 y1)), color, thickness, CvEnum.LineType.AntiAlias);
let drawEllipse (img : Image<'TColor, 'TDepth>) (e : Ellipse) (color : 'TColor) (alpha : float) =
if alpha >= 1.0 then
- img.Draw(Emgu.CV.Structure.Ellipse(PointF(e.Cx, e.Cy), SizeF(2.f * e.B, 2.f * e.A), e.Alpha / PI * 180.f), color, 1, CvEnum.LineType.AntiAlias)
+ img.Draw (Emgu.CV.Structure.Ellipse (PointF (e.Cx, e.Cy), SizeF (2.f * e.B, 2.f * e.A), e.Alpha / PI * 180.f), color, 1, CvEnum.LineType.AntiAlias)
else
let windowPosX = e.Cx - e.A - 5.f
let gapX = windowPosX - (float32 (int windowPosX))
let windowPosY = e.Cy - e.A - 5.f
let gapY = windowPosY - (float32 (int windowPosY))
- let roi = Rectangle(int windowPosX, int windowPosY, 2.f * (e.A + 5.f) |> int, 2.f * (e.A + 5.f) |> int)
+ let roi = Rectangle (int windowPosX, int windowPosY, 2.f * (e.A + 5.f) |> int, 2.f * (e.A + 5.f) |> int)
img.ROI <- roi
if roi = img.ROI then // We do not display ellipses touching the edges (FIXME)
- use i = new Image<'TColor, 'TDepth>(img.ROI.Size)
- i.Draw(Emgu.CV.Structure.Ellipse(PointF(e.A + 5.f + gapX, e.A + 5.f + gapY), SizeF(2.f * e.B, 2.f * e.A), e.Alpha / PI * 180.f), color, 1, CvEnum.LineType.AntiAlias)
- CvInvoke.AddWeighted(img, 1.0, i, alpha, 0.0, img)
+ use i = new Image<'TColor, 'TDepth> (img.ROI.Size)
+ i.Draw (Emgu.CV.Structure.Ellipse(PointF(e.A + 5.f + gapX, e.A + 5.f + gapY), SizeF(2.f * e.B, 2.f * e.A), e.Alpha / PI * 180.f), color, 1, CvEnum.LineType.AntiAlias)
+ CvInvoke.AddWeighted (img, 1.0, i, alpha, 0.0, img)
img.ROI <- Rectangle.Empty
let drawEllipses (img : Image<'TColor, 'TDepth>) (ellipses : Ellipse list) (color : 'TColor) (alpha : float) =
List.iter (fun e -> drawEllipse img e color alpha) ellipses
-let rngCell = System.Random()
+let rngCell = System.Random ()
let drawCell (img : Image<Bgr, byte>) (drawCellContent : bool) (c : Cell) =
if drawCellContent then
- let colorB = rngCell.Next(20, 70)
- let colorG = rngCell.Next(20, 70)
- let colorR = rngCell.Next(20, 70)
+ let colorB = rngCell.Next (20, 70)
+ let colorG = rngCell.Next (20, 70)
+ let colorR = rngCell.Next (20, 70)
for y = 0 to c.elements.Height - 1 do
for x = 0 to c.elements.Width - 1 do
let crossColor, crossColor2 =
match c.cellClass with
- | HealthyRBC -> Bgr(255., 0., 0.), Bgr(255., 255., 255.)
- | InfectedRBC -> Bgr(0., 0., 255.), Bgr(120., 120., 255.)
- | Peculiar -> Bgr(0., 0., 0.), Bgr(80., 80., 80.)
+ | HealthyRBC -> Bgr (255., 0., 0.), Bgr (255., 255., 255.)
+ | InfectedRBC -> Bgr (0., 0., 255.), Bgr (120., 120., 255.)
+ | Peculiar -> Bgr (0., 0., 0.), Bgr (80., 80., 80.)
drawLine img crossColor2 (c.center.X - 3) c.center.Y (c.center.X + 3) c.center.Y 2
drawLine img crossColor2 c.center.X (c.center.Y - 3) c.center.X (c.center.Y + 3) 2
let h = img.Height
use sobelKernel =
- new Matrix<float32>(
+ new Matrix<float32> (
array2D [[ -1.0f; 0.0f; 1.0f ]
[ -2.0f; 0.0f; 2.0f ]
[ -1.0f; 0.0f; 1.0f ]]
)
- let xGradient = new Matrix<float32>(img.Size)
- let yGradient = new Matrix<float32>(img.Size)
- CvInvoke.Filter2D(img, xGradient, sobelKernel, Point(1, 1))
- CvInvoke.Filter2D(img, yGradient, sobelKernel.Transpose(), Point(1, 1))
+ let xGradient = new Matrix<float32> (img.Size)
+ let yGradient = new Matrix<float32> (img.Size)
+ CvInvoke.Filter2D (img, xGradient, sobelKernel, Point (1, 1))
+ CvInvoke.Filter2D (img, yGradient, sobelKernel.Transpose (), Point (1, 1))
- use magnitudes = new Matrix<float32>(xGradient.Size)
- use angles = new Matrix<float32>(xGradient.Size)
- CvInvoke.CartToPolar(xGradient, yGradient, magnitudes, angles) // Compute the magnitudes and angles. The angles are between 0 and 2 * pi.
+ use magnitudes = new Matrix<float32> (xGradient.Size)
+ use angles = new Matrix<float32> (xGradient.Size)
+ CvInvoke.CartToPolar (xGradient, yGradient, magnitudes, angles) // Compute the magnitudes and angles. The angles are between 0 and 2 * pi.
let thresholdHigh, thresholdLow =
let threshold, _, _ = otsu (histogramMat magnitudes 300)
threshold + (sensibilityHigh * threshold), threshold - (sensibilityLow * threshold)
// Non-maximum suppression.
- use nms = new Matrix<byte>(xGradient.Size)
+ use nms = new Matrix<byte> (xGradient.Size)
let nmsData = nms.Data
let anglesData = angles.Data
// suppressMConnections nms // It's not helpful for the rest of the process (ellipse detection).
- let edges = new Matrix<byte>(xGradient.Size)
+ let edges = new Matrix<byte> (xGradient.Size)
let edgesData = edges.Data
// Hysteresis thresholding.
- let toVisit = Stack<Point>()
+ let toVisit = Stack<Point> ()
for i = 0 to h - 1 do
for j = 0 to w - 1 do
if nmsData.[i, j] = 1uy && magnitudesData.[i, j] >= thresholdHigh then
nmsData.[i, j] <- 0uy
- toVisit.Push(Point(j, i))
+ toVisit.Push (Point (j, i))
while toVisit.Count > 0 do
- let p = toVisit.Pop()
+ let p = toVisit.Pop ()
edgesData.[p.Y, p.X] <- 1uy
for i' = -1 to 1 do
for j' = -1 to 1 do
let nj = p.X + j'
if ni >= 0 && ni < h && nj >= 0 && nj < w && nmsData.[ni, nj] = 1uy then
nmsData.[ni, nj] <- 0uy
- toVisit.Push(Point(nj, ni))
+ toVisit.Push (Point (nj, ni))
edges, xGradient, yGradient
\ No newline at end of file
let min, max =
let min = ref [| 0.0 |]
- let minLocation = ref <| [| Point() |]
+ let minLocation = ref <| [| Point () |]
let max = ref [| 0.0 |]
- let maxLocation = ref <| [| Point() |]
- img.MinMax(min, max, minLocation, maxLocation)
+ let maxLocation = ref <| [| Point () |]
+ img.MinMax (min, max, minLocation, maxLocation)
float32 (!min).[0], float32 (!max).[0]
let inline bin (x : float32) : int =
let min, max =
let min = ref 0.0
- let minLocation = ref <| Point()
+ let minLocation = ref <| Point ()
let max = ref 0.0
- let maxLocation = ref <| Point()
- mat.MinMax(min, max, minLocation, maxLocation)
+ let maxLocation = ref <| Point ()
+ mat.MinMax (min, max, minLocation, maxLocation)
float32 !min, float32 !max
let inline bin (x : float32) : int =
open Emgu.CV.Structure
let saveImg (img : Image<'TColor, 'TDepth>) (filepath : string) =
- img.Save(filepath)
+ img.Save filepath
let saveMat (mat : Matrix<'TDepth>) (filepath : string) =
- use img = new Image<Gray, 'TDeph>(mat.Size)
- mat.CopyTo(img)
+ use img = new Image<Gray, 'TDeph> (mat.Size)
+ mat.CopyTo img
saveImg img filepath
/// <param name="upperLimit"></param>
let normalize (img : Image<Gray, float32>) (upperLimit : float) : Image<Gray, float32> =
let min = ref [| 0.0 |]
- let minLocation = ref <| [| Point() |]
+ let minLocation = ref <| [| Point () |]
let max = ref [| 0.0 |]
- let maxLocation = ref <| [| Point() |]
- img.MinMax(min, max, minLocation, maxLocation)
+ let maxLocation = ref <| [| Point () |]
+ img.MinMax (min, max, minLocation, maxLocation)
let normalized = (img - (!min).[0]) / ((!max).[0] - (!min).[0])
if upperLimit = 1.0 then
normalized
| 0., 1., 0. -> img.[1]
| 0., 0., 1. -> img.[0]
| redFactor, greenFactor, blueFactor ->
- let result = new Image<Gray, float32>(img.Size)
- CvInvoke.AddWeighted(result, 1., img.[2], redFactor, 0., result)
- CvInvoke.AddWeighted(result, 1., img.[1], greenFactor, 0., result)
- CvInvoke.AddWeighted(result, 1., img.[0], blueFactor, 0., result)
+ let result = new Image<Gray, float32> (img.Size)
+ CvInvoke.AddWeighted (result, 1., img.[2], redFactor, 0., result)
+ CvInvoke.AddWeighted (result, 1., img.[1], greenFactor, 0., result)
+ CvInvoke.AddWeighted (result, 1., img.[0], blueFactor, 0., result)
result
let mergeChannelsWithProjection (img : Image<Bgr, float32>) (v1r : float32, v1g : float32, v1b : float32) (v2r : float32, v2g : float32, v2b : float32) (upperLimit : float) : Image<Gray, float32> =
let vr, vg, vb = v2r - v1r, v2g - v1g, v2b - v1b
let vMagnitude = sqrt (vr ** 2.f + vg ** 2.f + vb ** 2.f)
let project (r : float32) (g : float32) (b : float32) = ((r - v1r) * vr + (g - v1g) * vg + (b - v1b) * vb) / vMagnitude
- let result = new Image<Gray, float32>(img.Size)
+ let result = new Image<Gray, float32> (img.Size)
// TODO: Essayer en bindant Data pour gagner du temps
for i = 0 to img.Height - 1 do
for j = 0 to img.Width - 1 do
// Normalize image values between 0uy and 255uy.
let normalizeAndConvert (img : Image<Gray, 'TDepth>) : Image<Gray, byte> =
- (normalize (img.Convert<Gray, float32>()) 255.).Convert<Gray, byte>()
+ (normalize (img.Convert<Gray, float32> ()) 255.).Convert<Gray, byte> ()
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)
+ img.SmoothGaussian (size, size, standardDeviation, standardDeviation)
let imgData = img.Data
let suppress : bool[,] = Array2D.zeroCreate h w
- let result = List<List<Point>>()
+ let result = List<List<Point>> ()
let flood (start : Point) : List<List<Point>> =
- let sameLevelToCheck = Stack<Point>()
- let betterLevelToCheck = Stack<Point>()
- betterLevelToCheck.Push(start)
+ let sameLevelToCheck = Stack<Point> ()
+ let betterLevelToCheck = Stack<Point> ()
+ betterLevelToCheck.Push start
- let result' = List<List<Point>>()
+ let result' = List<List<Point>> ()
while betterLevelToCheck.Count > 0 do
- let p = betterLevelToCheck.Pop()
+ let p = betterLevelToCheck.Pop ()
if not suppress.[p.Y, p.X] then
suppress.[p.Y, p.X] <- true
- sameLevelToCheck.Push(p)
- let current = List<Point>()
+ sameLevelToCheck.Push p
+ let current = List<Point> ()
let mutable betterExists = false
while sameLevelToCheck.Count > 0 do
- let p' = sameLevelToCheck.Pop()
+ let p' = sameLevelToCheck.Pop ()
let currentLevel = imgData.[p'.Y, p'.X, 0]
- current.Add(p') |> ignore
+ current.Add p' |> ignore
for i, j in se do
let ni = i + p'.Y
let nj = j + p'.X
if notSuppressed && level = currentLevel then
suppress.[ni, nj] <- true
- sameLevelToCheck.Push(Point(nj, ni))
+ sameLevelToCheck.Push (Point (nj, ni))
elif (if extremumType = ExtremumType.Maxima then level > currentLevel else level < currentLevel) then
betterExists <- true
if notSuppressed then
- betterLevelToCheck.Push(Point(nj, ni))
+ betterLevelToCheck.Push (Point (nj, ni))
if not betterExists then
- result'.Add(current)
+ result'.Add current
result'
for i = 0 to h - 1 do
for j = 0 to w - 1 do
- let maxima = flood (Point(j, i))
+ let maxima = flood (Point (j, i))
if maxima.Count > 0 then
- result.AddRange(maxima)
+ result.AddRange maxima
- result.Select(fun l -> Points(l))
+ result.Select (fun l -> Points l)
let inline findMaxima (img : Image<Gray, 'TDepth>) : IEnumerable<Points> when 'TDepth : unmanaged =
findExtremum img ExtremumType.Maxima
type PriorityQueue () =
let size = 256
- let q : Points[] = Array.init size (fun i -> Points())
+ let q : Points[] = Array.init size (fun i -> Points ())
let mutable highest = -1 // Value of the first elements of 'q'.
let mutable lowest = size
invalidOp "Queue is empty"
else
let l = q.[highest]
- let next = l.First()
- l.Remove(next) |> ignore
+ let next = l.First ()
+ l.Remove next |> ignore
let value = byte highest
if l.Count = 0 then
invalidOp "Queue is empty"
else
let l = q.[lowest + 1]
- let next = l.First()
- l.Remove(next) |> ignore
+ let next = l.First ()
+ l.Remove next |> ignore
let value = byte (lowest + 1)
if l.Count = 0 then
if vi <= lowest then
lowest <- vi - 1
- q.[vi].Add(p) |> ignore
+ q.[vi].Add p |> ignore
member this.Remove (value : byte) (p : Point) =
let vi = int value
- if q.[vi].Remove(p) && q.[vi].Count = 0 then
+ if q.[vi].Remove p && q.[vi].Count = 0 then
if vi = highest then
highest <- highest - 1
while highest > lowest && q.[highest].Count = 0 do
member this.Clear () =
while highest > lowest do
- q.[highest].Clear()
+ q.[highest].Clear ()
highest <- highest - 1
highest <- -1
lowest <- size
let imgData = img.Data
let se = [| -1, 0; 0, -1; 1, 0; 0, 1 |]
- let areas = List<Area>((if op = AreaOperation.Opening then findMaxima img else findMinima img) |> Seq.map Area)
+ let areas = List<Area> ((if op = AreaOperation.Opening then findMaxima img else findMinima img) |> Seq.map Area)
let pixels : Area[,] = Array2D.create h w null
for m in areas do
for e in m.Elements do
pixels.[e.Y, e.X] <- m
- let queue = PriorityQueue()
+ let queue = PriorityQueue ()
let addEdgeToQueue (elements : Points) =
for p in elements do
for i, j in se do
let ni = i + p.Y
let nj = j + p.X
- let p' = Point(nj, ni)
- if ni >= 0 && ni < h && nj >= 0 && nj < w && not (elements.Contains(p')) then
+ let p' = Point (nj, ni)
+ if ni >= 0 && ni < h && nj >= 0 && nj < w && not (elements.Contains p') then
queue.Add (imgData.[ni, nj, 0]) p'
// Reverse order is quicker.
for i = areas.Count - 1 downto 0 do
let m = areas.[i]
if m.Elements.Count <= area && m.State <> AreaState.Removed then
- queue.Clear()
+ queue.Clear ()
addEdgeToQueue m.Elements
let mutable intensity = if op = AreaOperation.Opening then queue.Max else queue.Min
- let nextElements = Points()
+ let nextElements = Points ()
let mutable stop = false
while not stop do
m.Intensity <- Some intensity
stop <- true
else
- nextElements.Add(p) |> ignore
+ nextElements.Add p |> ignore
elif (if op = AreaOperation.Opening then intensity' < intensity else intensity' > intensity) then
- m.Elements.UnionWith(nextElements)
+ m.Elements.UnionWith nextElements
for e in nextElements do
pixels.[e.Y, e.X] <- m
stop <- true
else
intensity <- intensity'
- nextElements.Clear()
- nextElements.Add(p) |> ignore
+ nextElements.Clear ()
+ nextElements.Add p |> ignore
else
match pixels.[p.Y, p.X] with
pixels.[e.Y, e.X] <- m
queue.Remove imgData.[e.Y, e.X, 0] e
addEdgeToQueue m'.Elements
- m.Elements.UnionWith(m'.Elements)
+ m.Elements.UnionWith m'.Elements
let intensityMax = if op = AreaOperation.Opening then queue.Max else queue.Min
if intensityMax <> intensity then
intensity <- intensityMax
- nextElements.Clear()
+ nextElements.Clear ()
merged <- true
if not merged then
for i, j in se do
let ni = i + p.Y
let nj = j + p.X
- let p' = Point(nj, ni)
+ let p' = Point (nj, ni)
if ni < 0 || ni >= h || nj < 0 || nj >= w then
m.State <- AreaState.Validated
m.Intensity <- Some (intensity)
stop <- true
- elif not (m.Elements.Contains(p')) && not (nextElements.Contains(p')) then
+ elif not (m.Elements.Contains p') && not (nextElements.Contains p') then
queue.Add (imgData.[ni, nj, 0]) p'
if queue.IsEmpty then
if m.Elements.Count + nextElements.Count <= area then
m.State <- AreaState.Validated
m.Intensity <- Some intensity'
- m.Elements.UnionWith(nextElements)
+ m.Elements.UnionWith nextElements
stop <- true
for m in areas do
let flooded : bool[,] = Array2D.zeroCreate h w
- let pointsChecked = HashSet<Point>()
- let pointsToCheck = Stack<Point>()
+ let pointsChecked = HashSet<Point> ()
+ let pointsToCheck = Stack<Point> ()
for level = 255 downto 0 do
let mutable n = histogram.[level]
for j = 0 to w - 1 do
if not flooded.[i, j] && imgData.[i, j, 0] = byte level then
let mutable maxNeighborValue = 0uy
- pointsChecked.Clear()
- pointsToCheck.Clear()
- pointsToCheck.Push(Point(j, i))
+ pointsChecked.Clear ()
+ pointsToCheck.Clear ()
+ pointsToCheck.Push (Point (j, i))
while pointsToCheck.Count > 0 do
- let next = pointsToCheck.Pop()
- pointsChecked.Add(next) |> ignore
+ let next = pointsToCheck.Pop ()
+ pointsChecked.Add next |> ignore
flooded.[next.Y, next.X] <- true
for nx, ny in se do
- let p = Point(next.X + nx, next.Y + ny)
+ let p = Point (next.X + nx, next.Y + ny)
if p.X >= 0 && p.X < w && p.Y >= 0 && p.Y < h then
let v = imgData.[p.Y, p.X, 0]
if v = byte level then
- if not (pointsChecked.Contains(p)) then
- pointsToCheck.Push(p)
+ if not (pointsChecked.Contains p) then
+ pointsToCheck.Push p
elif v > maxNeighborValue then
maxNeighborValue <- v
[<AllowNullLiteral>]
type Island (cmp : IComparer<float32>) =
- member val Shore = Heap.Heap<float32, Point>(cmp) with get
+ member val Shore = Heap.Heap<float32, Point> cmp with get
member val Level = 0.f with get, set
member val Surface = 0 with get, set
member this.IsInfinite = this.Surface = Int32.MaxValue
let comparer =
if op = AreaOperation.Opening then
- { new IComparer<float32> with member this.Compare(v1, v2) = v1.CompareTo(v2) }
+ { new IComparer<float32> with member this.Compare (v1, v2) = v1.CompareTo v2 }
else
- { new IComparer<float32> with member this.Compare(v1, v2) = v2.CompareTo(v1) }
+ { new IComparer<float32> with member this.Compare (v1, v2) = v2.CompareTo v1 }
let ownership : Island[,] = Array2D.create h w null
// Initialize islands with their shore.
- let islands = List<Island>()
+ let islands = List<Island> ()
let extremum = img |> if op = AreaOperation.Opening then findMaxima else findMinima
for e in extremum do
let island =
- let p = e.First()
- Island(comparer, Level = earth.[p.Y, p.X, 0], Surface = e.Count)
- islands.Add(island)
- let shorePoints = Points()
+ let p = e.First ()
+ Island (comparer, Level = earth.[p.Y, p.X, 0], Surface = e.Count)
+ islands.Add island
+ let shorePoints = Points ()
for p in e do
ownership.[p.Y, p.X] <- island
for i, j in se do
let ni = i + p.Y
let nj = j + p.X
- let neighbor = Point(nj, ni)
- if ni >= 0 && ni < h && nj >= 0 && nj < w && Object.ReferenceEquals(ownership.[ni, nj], null) && not (shorePoints.Contains(neighbor)) then
- shorePoints.Add(neighbor) |> ignore
+ let neighbor = Point (nj, ni)
+ if ni >= 0 && ni < h && nj >= 0 && nj < w && Object.ReferenceEquals (ownership.[ni, nj], null) && not (shorePoints.Contains neighbor) then
+ shorePoints.Add neighbor |> ignore
island.Shore.Add earth.[ni, nj, 0] neighbor
for area, obj in areas do
if other = island then // During merging, some points on the shore may be owned by the island itself -> ignored.
island.Shore.RemoveNext ()
else
- if not <| Object.ReferenceEquals(other, null) then
+ if not <| Object.ReferenceEquals (other, null) then
// We touching another island.
- if island.IsInfinite || other.IsInfinite || island.Surface + other.Surface >= area || comparer.Compare(island.Level, other.Level) < 0 then
+ if island.IsInfinite || other.IsInfinite || island.Surface + other.Surface >= area || comparer.Compare (island.Level, other.Level) < 0 then
stop <- true
else // We can merge 'other' into 'surface'.
island.Surface <- island.Surface + other.Surface
island.Level <- other.Level
- // island.Level <- if comparer.Compare(island.Level, other.Level) > 0 then other.Level else island.Level
for l, p in other.Shore do
let mutable currentY = p.Y + 1
while currentY < h && ownership.[currentY, p.X] = other do
ownership.[currentY, p.X] <- island
currentY <- currentY + 1
island.Shore.Add l p
- other.Shore.Clear()
+ other.Shore.Clear ()
- elif comparer.Compare(level, island.Level) > 0 then
+ elif comparer.Compare (level, island.Level) > 0 then
stop <- true
else
island.Shore.RemoveNext ()
island.Surface <- Int32.MaxValue
stop <- true
else
- let neighbor = Point(nj, ni)
+ let neighbor = Point (nj, ni)
if not <| ownedOrAdjacent neighbor then
island.Shore.Add earth.[ni, nj, 0] neighbor
if not stop then
( 0, -1) // p8
(-1, -1) |] // p9
- use mat' = new Matrix<byte>(mat.Size)
+ use mat' = new Matrix<byte> (mat.Size)
let w = mat'.Width
let h = mat'.Height
- mat.CopyTo(mat')
+ mat.CopyTo mat'
let data = mat.Data
let data' = mat'.Data
for i = 0 to h - 1 do
for j = 0 to w - 1 do
if data'.[i, j] = 1uy then
- let neighborhood = List<Point>()
- let neighborsToCheck = Stack<Point>()
- neighborsToCheck.Push(Point(j, i))
+ let neighborhood = List<Point> ()
+ let neighborsToCheck = Stack<Point> ()
+ neighborsToCheck.Push (Point (j, i))
data'.[i, j] <- 0uy
while neighborsToCheck.Count > 0 do
- let n = neighborsToCheck.Pop()
- neighborhood.Add(n)
+ let n = neighborsToCheck.Pop ()
+ neighborhood.Add n
for (ni, nj) in neighbors do
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.Push(Point(pj, pi))
+ neighborsToCheck.Push (Point (pj, pi))
data'.[pi, pj] <- 0uy
if neighborhood.Count <= areaSize then
for n in neighborhood do
let w = img.Width
let h = img.Height
- let pointChecked = Points()
- let pointToCheck = Stack<Point>(startPoints);
+ let pointChecked = Points ()
+ let pointToCheck = Stack<Point> startPoints;
let data = img.Data
while pointToCheck.Count > 0 do
- let next = pointToCheck.Pop()
- pointChecked.Add(next) |> ignore
+ let next = pointToCheck.Pop ()
+ pointChecked.Add next |> ignore
for ny = -1 to 1 do
for nx = -1 to 1 do
if ny <> 0 && nx <> 0 then
- let p = Point(next.X + nx, next.Y + ny)
+ 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.Push(p)
+ pointToCheck.Push p
pointChecked
let h = img.Height
let min = ref [| 0.0 |]
- let minLocation = ref <| [| Point() |]
+ let minLocation = ref <| [| Point () |]
let max = ref [| 0.0 |]
- let maxLocation = ref <| [| Point() |]
- img.MinMax(min, max, minLocation, maxLocation)
+ let maxLocation = ref <| [| Point () |]
+ img.MinMax (min, max, minLocation, maxLocation)
let minf = float32 (!min).[0]
let maxf = float32 (!max).[0]
let mutable mean_fg = minf + (maxf - minf) / 4.f
use mutable d_bg : Image<Gray, float32> = null
let mutable d_fg : Image<Gray, float32> = null
- let fg = new Image<Gray, byte>(img.Size)
+ let fg = new Image<Gray, byte> (img.Size)
let imgData = img.Data
let fgData = fg.Data
match d_bg with
| null -> ()
| _ ->
- d_bg.Dispose()
- d_fg.Dispose()
+ d_bg.Dispose ()
+ d_fg.Dispose ()
// EmGu doesn't import the in-place version of 'AbsDiff' so we have to create two images for each iteration.
- d_bg <- img.AbsDiff(Gray(float mean_bg))
- d_fg <- img.AbsDiff(Gray(float mean_fg))
+ d_bg <- img.AbsDiff (Gray (float mean_bg))
+ d_fg <- img.AbsDiff (Gray (float mean_fg))
- CvInvoke.Compare(d_fg, d_bg, fg, CvEnum.CmpType.LessThan)
+ CvInvoke.Compare (d_fg, d_bg, fg, CvEnum.CmpType.LessThan)
let mutable bg_total = 0.f
let mutable bg_nb = 0
let h = img.Height
let min = ref [| 0.0 |]
- let minLocation = ref <| [| Point() |]
+ let minLocation = ref <| [| Point () |]
let max = ref [| 0.0 |]
- let maxLocation = ref <| [| Point() |]
- img.MinMax(min, max, minLocation, maxLocation)
+ let maxLocation = ref <| [| Point () |]
+ img.MinMax (min, max, minLocation, maxLocation)
let mutable median_bg = (!max).[0] - ((!max).[0] - (!min).[0]) / 4.0
let mutable median_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)
+ 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 = 1 to nbIteration do
- d_bg <- img.AbsDiff(Gray(median_bg))
- d_fg <- img.AbsDiff(Gray(median_fg))
+ d_bg <- img.AbsDiff (Gray median_bg)
+ d_fg <- img.AbsDiff (Gray median_fg)
- CvInvoke.Compare(d_fg, d_bg, fg, CvEnum.CmpType.LessThan)
+ CvInvoke.Compare (d_fg, d_bg, fg, CvEnum.CmpType.LessThan)
- let bg_values = List<float>()
- let fg_values = List<float>()
+ let bg_values = List<float> ()
+ let fg_values = List<float> ()
for i = 0 to h - 1 do
for j = 0 to w - 1 do
if fg.Data.[i, j, 0] > 0uy then
- fg_values.Add(float img.Data.[i, j, 0])
+ fg_values.Add (float img.Data.[i, j, 0])
else
- bg_values.Add(float img.Data.[i, j, 0])
+ bg_values.Add (float img.Data.[i, j, 0])
- median_bg <- MathNet.Numerics.Statistics.Statistics.Median(bg_values)
- median_fg <- MathNet.Numerics.Statistics.Statistics.Median(fg_values)
+ median_bg <- MathNet.Numerics.Statistics.Statistics.Median bg_values
+ median_fg <- MathNet.Numerics.Statistics.Statistics.Median fg_values
{ fg = fg; median_bg = median_bg; median_fg = median_fg; d_fg = d_fg }
// Compare 'e1' and 'e2' by X.
let cmpX (e1 : I2DCoords) (e2 : I2DCoords) : int =
- match e1.X.CompareTo(e2.X) with
- | 0 -> match e1.Y.CompareTo(e2.Y) with
- | 0 -> e1.GetHashCode().CompareTo(e2.GetHashCode())
+ match e1.X.CompareTo e2.X with
+ | 0 -> match e1.Y.CompareTo e2.Y with
+ | 0 -> e1.GetHashCode().CompareTo (e2.GetHashCode ())
| v -> v
| v -> v
// Compare 'e1' and 'e2' by Y.
let cmpY (e1 : I2DCoords) (e2 : I2DCoords) : int =
- match e1.Y.CompareTo(e2.Y) with
- | 0 -> match e1.X.CompareTo(e2.X) with
- | 0 -> e1.GetHashCode().CompareTo(e2.GetHashCode())
+ match e1.Y.CompareTo e2.Y with
+ | 0 -> match e1.X.CompareTo e2.X with
+ | 0 -> e1.GetHashCode().CompareTo (e2.GetHashCode ())
| v -> v
| v -> v
member this.Y = this.Ellipse.Cy
type MatchingEllipses (radius : float32) =
- let ellipses = List<EllipseScoreFlaggedKd>()
+ let ellipses = List<EllipseScoreFlaggedKd> ()
member this.Add (e : Ellipse) =
- ellipses.Add(EllipseScoreFlaggedKd(0.f, e))
+ ellipses.Add (EllipseScoreFlaggedKd (0.f, e))
member this.Ellipses : Ellipse list =
List.ofSeq ellipses |> List.map (fun e -> e.Ellipse)
// Because of approximation error, see https://github.com/chraibi/EEOver/issues/4
when overlapArea - areaE < 1.f && overlapArea - areaOther < 1.f ->
let matchingScore = (2.f * overlapArea / (areaE + areaOther)) ** matchingScorePower
- other.AddMatchingScore(matchingScore)
- e.AddMatchingScore(matchingScore)
+ other.AddMatchingScore matchingScore
+ e.AddMatchingScore matchingScore
| _ -> ()
// 3) Remove ellipses whose center is near the center of another ellipse with a better score.
for other in tree.Search window do
if not other.Removed && e.MatchingScore > other.MatchingScore then
// Case where ellipses are too close.
- if distanceTwoPoints (PointF(e.Ellipse.Cx, e.Ellipse.Cy)) (PointF(other.Ellipse.Cx, other.Ellipse.Cy)) < minimumDistanceFromCenterRadiusFactor * e.Ellipse.B then
+ if distanceTwoPoints (PointF (e.Ellipse.Cx, e.Ellipse.Cy)) (PointF (other.Ellipse.Cx, other.Ellipse.Cy)) < minimumDistanceFromCenterRadiusFactor * e.Ellipse.B then
other.Removed <- true
else
// Case where ellipses are overlapped.
ellipses
|> List.ofSeq
|> List.filter (fun e -> not e.Removed)
- |> List.sortWith (fun e1 e2 -> e2.MatchingScore.CompareTo(e1.MatchingScore))
+ |> List.sortWith (fun e1 e2 -> e2.MatchingScore.CompareTo e1.MatchingScore)
|> List.map (fun e -> e.Ellipse)
<Private>True</Private>
</Reference>
<Reference Include="FSharp.Core">
- <HintPath>..\packages\FSharp.Core.4.1.17\lib\net45\FSharp.Core.dll</HintPath>
+ <HintPath>..\packages\FSharp.Core.4.2.1\lib\net45\FSharp.Core.dll</HintPath>
</Reference>
<Reference Include="MathNet.Numerics">
<HintPath>..\packages\MathNet.Numerics.3.19.0\lib\net40\MathNet.Numerics.dll</HintPath>
let find (img : Image<Gray, float32>) (config : Config.Config) : Result * Image<Gray, float32> * Image<Gray, float32> =
- let imgWithoutNucleus = img.Copy()
+ let imgWithoutNucleus = img.Copy ()
areaCloseF imgWithoutNucleus (roundInt config.RBCRadius.NucleusArea)
let darkStain =
let _, mean_fg, mean_bg =
let hist = histogramImg imgWithoutNucleus 300
otsu hist
- imgWithoutNucleus.Cmp(float mean_fg - config.Parameters.darkStainLevel * float (mean_bg - mean_fg), CvEnum.CmpType.LessThan)
+ imgWithoutNucleus.Cmp (float mean_fg - config.Parameters.darkStainLevel * float (mean_bg - mean_fg), CvEnum.CmpType.LessThan)
let marker (img : Image<Gray, float32>) (closed : Image<Gray, float32>) (level : float) : Image<Gray, byte> =
- let diff = img.Copy()
- diff._Mul(level)
- CvInvoke.Subtract(closed, diff, diff)
- diff._ThresholdBinary(Gray(0.0), Gray(255.))
- diff.Convert<Gray, byte>()
+ let diff = img.Copy ()
+ diff._Mul level
+ CvInvoke.Subtract (closed, diff, diff)
+ diff._ThresholdBinary (Gray 0.0, Gray 255.)
+ diff.Convert<Gray, byte> ()
// Nucleus.
let nucleusMarker = marker img imgWithoutNucleus (1. / config.Parameters.infectionSensitivity)
// Cytoplasm.
- let imgWithoutParasite = img.CopyBlank()
+ let imgWithoutParasite = img.CopyBlank ()
let kernelSize =
let size = roundInt config.RBCRadius.CytoplasmSize
if size % 2 = 0 then size + 1 else size
use kernel =
if kernelSize <= 3 then
- CvInvoke.GetStructuringElement(CvEnum.ElementShape.Rectangle, Size(3, 3), Point(-1, -1))
+ CvInvoke.GetStructuringElement (CvEnum.ElementShape.Rectangle, Size (3, 3), Point (-1, -1))
else
- CvInvoke.GetStructuringElement(CvEnum.ElementShape.Ellipse, Size(kernelSize, kernelSize), Point(-1, -1))
+ CvInvoke.GetStructuringElement (CvEnum.ElementShape.Ellipse, Size (kernelSize, kernelSize), Point (-1, -1))
- CvInvoke.MorphologyEx(img, imgWithoutParasite, CvEnum.MorphOp.Close, kernel, Point(-1, -1), 1, CvEnum.BorderType.Replicate, MCvScalar())
+ CvInvoke.MorphologyEx (img, imgWithoutParasite, CvEnum.MorphOp.Close, kernel, Point(-1, -1), 1, CvEnum.BorderType.Replicate, MCvScalar())
let parasiteMarker = marker img imgWithoutParasite (1. / config.Parameters.cytoplasmSensitivity)
{
this.CutAnHorizontalLine 0.f || this.CutAnHorizontalLine height
member this.Scale (factor : float32) : Ellipse =
- Ellipse(this.Cx, this.Cy, this.A * factor, this.B * factor, alpha)
+ Ellipse (this.Cx, this.Cy, this.A * factor, this.B * factor, alpha)
// Approximation of Ramanujan.
member this.Perimeter =
PI * (3.f * (this.A + this.B) - sqrt ((3.f * this.A + this.B) * (this.A + 3.f * this.B)))
override this.ToString () =
- sprintf "(cx: %f, cy: %f, a: %f, b: %f, alpha: %f)" this.Cx this.Cy this.A this.B this.Alpha
+ sprintf "{Ellipse: cx = %f, cy = %f, a = %f, b = %f, alpha = %f}" this.Cx this.Cy this.A this.B this.Alpha
type CellClass = HealthyRBC | InfectedRBC | Peculiar
member this.TryFinally (body, compensation) =
try
- this.ReturnFrom(body())
+ this.ReturnFrom (body ())
finally
- compensation()
+ compensation ()
member this.Using (disposable : 'a when 'a :> IDisposable, body) =
let body' = fun () -> body disposable
- this.TryFinally(body', fun () ->
+ this.TryFinally (body', fun () ->
match disposable with
| null -> ()
- | disp -> disp.Dispose())
+ | disp -> disp.Dispose ())
member this.Zero () =
None
member this.Return x =
Some x
-let maybe = MaybeBuilder()
+let maybe = MaybeBuilder ()
type Result<'a> =
| Success of 'a
member this.ReturnFrom (x) = x
-let result = ResultBuilder()
\ No newline at end of file
+let result = ResultBuilder ()
\ No newline at end of file
let μmPerInch = 25.4e3<μm/inch>
let mmPerInch = 25.4<mm/inch>
-let μmToInch(x : float<μm>) : float<inch> = x / μmPerInch
-let inchToμm(x : float<inch>) : float<μm> = x * μmPerInch
+let μmToInch (x : float<μm>) : float<inch> = x / μmPerInch
+let inchToμm (x : float<inch>) : float<μm> = x * μmPerInch
-let mmToInch(x : float<mm>) : float<inch> = x / mmPerInch
-let inchTomm(x : float<inch>) : float<mm> = x * mmPerInch
+let mmToInch (x : float<mm>) : float<inch> = x / mmPerInch
+let inchTomm (x : float<inch>) : float<mm> = x * mmPerInch
let inline lineFromTwoPoints (p1 : PointF) (p2 : PointF) : Line =
let a = (p1.Y - p2.Y) / (p1.X - p2.X)
let b = -(p2.X * p1.Y - p1.X * p2.Y) / (p1.X - p2.X)
- Line(a, b)
+ Line (a, b)
let inline pointFromTwoLines (l1 : Line) (l2 : Line) : PointF =
let x = -(l1.B - l2.B) / (l1.A - l2.A)
let y = -(l2.A * l1.B - l1.A * l2.B) / (l1.A - l2.A)
- PointF(x, y)
+ PointF (x, y)
let inline linePassThroughSegment (l : Line) (p1 : PointF) (p2 : PointF) : bool =
let p = pointFromTwoLines l (lineFromTwoPoints p1 p2)
<packages>
<package id="EmguCV" version="3.1.0.1" targetFramework="net452" />
<package id="FSharp.Collections.ParallelSeq" version="1.0.2" targetFramework="net452" />
- <package id="FSharp.Core" version="4.1.17" targetFramework="net452" />
+ <package id="FSharp.Core" version="4.2.1" targetFramework="net452" />
<package id="MathNet.Numerics" version="3.19.0" targetFramework="net452" />
<package id="MathNet.Numerics.FSharp" version="3.19.0" targetFramework="net452" />
<package id="OpenTK" version="2.0.0" targetFramework="net452" />
open System
open System.Windows
-open System.Windows.Media
-open System.Windows.Markup
-open System.Windows.Shapes
open System.Windows.Controls
open System.Diagnostics
let showWindow (parent : Window) =
- let win = Views.AboutWindow()
+ let win = Views.AboutWindow ()
win.Owner <- parent
win.Left <- (if parent.WindowState = WindowState.Maximized then 0. else parent.Left) + parent.ActualWidth / 2. - win.Width / 2.
let version = System.Reflection.Assembly.GetEntryAssembly().GetName().Version
let txtVersion = sprintf " %d.%d.%d" version.Major version.Minor version.Revision
- win.txtAbout.Inlines.FirstInline.ElementEnd.InsertTextInRun(txtVersion)
+ win.txtAbout.Inlines.FirstInline.ElementEnd.InsertTextInRun txtVersion
- let navigateTo = Navigation.RequestNavigateEventHandler(fun obj args ->
- Process.Start(ProcessStartInfo(args.Uri.AbsoluteUri)) |> ignore
- args.Handled <- true)
+ let navigateTo =
+ Navigation.RequestNavigateEventHandler (
+ fun obj args ->
+ Process.Start (ProcessStartInfo args.Uri.AbsoluteUri) |> ignore
+ args.Handled <- true
+ )
- win.linkHESSO.RequestNavigate.AddHandler(navigateTo);
- win.linkCHUV.RequestNavigate.AddHandler(navigateTo);
- win.linkGBurri.RequestNavigate.AddHandler(navigateTo);
+ win.linkHESSO.RequestNavigate.AddHandler navigateTo;
+ win.linkCHUV.RequestNavigate.AddHandler navigateTo;
+ win.linkGBurri.RequestNavigate.AddHandler navigateTo;
#if DEBUG
- win.txtAbout.Inlines.FirstInline.ElementEnd.InsertTextInRun(" - DEBUG")
+ win.txtAbout.Inlines.FirstInline.ElementEnd.InsertTextInRun " - DEBUG"
#endif
- win.butClose.Click.AddHandler(fun obj args -> win.Close())
+ win.butClose.Click.AddHandler (fun obj args -> win.Close ())
- win.ShowDialog() |> ignore
+ win.ShowDialog () |> ignore
open Types
let showWindow (parent : Window) (state : State.State) : bool =
- let win = Views.AnalysisWindow()
+ let win = Views.AnalysisWindow ()
win.Owner <- parent
win.Left <- (if parent.WindowState = WindowState.Maximized then 0. else parent.Left) + parent.ActualWidth / 2. - win.Width / 2.
win.Top <- (if parent.WindowState = WindowState.Maximized then 0. else parent.Top) + parent.ActualHeight / 2. - win.Height / 2.
{
new Logger.IListener with
member this.NewEntry severity _header mess =
- win.Dispatcher.Invoke(fun () ->
- win.textLog.Inlines.Add(Documents.Run(mess))
- win.textLog.Inlines.Add(Documents.LineBreak())
- win.scrollLog.ScrollToBottom()
+ win.Dispatcher.Invoke (
+ fun () ->
+ win.textLog.Inlines.Add (Documents.Run mess)
+ win.textLog.Inlines.Add (Documents.LineBreak ())
+ win.scrollLog.ScrollToBottom ()
)
}
- Logger.Log.AddListener(logListener)
+ Logger.Log.AddListener (logListener)
let minPPI = 1.
let maxPPI = 10e6
let parseAndValidatePPI (input : string) : float option =
- match Double.TryParse(input) with
+ match Double.TryParse input with
| true, value when value >= minPPI && value <= maxPPI -> Some value
| _ -> None
- let monitor = Object()
+ let monitor = Object ()
let mutable atLeastOneAnalysisPerformed = false
let mutable analysisPerformed = false
let mutable analysisCancelled = false
let updateSourceImages () =
- win.stackSourceImagesSelection.Children.Clear()
+ win.stackSourceImagesSelection.Children.Clear ()
let width = int win.stackSourceImagesSelection.ActualWidth
for srcImg in state.SourceImages do
- let imageSourceSelection = Views.ImageSourceSelection(Tag = srcImg, Margin = Thickness(3.))
+ let imageSourceSelection = Views.ImageSourceSelection (Tag = srcImg, Margin = Thickness 3.)
imageSourceSelection.Tag <- srcImg
- imageSourceSelection.txtImageNumber.Text <- srcImg.num.ToString()
+ imageSourceSelection.txtImageNumber.Text <- string srcImg.num
let height = srcImg.img.Height * width / srcImg.img.Width
- imageSourceSelection.imagePreview.Source <- BitmapSourceConvert.ToBitmapSource(srcImg.img.Resize(width, height, Emgu.CV.CvEnum.Inter.Cubic))
- imageSourceSelection.chkSelection.IsChecked <- Nullable<bool>(srcImg.dateLastAnalysis.Ticks = 0L)
- imageSourceSelection.lblDateLastAnalysis.Content <- if srcImg.dateLastAnalysis.Ticks = 0L then "<Never>" else srcImg.dateLastAnalysis.ToString()
+ imageSourceSelection.imagePreview.Source <- BitmapSourceConvert.ToBitmapSource (srcImg.img.Resize (width, height, Emgu.CV.CvEnum.Inter.Cubic))
+ imageSourceSelection.chkSelection.IsChecked <- Nullable<bool> (srcImg.dateLastAnalysis.Ticks = 0L)
+ imageSourceSelection.lblDateLastAnalysis.Content <- if srcImg.dateLastAnalysis.Ticks = 0L then "<Never>" else string srcImg.dateLastAnalysis
- imageSourceSelection.txtResolution.Text <- if srcImg.dateLastAnalysis.Ticks = 0L then "" else srcImg.config.Parameters.resolution.ToString()
+ imageSourceSelection.txtResolution.Text <- if srcImg.dateLastAnalysis.Ticks = 0L then "" else string srcImg.config.Parameters.resolution
for ppi in Utils.predefinedPPI do
- let menu = MenuItem()
- menu.Header <- ppi.ToString()
- menu.Click.AddHandler(fun obj args -> imageSourceSelection.txtResolution.Text <- ppi.ppi.ToString())
- imageSourceSelection.predefinedValuesMenu.Items.Add(menu) |> ignore
-
- imageSourceSelection.butPPICalculator.Click.AddHandler(fun obj args ->
- match PPICalculator.showWindow win with
- | Some resolution -> imageSourceSelection.txtResolution.Text <- resolution.ToString()
- | None -> ())
-
- imageSourceSelection.txtResolution.PreviewTextInput.AddHandler(fun obj args ->
- let text = imageSourceSelection.txtResolution.Text + args.Text
- args.Handled <- match parseAndValidatePPI text with Some _ -> false | None -> true)
-
- imageSourceSelection.imagePreview.MouseLeftButtonDown.AddHandler(fun obj args ->
- let checkbox = imageSourceSelection.chkSelection
- checkbox.IsChecked <- Nullable<bool>(not (checkbox.IsChecked.HasValue && checkbox.IsChecked.Value)))
-
- win.stackSourceImagesSelection.Children.Add(imageSourceSelection) |> ignore
+ let menu = MenuItem ()
+ menu.Header <- string ppi
+ menu.Click.AddHandler (fun obj args -> imageSourceSelection.txtResolution.Text <- string ppi.ppi)
+ imageSourceSelection.predefinedValuesMenu.Items.Add menu |> ignore
+
+ imageSourceSelection.butPPICalculator.Click.AddHandler (
+ fun obj args ->
+ match PPICalculator.showWindow win with
+ | Some resolution -> imageSourceSelection.txtResolution.Text <- string resolution
+ | None -> ()
+ )
+
+ imageSourceSelection.txtResolution.PreviewTextInput.AddHandler (
+ fun obj args ->
+ let text = imageSourceSelection.txtResolution.Text + args.Text
+ args.Handled <- match parseAndValidatePPI text with Some _ -> false | None -> true
+ )
+
+ imageSourceSelection.imagePreview.MouseLeftButtonDown.AddHandler (
+ fun obj args ->
+ let checkbox = imageSourceSelection.chkSelection
+ checkbox.IsChecked <- Nullable<bool> (not (checkbox.IsChecked.HasValue && checkbox.IsChecked.Value))
+ )
+
+ win.stackSourceImagesSelection.Children.Add (imageSourceSelection) |> ignore
// Get the new parameters for each image. If an error occurs then 'None' is returned and a message box is displayed.
// The boolean is 'true' if the image is selected (checked).
| Some resolution ->
yield Some (srcImg, isChecked.HasValue && isChecked.Value, { srcImg.config.Parameters with resolution = resolution * 1.<ppi> })
| None ->
- MessageBox.Show(sprintf "No resolution defined for the image number %d" srcImg.num, "No resolution defined", MessageBoxButton.OK, MessageBoxImage.Information) |> ignore
+ MessageBox.Show (sprintf "No resolution defined for the image number %d" srcImg.num, "No resolution defined", MessageBoxButton.OK, MessageBoxImage.Information) |> ignore
yield None
} |> Seq.takeWhile (fun e -> e.IsSome) |> Seq.map (fun e -> e.Value) |> List.ofSeq
- if parameters.Count() <> sourceImagesControls.Count() then
+ if parameters.Count () <> sourceImagesControls.Count () then
None
else
Some parameters
- win.butClose.Click.AddHandler(fun obj args -> win.Close())
-
- win.butStart.Click.AddHandler(fun obj args ->
- match getInputImagesParameters () with
- | Some imagesParameters ->
- let imagesToProcess =
- [
- for srcImg, selected, parameters in imagesParameters do
- srcImg.config.Parameters <- parameters // Save parameters.
- if selected then
- yield srcImg.num.ToString(), srcImg.config, srcImg.img
- ]
-
- if imagesToProcess.IsEmpty then
- MessageBox.Show("No image selected", "Cannot start analysis", MessageBoxButton.OK, MessageBoxImage.Information) |> ignore
- else
- win.stackSourceImagesSelection.IsEnabled <- false
- analysisPerformed <- false
- win.butStart.IsEnabled <- false
- win.butClose.Content <- "Abort"
-
- async {
- let maybeResults =
- ParasitemiaCore.Analysis.doMultipleAnalysis
- imagesToProcess
- (Some (fun progress -> win.Dispatcher.Invoke(fun () -> win.progress.Value <- float progress); not analysisCancelled))
-
- lock monitor (
- fun() ->
- match maybeResults with
- | Some results ->
- for id, cells in results do
- state.SetResult (int id) cells
- Logger.Log.Info "All analyses terminated successfully"
- atLeastOneAnalysisPerformed <- true
- analysisPerformed <- true
- | None ->
- Logger.Log.Info "Analysis aborted"
-
- win.Dispatcher.Invoke(fun () ->
- win.progress.Value <- if maybeResults.IsSome then 100. else 0.
- win.stackSourceImagesSelection.IsEnabled <- true
- win.butStart.IsEnabled <- true
- win.butClose.Content <- "Close"
- updateSourceImages ()
- )
- )
- } |> Async.Start
- | _ -> ()
+ win.butClose.Click.AddHandler (fun obj args -> win.Close ())
+
+ win.butStart.Click.AddHandler (
+ fun obj args ->
+ match getInputImagesParameters () with
+ | Some imagesParameters ->
+ let imagesToProcess =
+ [
+ for srcImg, selected, parameters in imagesParameters do
+ srcImg.config.Parameters <- parameters // Save parameters.
+ if selected then
+ yield string srcImg.num, srcImg.config, srcImg.img
+ ]
+
+ if imagesToProcess.IsEmpty then
+ MessageBox.Show ("No image selected", "Cannot start analysis", MessageBoxButton.OK, MessageBoxImage.Information) |> ignore
+ else
+ win.stackSourceImagesSelection.IsEnabled <- false
+ analysisPerformed <- false
+ win.butStart.IsEnabled <- false
+ win.butClose.Content <- "Abort"
+
+ async {
+ let maybeResults =
+ ParasitemiaCore.Analysis.doMultipleAnalysis
+ imagesToProcess
+ (Some (fun progress -> win.Dispatcher.Invoke (fun () -> win.progress.Value <- float progress); not analysisCancelled))
+
+ lock monitor (
+ fun () ->
+ match maybeResults with
+ | Some results ->
+ for id, cells in results do
+ state.SetResult (int id) cells
+ Logger.Log.Info "All analyses terminated successfully"
+ atLeastOneAnalysisPerformed <- true
+ analysisPerformed <- true
+ | None ->
+ Logger.Log.Info "Analysis aborted"
+
+ win.Dispatcher.Invoke (
+ fun () ->
+ win.progress.Value <- if maybeResults.IsSome then 100. else 0.
+ win.stackSourceImagesSelection.IsEnabled <- true
+ win.butStart.IsEnabled <- true
+ win.butClose.Content <- "Close"
+ updateSourceImages ()
+ )
+ )
+ } |> Async.Start
+ | _ -> ()
)
- win.Loaded.AddHandler(fun obj args -> updateSourceImages ())
+ win.Loaded.AddHandler (fun obj args -> updateSourceImages ())
- win.ShowDialog() |> ignore
+ win.ShowDialog () |> ignore
- Logger.Log.RmListener(logListener)
+ Logger.Log.RmListener (logListener)
lock monitor (
fun () ->
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
-[<assembly: AssemblyTitle("ParasitemiaUI")>]
-[<assembly: AssemblyDescription("")>]
-[<assembly: AssemblyConfiguration("")>]
-[<assembly: AssemblyCompany("HES-SO / CHUV / Grégory Burri")>]
-[<assembly: AssemblyProduct("ParasitemiaUI")>]
-[<assembly: AssemblyCopyright("Copyright © 2015-2016")>]
-[<assembly: AssemblyTrademark("")>]
-[<assembly: AssemblyCulture("")>]
+[<assembly: AssemblyTitle "ParasitemiaUI">]
+[<assembly: AssemblyDescription "">]
+[<assembly: AssemblyConfiguration "">]
+[<assembly: AssemblyCompany "HES-SO / CHUV / Grégory Burri">]
+[<assembly: AssemblyProduct "ParasitemiaUI">]
+[<assembly: AssemblyCopyright "Copyright © 2015-2016">]
+[<assembly: AssemblyTrademark "">]
+[<assembly: AssemblyCulture "">]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
-[<assembly: ComVisible(false)>]
+[<assembly: ComVisible false>]
// The following GUID is for the ID of the typelib if this project is exposed to COM
-[<assembly: Guid("70838e65-f211-44fc-b28f-0ed1ca6e850f")>]
+[<assembly: Guid "70838e65-f211-44fc-b28f-0ed1ca6e850f">]
// Version information for an assembly consists of the following four values:
//
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-// [<assembly: AssemblyVersion("1.0.*")>]
-[<assembly: AssemblyVersion("1.0.0.10")>]
-[<assembly: AssemblyFileVersion("1.0.0.10")>]
+// [<assembly: AssemblyVersion "1.0.*">]
+[<assembly: AssemblyVersion "1.0.0.10">]
+[<assembly: AssemblyFileVersion "1.0.0.10">]
do
()
\ No newline at end of file
open Types
let showWindow (parent : Window) : int option =
- let win = Views.PPICalculatorWindow()
+ let win = Views.PPICalculatorWindow ()
win.Owner <- parent
win.Left <- parent.Left + parent.ActualWidth / 2. - win.Width / 2.
win.Top <- parent.Top + parent.ActualHeight / 2. - win.Height / 2.
for size in Utils.sensorSizes do
- win.cmbSensorSize.Items.Add(size) |> ignore
+ win.cmbSensorSize.Items.Add (size) |> ignore
win.cmbSensorSize.SelectedIndex <- 0
let resolution (w_p : float<px>) (w_mm : float<mm>) (zoom : float) : float<ppi> =
let { w = w; h = h } = win.cmbSensorSize.SelectedValue :?> SensorSize
let ratio = h / w
- let parseDouble txt errorMess = match Double.TryParse(txt) with true, value -> Success value | _ -> Fail errorMess
+ let parseDouble txt errorMess = match Double.TryParse (txt) with true, value -> Success value | _ -> Fail errorMess
match
(result {
let wPixel = 1.<px> * sqrt (sensorResolution * 1e6 / ratio)
return! Success (float <| resolution wPixel w zoom)
}) with
- | Success res -> win.txtImageResolution.Text <- (int (res / 1000.) * 1000).ToString()
+ | Success res -> win.txtImageResolution.Text <- int (res / 1000.) * 1000 |> string
| Fail mess -> win.txtImageResolution.Text <- mess
- win.butCancel.Click.AddHandler(fun obj args -> win.DialogResult <- Nullable<bool>(false); win.Close())
- win.butOK.Click.AddHandler(fun obj args -> win.DialogResult <- Nullable<bool>(true); win.Close())
+ win.butCancel.Click.AddHandler (fun obj args -> win.DialogResult <- Nullable<bool> (false); win.Close ())
+ win.butOK.Click.AddHandler (fun obj args -> win.DialogResult <- Nullable<bool> (true); win.Close ())
- win.cmbSensorSize.SelectionChanged.AddHandler(fun obj arg -> updateCurrentResolution ())
- win.txtSensorResolution.TextChanged.AddHandler(fun obj arg -> updateCurrentResolution ())
- win.txtZoom.TextChanged.AddHandler(fun obj arg -> updateCurrentResolution ())
+ win.cmbSensorSize.SelectionChanged.AddHandler (fun obj arg -> updateCurrentResolution ())
+ win.txtSensorResolution.TextChanged.AddHandler (fun obj arg -> updateCurrentResolution ())
+ win.txtZoom.TextChanged.AddHandler (fun obj arg -> updateCurrentResolution ())
- let result = win.ShowDialog()
+ let result = win.ShowDialog ()
if result.HasValue && result.Value then
match Int32.TryParse win.txtImageResolution.Text with
| true, res -> Some res
/// <exception cref="System.IOException">If the results cannot be exported</exception>
let exportResults (state : State) (filePath : string) =
- use writer = new StreamWriter(new FileStream(filePath, FileMode.Create, FileAccess.Write))
+ use writer = new StreamWriter (new FileStream (filePath, FileMode.Create, FileAccess.Write))
fprintfn writer "File: %s" state.FilePath
fprintfn writer "Export date: %O" DateTime.Now
open Types
let run (defaultConfig : Config) (fileToOpen : string option) =
- let app = new Application()
- let win = Views.MainWindow()
+ let app = new Application ()
+ let win = Views.MainWindow ()
- let state = State.State(defaultConfig)
+ let state = State.State defaultConfig
let mutable currentScale = 1.
let mutable displayHealthy = false
let warningBelowNumberOfRBC = 1000
let y = rbc.center.Y - rbcHeight / 2. |> roundInt
let w = roundInt rbcWidth
let h = roundInt rbcHeight
- img.GetSubRect(System.Drawing.Rectangle(System.Drawing.Point((if x < 0 then 0 else x), (if y < 0 then 0 else y)),
- System.Drawing.Size((if x + w >= img.Width then img.Width - x else w),
- (if y + h >= img.Height then img.Height - y else h))))
+ img.GetSubRect (
+ System.Drawing.Rectangle (
+ System.Drawing.Point ((if x < 0 then 0 else x), (if y < 0 then 0 else y)),
+ System.Drawing.Size ((if x + w >= img.Width then img.Width - x else w), (if y + h >= img.Height then img.Height - y else h))
+ )
+ )
let setRBCFrameStyle (srcImg : SourceImage) (rbc : RBC) (frame : Views.RBCFrame) =
frame.Opacity <- if displayHealthy || rbc.setManually || rbc.infected then 1. else 0.
frame.Tag <- rbc
setRBCFrameStyle srcImg rbc frame
frame.border.StrokeThickness <- 1.
- frame.txtRBCNumber.Text <- rbc.num.ToString()
+ frame.txtRBCNumber.Text <- string rbc.num
frame
let updateDocumentStatus () =
win.txtDocumentStatus.Text <- if state.FilePath = "" then "<New document>" else state.FilePath
- let statusMessageTimer = Threading.DispatcherTimer()
- statusMessageTimer.Tick.AddHandler(fun obj args -> statusMessageTimer.Stop(); win.txtMessageStatus.Text <- "")
- statusMessageTimer.Interval <- TimeSpan(0, 0, 2)
+ let statusMessageTimer = Threading.DispatcherTimer ()
+ statusMessageTimer.Tick.AddHandler (fun obj args -> statusMessageTimer.Stop (); win.txtMessageStatus.Text <- "")
+ statusMessageTimer.Interval <- TimeSpan (0, 0, 2)
let displayStatusMessage (message : string) =
win.txtMessageStatus.Text <- message
- statusMessageTimer.Stop()
- statusMessageTimer.Start()
+ statusMessageTimer.Stop ()
+ statusMessageTimer.Start ()
let highlightRBCFrame (frame : Views.RBCFrame) (highlight : bool) =
let rbc = frame.Tag :?> RBC
if not rbc.infected && not rbc.setManually && not displayHealthy then frame.Opacity <- 0.
let zoomToRBC (rbc : RBC) =
- win.scrollViewCurrentImage.ScrollToHorizontalOffset(rbc.center.X * currentScale - win.scrollViewCurrentImage.ViewportWidth / 2. + win.borderCurrentImage.BorderThickness.Left)
- win.scrollViewCurrentImage.ScrollToVerticalOffset(rbc.center.Y * currentScale - win.scrollViewCurrentImage.ViewportHeight / 2. + win.borderCurrentImage.BorderThickness.Top)
+ win.scrollViewCurrentImage.ScrollToHorizontalOffset (rbc.center.X * currentScale - win.scrollViewCurrentImage.ViewportWidth / 2. + win.borderCurrentImage.BorderThickness.Left)
+ win.scrollViewCurrentImage.ScrollToVerticalOffset (rbc.center.Y * currentScale - win.scrollViewCurrentImage.ViewportHeight / 2. + win.borderCurrentImage.BorderThickness.Top)
let txtImageName_TextChanged =
- TextChangedEventHandler(fun obj args -> state.CurrentImage |> Option.iter(fun srcImg -> state.SetName srcImg win.txtImageName.Text))
+ TextChangedEventHandler (fun obj args -> state.CurrentImage |> Option.iter (fun srcImg -> state.SetName srcImg win.txtImageName.Text))
let updateCurrentImageInformation () =
- win.txtImageName.TextChanged.RemoveHandler(txtImageName_TextChanged)
- win.txtImageInformation1.Inlines.Clear()
- win.txtImageInformation2.Inlines.Clear()
+ win.txtImageName.TextChanged.RemoveHandler (txtImageName_TextChanged)
+ win.txtImageInformation1.Inlines.Clear ()
+ win.txtImageInformation2.Inlines.Clear ()
win.txtImageName.Text <- ""
match state.CurrentImage with
| Some srcImg ->
win.gridImageInformation.Visibility <- Visibility.Visible
win.txtImageName.Text <- srcImg.name
- win.txtImageName.TextChanged.AddHandler(txtImageName_TextChanged)
+ win.txtImageName.TextChanged.AddHandler txtImageName_TextChanged
// The left part.
let parasitemiaStr = Utils.percentText (state.ImageParasitemia srcImg)
- win.txtImageInformation1.Inlines.Add(Documents.Run("Parasitemia: ", FontWeight = FontWeights.Bold))
- win.txtImageInformation1.Inlines.Add(parasitemiaStr)
- win.txtImageInformation1.Inlines.Add(Documents.LineBreak())
+ win.txtImageInformation1.Inlines.Add (Documents.Run ("Parasitemia: ", FontWeight = FontWeights.Bold))
+ win.txtImageInformation1.Inlines.Add parasitemiaStr
+ win.txtImageInformation1.Inlines.Add (Documents.LineBreak ())
- win.txtImageInformation1.Inlines.Add(Documents.Run("Last analysis: ", FontWeight = FontWeights.Bold))
- win.txtImageInformation1.Inlines.Add(Documents.Run(if srcImg.dateLastAnalysis.Ticks = 0L then "<Never>" else srcImg.dateLastAnalysis.ToLocalTime().ToString()))
+ win.txtImageInformation1.Inlines.Add (Documents.Run ("Last analysis: ", FontWeight = FontWeights.Bold))
+ win.txtImageInformation1.Inlines.Add (Documents.Run (if srcImg.dateLastAnalysis.Ticks = 0L then "<Never>" else string (srcImg.dateLastAnalysis.ToLocalTime())))
// The right part part.
- win.txtImageInformation2.Inlines.Add(Documents.Run("Added infected erythrocyte: ", FontWeight = FontWeights.Bold))
- win.txtImageInformation2.Inlines.Add(Documents.Run((state.ImageNbManuallyChangedRBCStr srcImg true) + " " + (state.ImageManuallyChangedRBCStr srcImg true)))
- win.txtImageInformation2.Inlines.Add(Documents.LineBreak())
- win.txtImageInformation2.Inlines.Add(Documents.Run("Removed infected erythrocyte: ", FontWeight = FontWeights.Bold))
- win.txtImageInformation2.Inlines.Add(Documents.Run((state.ImageNbManuallyChangedRBCStr srcImg false) + " " + (state.ImageManuallyChangedRBCStr srcImg false)))
+ win.txtImageInformation2.Inlines.Add (Documents.Run ("Added infected erythrocyte: ", FontWeight = FontWeights.Bold))
+ win.txtImageInformation2.Inlines.Add (Documents.Run ((state.ImageNbManuallyChangedRBCStr srcImg true) + " " + (state.ImageManuallyChangedRBCStr srcImg true)))
+ win.txtImageInformation2.Inlines.Add (Documents.LineBreak ())
+ win.txtImageInformation2.Inlines.Add (Documents.Run ("Removed infected erythrocyte: ", FontWeight = FontWeights.Bold))
+ win.txtImageInformation2.Inlines.Add (Documents.Run ((state.ImageNbManuallyChangedRBCStr srcImg false) + " " + (state.ImageManuallyChangedRBCStr srcImg false)))
| _ ->
win.gridImageInformation.Visibility <- Visibility.Hidden
let updateGlobalParasitemia () =
- win.txtGlobalParasitemia.Inlines.Clear()
+ win.txtGlobalParasitemia.Inlines.Clear ()
let total, infected = state.GlobalParasitemia
- win.txtGlobalParasitemia.Inlines.Add(Documents.Run(Utils.percentText (total, infected), FontWeight = FontWeights.Bold))
+ win.txtGlobalParasitemia.Inlines.Add (Documents.Run (Utils.percentText (total, infected), FontWeight = FontWeights.Bold))
if total > 0 && total < warningBelowNumberOfRBC then
- win.txtGlobalParasitemia.Inlines.Add(
- Documents.Run(
+ win.txtGlobalParasitemia.Inlines.Add (
+ Documents.Run (
sprintf " Warning: the number of erythrocytes should be above %d" warningBelowNumberOfRBC,
FontWeight = FontWeights.Bold,
Foreground = Brushes.Red
let marginBottom = previewHeight * (canvasHeight - (win.scrollViewCurrentImage.VerticalOffset - win.borderCurrentImage.BorderThickness.Bottom) - win.scrollViewCurrentImage.ViewportHeight) / canvasHeight - 2.
preview.viewport.Margin <-
- Thickness(
+ Thickness (
marginLeft,
marginTop,
marginRight,
updateGlobalParasitemia ()
and RBCFrame (srcImg : SourceImage) (rbc : RBC) : Views.RBCFrame =
- let frame = RBCFrameFromExisting srcImg rbc (Views.RBCFrame())
- frame.SetValue(Panel.ZIndexProperty, Int32.MaxValue - rbc.num) // To be sure the
- frame.menuRBCSetAsHealthy.Click.AddHandler(fun obj args -> setAsInfected srcImg (frame.Tag :?> RBC) false)
- frame.menuRBCSetAsInfected.Click.AddHandler(fun obj args -> setAsInfected srcImg (frame.Tag :?> RBC) true)
- frame.ContextMenuOpening.AddHandler(
+ let frame = RBCFrameFromExisting srcImg rbc (Views.RBCFrame ())
+ frame.SetValue (Panel.ZIndexProperty, Int32.MaxValue - rbc.num) // To be sure the
+ frame.menuRBCSetAsHealthy.Click.AddHandler (fun obj args -> setAsInfected srcImg (frame.Tag :?> RBC) false)
+ frame.menuRBCSetAsInfected.Click.AddHandler (fun obj args -> setAsInfected srcImg (frame.Tag :?> RBC) true)
+ frame.ContextMenuOpening.AddHandler (
fun obj args ->
if (frame.Tag :?> RBC).infected then
frame.menuRBCSetAsHealthy.Visibility <- Visibility.Visible
frame.menuRBCSetAsHealthy.Visibility <- Visibility.Collapsed
frame.menuRBCSetAsInfected.Visibility <- Visibility.Visible
)
- frame.ContextMenuClosing.AddHandler(fun obj args -> if not frame.IsMouseOver then highlightRBCFrame frame false )
- frame.MouseEnter.AddHandler(fun obj args -> highlightRBCFrame frame true)
- frame.MouseLeave.AddHandler(fun obj args -> if not frame.grid.ContextMenu.IsOpen then highlightRBCFrame frame false)
+ frame.ContextMenuClosing.AddHandler (fun obj args -> if not frame.IsMouseOver then highlightRBCFrame frame false )
+ frame.MouseEnter.AddHandler (fun obj args -> highlightRBCFrame frame true)
+ frame.MouseLeave.AddHandler (fun obj args -> if not frame.grid.ContextMenu.IsOpen then highlightRBCFrame frame false)
frame
and updateRBCFramesPreview () =
RBCFrameFromExisting srcImg rbc (win.stackRBC.Children.[currentPreview] :?> Views.RBCFrame)
else
let f = RBCFrame srcImg rbc
- f.MouseLeftButtonUp.AddHandler(fun obj args -> zoomToRBC (f.Tag :?> RBC))
- win.stackRBC.Children.Add(f) |> ignore
+ f.MouseLeftButtonUp.AddHandler (fun obj args -> zoomToRBC (f.Tag :?> RBC))
+ win.stackRBC.Children.Add f |> ignore
f
currentPreview <- currentPreview + 1
previewInfected.Height <- win.stackRBC.ActualHeight
previewInfected.Width <- win.stackRBC.ActualHeight * rbc.size.Width / rbc.size.Height
- previewInfected.border.Fill <- ImageBrush(BitmapSourceConvert.ToBitmapSource(extractRBCPreview srcImg.img rbc))
+ previewInfected.border.Fill <- ImageBrush (BitmapSourceConvert.ToBitmapSource (extractRBCPreview srcImg.img rbc))
- win.stackRBC.Children.RemoveRange(currentPreview, win.stackRBC.Children.Count - currentPreview)
+ win.stackRBC.Children.RemoveRange (currentPreview, win.stackRBC.Children.Count - currentPreview)
| _ -> ()
updateViewportPreview ()
RBCFrameFromExisting srcImg rbc (win.canvasCurrentImage.Children.[currentCanvas] :?> Views.RBCFrame)
else
let f = RBCFrame srcImg rbc
- win.canvasCurrentImage.Children.Add(f) |> ignore
+ win.canvasCurrentImage.Children.Add f |> ignore
f
currentCanvas <- currentCanvas + 1
- Canvas.SetLeft(frame, rbc.center.X - rbc.size.Width / 2.)
- Canvas.SetTop(frame, rbc.center.Y - rbc.size.Height / 2.)
+ Canvas.SetLeft (frame, rbc.center.X - rbc.size.Width / 2.)
+ Canvas.SetTop (frame, rbc.center.Y - rbc.size.Height / 2.)
for i in currentCanvas .. win.canvasCurrentImage.Children.Count - 1 do
win.canvasCurrentImage.Children.[i].Visibility <- Visibility.Hidden
| _ -> ()
let askDocumentPathToSave () : string option =
- let dialog = SaveFileDialog(AddExtension = true, DefaultExt = PiaZ.extension, Filter = PiaZ.filter)
+ let dialog = SaveFileDialog (AddExtension = true, DefaultExt = PiaZ.extension, Filter = PiaZ.filter)
if state.FilePath <> "" then
dialog.FileName <- FileInfo(state.FilePath).Name
elif state.PatientID <> "" then
dialog.FileName <- state.PatientID + PiaZ.extension
- let res = dialog.ShowDialog()
+ let res = dialog.ShowDialog ()
if res.HasValue && res.Value then
Some dialog.FileName
else
match askDocumentPathToSave () with
| Some filepath ->
state.FilePath <- filepath
- state.Save()
+ state.Save ()
| _ -> ()
else
- state.Save()
+ state.Save ()
updateDocumentStatus ()
displayStatusMessage "Document saved"
with
| :? IOException as ex ->
Log.Error "%O" ex
- MessageBox.Show(sprintf "The document cannot be save in \"%s\"" state.FilePath, "Error saving the document", MessageBoxButton.OK, MessageBoxImage.Error) |> ignore
+ MessageBox.Show (sprintf "The document cannot be save in \"%s\"" state.FilePath, "Error saving the document", MessageBoxButton.OK, MessageBoxImage.Error) |> ignore
let saveCurrentDocumentAsNewFile () =
match askDocumentPathToSave () with
// Ask the use to save the current document if neccessary.
let askSaveCurrent () =
if state.AlteredSinceLastSave then
- match MessageBox.Show("Would you like to save the current document?", "Saving the current document", MessageBoxButton.YesNo, MessageBoxImage.Question) with
+ match MessageBox.Show ("Would you like to save the current document?", "Saving the current document", MessageBoxButton.YesNo, MessageBoxImage.Question) with
| MessageBoxResult.Yes -> saveCurrentDocument ()
| _ -> ()
// Highlight the preview.
win.stackPreviews.Children
|> Seq.cast<Views.ImageSourcePreview>
- |> Seq.iter (fun preview -> preview.border.BorderThickness <- Thickness(if preview.Tag = (srcImg :> Object) then 3. else 0.))
+ |> Seq.iter (fun preview -> preview.border.BorderThickness <- Thickness (if preview.Tag = (srcImg :> Object) then 3. else 0.))
win.canvasCurrentImage.Height <- float srcImg.img.Height
win.canvasCurrentImage.Width <- float srcImg.img.Width
- win.canvasCurrentImage.Background <- ImageBrush(BitmapSourceConvert.ToBitmapSource(srcImg.img))
+ win.canvasCurrentImage.Background <- ImageBrush (BitmapSourceConvert.ToBitmapSource (srcImg.img))
updateRBCFramesCurrent ()
updateRBCFramesPreview ()
| None ->
win.imgLogos.Visibility <- Visibility.Visible
- win.stackRBC.Children.Clear()
- win.canvasCurrentImage.Children.Clear()
+ win.stackRBC.Children.Clear ()
+ win.canvasCurrentImage.Children.Clear ()
win.canvasCurrentImage.Background <- canvasCurrentImageColor
updateCurrentImageInformation ()
updateCurrentImage ()
let addPreview (srcImg : SourceImage) =
- let imgCtrl = Views.ImageSourcePreview(Margin = Thickness(3.))
+ let imgCtrl = Views.ImageSourcePreview (Margin = Thickness 3.)
- imgCtrl.menuRemoveImage.Click.AddHandler(fun obj args ->
- win.stackPreviews.Children.Remove(imgCtrl)
- let srcImg = imgCtrl.Tag :?> SourceImage
- let currentRemoved = Some srcImg = state.CurrentImage
- state.RemoveSourceImage srcImg
- if currentRemoved then
- updateCurrentImage()
+ imgCtrl.menuRemoveImage.Click.AddHandler (
+ fun obj args ->
+ win.stackPreviews.Children.Remove (imgCtrl)
+ let srcImg = imgCtrl.Tag :?> SourceImage
+ let currentRemoved = Some srcImg = state.CurrentImage
+ state.RemoveSourceImage srcImg
+ if currentRemoved then
+ updateCurrentImage ()
- updateGlobalParasitemia()
+ updateGlobalParasitemia ()
- // Update image numbers.
- win.stackPreviews.Children |> Seq.cast<Views.ImageSourcePreview> |> Seq.iter (fun imgPreview -> imgPreview.txtImageNumber.Text <- (imgPreview.Tag :?> SourceImage).num.ToString()))
+ // Update image numbers.
+ win.stackPreviews.Children |> Seq.cast<Views.ImageSourcePreview> |> Seq.iter (fun imgPreview -> imgPreview.txtImageNumber.Text <- (imgPreview.Tag :?> SourceImage).num.ToString ())
+ )
imgCtrl.Tag <- srcImg
- imgCtrl.txtImageNumber.Text <- srcImg.num.ToString()
+ imgCtrl.txtImageNumber.Text <- string srcImg.num
let width = 200
let height = srcImg.img.Height * width / srcImg.img.Width
- imgCtrl.imagePreview.Source <- BitmapSourceConvert.ToBitmapSource(srcImg.img.Resize(width, height, Emgu.CV.CvEnum.Inter.Cubic))
- win.stackPreviews.Children.Add(imgCtrl) |> ignore
+ imgCtrl.imagePreview.Source <- BitmapSourceConvert.ToBitmapSource (srcImg.img.Resize (width, height, Emgu.CV.CvEnum.Inter.Cubic))
+ win.stackPreviews.Children.Add imgCtrl |> ignore
// Zoom to a mouse position into the control 'imgCtrl'.
let zoomTo (mousePos : Point) =
let canvasH = win.canvasCurrentImage.ActualHeight * currentScale
let centerX = (mousePos.X - imgCtrl.BorderThickness.Left) / (imgCtrl.ActualWidth - imgCtrl.BorderThickness.Left) * canvasW
let centerY = (mousePos.Y - imgCtrl.BorderThickness.Top) / (imgCtrl.ActualHeight - imgCtrl.BorderThickness.Top) * canvasH
- win.scrollViewCurrentImage.ScrollToHorizontalOffset(centerX - win.scrollViewCurrentImage.ViewportWidth / 2. + win.borderCurrentImage.BorderThickness.Left)
- win.scrollViewCurrentImage.ScrollToVerticalOffset(centerY - win.scrollViewCurrentImage.ViewportHeight / 2. + win.borderCurrentImage.BorderThickness.Top)
-
- imgCtrl.MouseLeftButtonDown.AddHandler(fun obj args ->
- setCurrentImage (state.SourceImages |> Seq.find (fun srcImg -> (srcImg :> Object) = imgCtrl.Tag))
- imgCtrl.UpdateLayout()
- zoomTo (args.GetPosition(imgCtrl))
- imgCtrl.CaptureMouse() |> ignore
+ win.scrollViewCurrentImage.ScrollToHorizontalOffset (centerX - win.scrollViewCurrentImage.ViewportWidth / 2. + win.borderCurrentImage.BorderThickness.Left)
+ win.scrollViewCurrentImage.ScrollToVerticalOffset (centerY - win.scrollViewCurrentImage.ViewportHeight / 2. + win.borderCurrentImage.BorderThickness.Top)
+
+ imgCtrl.MouseLeftButtonDown.AddHandler (
+ fun obj args ->
+ setCurrentImage (state.SourceImages |> Seq.find (fun srcImg -> (srcImg :> Object) = imgCtrl.Tag))
+ imgCtrl.UpdateLayout ()
+ zoomTo (args.GetPosition (imgCtrl))
+ imgCtrl.CaptureMouse () |> ignore
)
- imgCtrl.MouseMove.AddHandler(fun obj args ->
- if imgCtrl.IsMouseCaptured then
- zoomTo (args.GetPosition(imgCtrl))
+ imgCtrl.MouseMove.AddHandler (
+ fun obj args ->
+ if imgCtrl.IsMouseCaptured then
+ zoomTo (args.GetPosition imgCtrl)
)
- imgCtrl.MouseLeftButtonUp.AddHandler(fun obj args ->
- if imgCtrl.IsMouseCaptured then
- imgCtrl.ReleaseMouseCapture()
+ imgCtrl.MouseLeftButtonUp.AddHandler (
+ fun obj args ->
+ if imgCtrl.IsMouseCaptured then
+ imgCtrl.ReleaseMouseCapture ()
)
let updatePreviews () =
let previousFilePath = state.FilePath
try
state.FilePath <- filepath
- state.Load()
+ state.Load ()
updateGUI ()
with
| :? IOException as ex ->
Log.Error "%O" ex
state.FilePath <- previousFilePath
- MessageBox.Show(sprintf "The document cannot be loaded from \"%s\"" filepath, "Error loading the document", MessageBoxButton.OK, MessageBoxImage.Error) |> ignore
+ MessageBox.Show (sprintf "The document cannot be loaded from \"%s\"" filepath, "Error loading the document", MessageBoxButton.OK, MessageBoxImage.Error) |> ignore
let askLoadFile () =
- let dialog = OpenFileDialog(Filter = PiaZ.filter)
- let res = dialog.ShowDialog()
+ let dialog = OpenFileDialog (Filter = PiaZ.filter)
+ let res = dialog.ShowDialog ()
if res.HasValue && res.Value then
loadFile dialog.FileName
let newFile () =
askSaveCurrent ()
- state.Reset()
- updateGUI()
+ state.Reset ()
+ updateGUI ()
let exportResults () =
let extension = ".txt"
- let dialog = SaveFileDialog(AddExtension = true, DefaultExt = extension)
+ let dialog = SaveFileDialog (AddExtension = true, DefaultExt = extension)
if state.FilePath <> "" then
- dialog.FileName <- Path.GetFileNameWithoutExtension(state.FilePath) + extension
+ dialog.FileName <- Path.GetFileNameWithoutExtension state.FilePath + extension
elif state.PatientID <> "" then
dialog.FileName <- state.PatientID + extension
- let res = dialog.ShowDialog()
+ let res = dialog.ShowDialog ()
if res.HasValue && res.Value then
try
Export.exportResults state dialog.FileName
with
| :? IOException as ex ->
Log.Error "%O" ex
- MessageBox.Show(sprintf "The results cannot be exported in \"%s\"" state.FilePath, "Error exporting the files", MessageBoxButton.OK, MessageBoxImage.Error) |> ignore
+ MessageBox.Show (sprintf "The results cannot be exported in \"%s\"" state.FilePath, "Error exporting the files", MessageBoxButton.OK, MessageBoxImage.Error) |> ignore
let importImage () =
- let dialog = OpenFileDialog(Filter = "Image Files|*.png;*.jpg;*.tif;*.tiff", Multiselect = true)
- let res = dialog.ShowDialog()
+ let dialog = OpenFileDialog (Filter = "Image Files|*.png;*.jpg;*.tif;*.tiff", Multiselect = true)
+ let res = dialog.ShowDialog ()
if res.HasValue && res.Value then
- let noSourceImage = state.SourceImages.Count() = 0
+ let noSourceImage = state.SourceImages.Count () = 0
for filename in dialog.FileNames do
try
with
| _ as ex ->
Log.Error "%O" ex
- MessageBox.Show(sprintf "Unable to read the image from \"%s\"" filename, "Error adding an image", MessageBoxButton.OK, MessageBoxImage.Error) |> ignore
+ MessageBox.Show (sprintf "Unable to read the image from \"%s\"" filename, "Error adding an image", MessageBoxButton.OK, MessageBoxImage.Error) |> ignore
updateGlobalParasitemia ()
updateRBCFramesPreview ()
updateRBCFramesCurrent ()
- win.txtPatient.TextChanged.AddHandler(fun obj args -> state.PatientID <- win.txtPatient.Text)
+ win.txtPatient.TextChanged.AddHandler (fun obj args -> state.PatientID <- win.txtPatient.Text)
- win.menuExit.Click.AddHandler(fun obj args -> win.Close())
- win.menuSave.Click.AddHandler(fun obj args -> saveCurrentDocument ())
- win.menuSaveAs.Click.AddHandler(fun obj args -> saveCurrentDocumentAsNewFile ())
- win.menuOpen.Click.AddHandler(fun obj args -> askLoadFile ())
- win.menuNew.Click.AddHandler(fun obj args -> newFile ())
- win.menuExportResults.Click.AddHandler(fun obj args -> exportResults ())
+ win.menuExit.Click.AddHandler (fun obj args -> win.Close ())
+ win.menuSave.Click.AddHandler (fun obj args -> saveCurrentDocument ())
+ win.menuSaveAs.Click.AddHandler (fun obj args -> saveCurrentDocumentAsNewFile ())
+ win.menuOpen.Click.AddHandler (fun obj args -> askLoadFile ())
+ win.menuNew.Click.AddHandler (fun obj args -> newFile ())
+ win.menuExportResults.Click.AddHandler (fun obj args -> exportResults ())
- win.menuAddSourceImage.Click.AddHandler(fun obj args -> importImage ())
+ win.menuAddSourceImage.Click.AddHandler (fun obj args -> importImage ())
- win.menuAnalysis.SubmenuOpened.AddHandler(fun obj args -> win.menuStartAnalysis.IsEnabled <- state.SourceImages.Count() > 0)
+ win.menuAnalysis.SubmenuOpened.AddHandler (fun obj args -> win.menuStartAnalysis.IsEnabled <- state.SourceImages.Count () > 0)
- win.menuStartAnalysis.Click.AddHandler(fun obj args -> showAnalysisWindow ())
+ win.menuStartAnalysis.Click.AddHandler (fun obj args -> showAnalysisWindow ())
- win.menuHightlightRBC.Click.AddHandler(fun obj args -> setHighlightRBC win.menuHightlightRBC.IsChecked)
+ win.menuHightlightRBC.Click.AddHandler (fun obj args -> setHighlightRBC win.menuHightlightRBC.IsChecked)
- win.menuAbout.Click.AddHandler(fun obj args -> About.showWindow win)
+ win.menuAbout.Click.AddHandler (fun obj args -> About.showWindow win)
- win.Closing.AddHandler(fun obj args -> askSaveCurrent ())
+ win.Closing.AddHandler (fun obj args -> askSaveCurrent ())
// Zoom on the current image.
let adjustCurrentImageBorders (deltaX : float) (deltaY : float) =
win.borderCurrentImage.BorderThickness <-
- Thickness(
+ Thickness (
(win.scrollViewCurrentImage.ViewportWidth + deltaX) / 2.,
(win.scrollViewCurrentImage.ViewportHeight + deltaY) / 2.,
(win.scrollViewCurrentImage.ViewportWidth + deltaX) / 2.,
(win.scrollViewCurrentImage.ViewportHeight + deltaY) / 2.
)
- win.canvasCurrentImage.SizeChanged.AddHandler(fun obj args ->
- let deltaX = args.NewSize.Width - args.PreviousSize.Width
- let deltaY = args.NewSize.Height - args.PreviousSize.Height
- if deltaX > 0.5 || deltaY > 0.5 then
- adjustCurrentImageBorders 0.0 0.0
- // Center the view at the center of the image initialy.
- win.scrollViewCurrentImage.UpdateLayout()
- win.scrollViewCurrentImage.ScrollToHorizontalOffset(win.borderCurrentImage.ActualWidth / 2. - win.scrollViewCurrentImage.ViewportWidth / 2.)
- win.scrollViewCurrentImage.ScrollToVerticalOffset(win.borderCurrentImage.ActualHeight / 2. - win.scrollViewCurrentImage.ViewportHeight / 2.)
+ win.canvasCurrentImage.SizeChanged.AddHandler (
+ fun obj args ->
+ let deltaX = args.NewSize.Width - args.PreviousSize.Width
+ let deltaY = args.NewSize.Height - args.PreviousSize.Height
+ if deltaX > 0.5 || deltaY > 0.5 then
+ adjustCurrentImageBorders 0.0 0.0
+ // Center the view at the center of the image initialy.
+ win.scrollViewCurrentImage.UpdateLayout ()
+ win.scrollViewCurrentImage.ScrollToHorizontalOffset (win.borderCurrentImage.ActualWidth / 2. - win.scrollViewCurrentImage.ViewportWidth / 2.)
+ win.scrollViewCurrentImage.ScrollToVerticalOffset (win.borderCurrentImage.ActualHeight / 2. - win.scrollViewCurrentImage.ViewportHeight / 2.)
)
- win.scrollViewCurrentImage.SizeChanged.AddHandler(fun obj args ->
- let deltaX = args.NewSize.Width - args.PreviousSize.Width
- let deltaY = args.NewSize.Height - args.PreviousSize.Height
- adjustCurrentImageBorders deltaX deltaY
- win.scrollViewCurrentImage.ScrollToHorizontalOffset(win.scrollViewCurrentImage.HorizontalOffset + deltaX / 8.)
- win.scrollViewCurrentImage.ScrollToVerticalOffset(win.scrollViewCurrentImage.VerticalOffset + deltaY / 8.)
+ win.scrollViewCurrentImage.SizeChanged.AddHandler (
+ fun obj args ->
+ let deltaX = args.NewSize.Width - args.PreviousSize.Width
+ let deltaY = args.NewSize.Height - args.PreviousSize.Height
+ adjustCurrentImageBorders deltaX deltaY
+ win.scrollViewCurrentImage.ScrollToHorizontalOffset (win.scrollViewCurrentImage.HorizontalOffset + deltaX / 8.)
+ win.scrollViewCurrentImage.ScrollToVerticalOffset (win.scrollViewCurrentImage.VerticalOffset + deltaY / 8.)
)
let mutable maxScale = 4.
let mutable minScale = 0.25
- let currentImageScaleTransform = ScaleTransform()
+ let currentImageScaleTransform = ScaleTransform ()
win.canvasCurrentImage.LayoutTransform <- currentImageScaleTransform
- win.borderCurrentImage.PreviewMouseWheel.AddHandler(fun obj args ->
- let scaleFactor = if args.Delta > 0 then 2.0 else 0.5
- if scaleFactor > 1. && currentScale < maxScale || scaleFactor < 1. && currentScale > minScale then
- let previousScale = currentScale
- currentScale <-
- let newScale = currentScale * scaleFactor
- if newScale > maxScale then maxScale elif newScale < minScale then minScale else newScale
- let realScaleFactor = currentScale / previousScale
+ win.borderCurrentImage.PreviewMouseWheel.AddHandler (
+ fun obj args ->
+ let scaleFactor = if args.Delta > 0 then 2.0 else 0.5
+ if scaleFactor > 1. && currentScale < maxScale || scaleFactor < 1. && currentScale > minScale then
+ let previousScale = currentScale
+ currentScale <-
+ let newScale = currentScale * scaleFactor
+ if newScale > maxScale then maxScale elif newScale < minScale then minScale else newScale
+ let realScaleFactor = currentScale / previousScale
- let centerX = win.scrollViewCurrentImage.HorizontalOffset + win.scrollViewCurrentImage.ViewportWidth / 2. - win.borderCurrentImage.BorderThickness.Left
- let centerY = win.scrollViewCurrentImage.VerticalOffset + win.scrollViewCurrentImage.ViewportHeight / 2. - win.borderCurrentImage.BorderThickness.Top
+ let centerX = win.scrollViewCurrentImage.HorizontalOffset + win.scrollViewCurrentImage.ViewportWidth / 2. - win.borderCurrentImage.BorderThickness.Left
+ let centerY = win.scrollViewCurrentImage.VerticalOffset + win.scrollViewCurrentImage.ViewportHeight / 2. - win.borderCurrentImage.BorderThickness.Top
- currentImageScaleTransform.ScaleX <- currentScale
- currentImageScaleTransform.ScaleY <- currentScale
+ currentImageScaleTransform.ScaleX <- currentScale
+ currentImageScaleTransform.ScaleY <- currentScale
- win.scrollViewCurrentImage.ScrollToHorizontalOffset(centerX * realScaleFactor - win.scrollViewCurrentImage.ViewportWidth / 2. + win.borderCurrentImage.BorderThickness.Left)
- win.scrollViewCurrentImage.ScrollToVerticalOffset(centerY * realScaleFactor - win.scrollViewCurrentImage.ViewportHeight / 2. + win.borderCurrentImage.BorderThickness.Top)
+ win.scrollViewCurrentImage.ScrollToHorizontalOffset (centerX * realScaleFactor - win.scrollViewCurrentImage.ViewportWidth / 2. + win.borderCurrentImage.BorderThickness.Left)
+ win.scrollViewCurrentImage.ScrollToVerticalOffset (centerY * realScaleFactor - win.scrollViewCurrentImage.ViewportHeight / 2. + win.borderCurrentImage.BorderThickness.Top)
- args.Handled <- true
+ args.Handled <- true
)
// Pan on the current image.
- let mutable scrollStartPosition = Point(0., 0.)
+ let mutable scrollStartPosition = Point (0., 0.)
let mutable scrollStartOffsetX = 0.
let mutable scrollStartOffsetY = 0.
- win.borderCurrentImage.PreviewMouseLeftButtonDown.AddHandler(fun obj args ->
- scrollStartPosition <- args.GetPosition(win.scrollViewCurrentImage)
- scrollStartOffsetX <- win.scrollViewCurrentImage.HorizontalOffset
- scrollStartOffsetY <- win.scrollViewCurrentImage.VerticalOffset
- win.borderCurrentImage.Cursor <- Input.Cursors.ScrollAll
- win.borderCurrentImage.CaptureMouse() |> ignore
- args.Handled <- true
+ win.borderCurrentImage.PreviewMouseLeftButtonDown.AddHandler (
+ fun obj args ->
+ scrollStartPosition <- args.GetPosition win.scrollViewCurrentImage
+ scrollStartOffsetX <- win.scrollViewCurrentImage.HorizontalOffset
+ scrollStartOffsetY <- win.scrollViewCurrentImage.VerticalOffset
+ win.borderCurrentImage.Cursor <- Input.Cursors.ScrollAll
+ win.borderCurrentImage.CaptureMouse () |> ignore
+ args.Handled <- true
)
- win.borderCurrentImage.PreviewMouseMove.AddHandler(fun obj args ->
- if win.borderCurrentImage.IsMouseCaptured then
- let position = args.GetPosition(win.scrollViewCurrentImage)
- let deltaX = scrollStartPosition.X - position.X
- let deltaY = scrollStartPosition.Y - position.Y
- win.scrollViewCurrentImage.ScrollToHorizontalOffset(deltaX + scrollStartOffsetX)
- win.scrollViewCurrentImage.ScrollToVerticalOffset(deltaY + scrollStartOffsetY)
+ win.borderCurrentImage.PreviewMouseMove.AddHandler (
+ fun obj args ->
+ if win.borderCurrentImage.IsMouseCaptured then
+ let position = args.GetPosition win.scrollViewCurrentImage
+ let deltaX = scrollStartPosition.X - position.X
+ let deltaY = scrollStartPosition.Y - position.Y
+ win.scrollViewCurrentImage.ScrollToHorizontalOffset (deltaX + scrollStartOffsetX)
+ win.scrollViewCurrentImage.ScrollToVerticalOffset (deltaY + scrollStartOffsetY)
- args.Handled <- true
+ args.Handled <- true
)
- win.borderCurrentImage.PreviewMouseLeftButtonUp.AddHandler(fun obj args ->
- if win.borderCurrentImage.IsMouseCaptured then
- win.borderCurrentImage.Cursor <- Input.Cursors.Arrow
- win.borderCurrentImage.ReleaseMouseCapture()
- args.Handled <- true
+ win.borderCurrentImage.PreviewMouseLeftButtonUp.AddHandler (
+ fun obj args ->
+ if win.borderCurrentImage.IsMouseCaptured then
+ win.borderCurrentImage.Cursor <- Input.Cursors.Arrow
+ win.borderCurrentImage.ReleaseMouseCapture ()
+ args.Handled <- true
)
// Shortcuts.
// Save.
- win.InputBindings.Add(
- Input.KeyBinding(
- ViewModule.FunCommand((fun obj -> saveCurrentDocument ()), (fun obj -> true)),
- Input.KeyGesture(Input.Key.S, Input.ModifierKeys.Control)
+ win.InputBindings.Add (
+ Input.KeyBinding (
+ ViewModule.FunCommand ((fun obj -> saveCurrentDocument ()), (fun obj -> true)),
+ Input.KeyGesture (Input.Key.S, Input.ModifierKeys.Control)
)
) |> ignore
// Save as.
- win.InputBindings.Add(
- Input.KeyBinding(
- ViewModule.FunCommand((fun obj -> saveCurrentDocumentAsNewFile ()), (fun obj -> true)),
- Input.KeyGesture(Input.Key.S, Input.ModifierKeys.Control ||| Input.ModifierKeys.Shift)
+ win.InputBindings.Add (
+ Input.KeyBinding (
+ ViewModule.FunCommand ((fun obj -> saveCurrentDocumentAsNewFile ()), (fun obj -> true)),
+ Input.KeyGesture (Input.Key.S, Input.ModifierKeys.Control ||| Input.ModifierKeys.Shift)
)
) |> ignore
// Open.
- win.InputBindings.Add(
- Input.KeyBinding(
- ViewModule.FunCommand((fun obj -> askLoadFile ()), (fun obj -> true)),
- Input.KeyGesture(Input.Key.O, Input.ModifierKeys.Control)
+ win.InputBindings.Add (
+ Input.KeyBinding (
+ ViewModule.FunCommand ((fun obj -> askLoadFile ()), (fun obj -> true)),
+ Input.KeyGesture (Input.Key.O, Input.ModifierKeys.Control)
)
) |> ignore
// New file.
- win.InputBindings.Add(
- Input.KeyBinding(
- ViewModule.FunCommand((fun obj -> newFile ()), (fun obj -> true)),
- Input.KeyGesture(Input.Key.N, Input.ModifierKeys.Control)
+ win.InputBindings.Add (
+ Input.KeyBinding (
+ ViewModule.FunCommand ((fun obj -> newFile ()), (fun obj -> true)),
+ Input.KeyGesture (Input.Key.N, Input.ModifierKeys.Control)
)
) |> ignore
// Export results.
- win.InputBindings.Add(
- Input.KeyBinding(
- ViewModule.FunCommand((fun obj -> exportResults ()), (fun obj -> true)),
- Input.KeyGesture(Input.Key.E, Input.ModifierKeys.Control)
+ win.InputBindings.Add (
+ Input.KeyBinding (
+ ViewModule.FunCommand ((fun obj -> exportResults ()), (fun obj -> true)),
+ Input.KeyGesture (Input.Key.E, Input.ModifierKeys.Control)
)
) |> ignore
// Import an image.
- win.InputBindings.Add(
- Input.KeyBinding(
- ViewModule.FunCommand((fun obj -> importImage ()), (fun obj -> true)),
- Input.KeyGesture(Input.Key.A, Input.ModifierKeys.Control)
+ win.InputBindings.Add (
+ Input.KeyBinding (
+ ViewModule.FunCommand ((fun obj -> importImage ()), (fun obj -> true)),
+ Input.KeyGesture (Input.Key.A, Input.ModifierKeys.Control)
)
) |> ignore
// Show analysis dialog.
- win.InputBindings.Add(
- Input.KeyBinding(
- ViewModule.FunCommand((fun obj -> showAnalysisWindow ()), (fun obj -> state.SourceImages.Count() > 0)),
- Input.KeyGesture(Input.Key.Y, Input.ModifierKeys.Control)
+ win.InputBindings.Add (
+ Input.KeyBinding (
+ ViewModule.FunCommand ((fun obj -> showAnalysisWindow ()), (fun obj -> state.SourceImages.Count () > 0)),
+ Input.KeyGesture (Input.Key.Y, Input.ModifierKeys.Control)
)
) |> ignore
// Toggle RBC highlight.
- win.InputBindings.Add(
- Input.KeyBinding(
- ViewModule.FunCommand(
+ win.InputBindings.Add (
+ Input.KeyBinding (
+ ViewModule.FunCommand (
(
fun obj ->
win.menuHightlightRBC.IsChecked <- not win.menuHightlightRBC.IsChecked
),
(fun obj -> true)
),
- Input.KeyGesture(Input.Key.H, Input.ModifierKeys.Control)
+ Input.KeyGesture (Input.Key.H, Input.ModifierKeys.Control)
)
) |> ignore
// Viewport preview.
- win.scrollViewCurrentImage.ScrollChanged.AddHandler(fun obj args -> updateViewportPreview ())
+ win.scrollViewCurrentImage.ScrollChanged.AddHandler (fun obj args -> updateViewportPreview ())
updateDocumentStatus ()
win.gridImageInformation.Visibility <- Visibility.Hidden
- win.Show()
+ win.Show ()
match fileToOpen with
| Some filepath -> loadFile filepath
| None -> ()
- app.Run()
+ app.Run ()
<HintPath>..\packages\EmguCV.3.1.0.1\lib\net30\Emgu.CV.World.dll</HintPath>
</Reference>
<Reference Include="FSharp.Core">
- <HintPath>..\packages\FSharp.Core.4.1.17\lib\net45\FSharp.Core.dll</HintPath>
+ <HintPath>..\packages\FSharp.Core.4.2.1\lib\net45\FSharp.Core.dll</HintPath>
</Reference>
<Reference Include="FSharp.ViewModule">
<HintPath>..\packages\FSharp.ViewModule.Core.1.0.7.0\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\FSharp.ViewModule.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="Newtonsoft.Json">
- <HintPath>..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
+ <HintPath>..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="OpenTK">
<HintPath>..\packages\OpenTK.2.0.0\lib\net20\OpenTK.dll</HintPath>
/// <param name="data"></param>
/// <exception cref="System.IOException">If the file cannot be written</exception>
let save (filePath : string) (data : DocumentData) =
- use file = ZipFile.Open(filePath, ZipArchiveMode.Update)
+ use file = ZipFile.Open (filePath, ZipArchiveMode.Update)
for e in List.ofSeq file.Entries do // 'ofSeq' to not iterate a collection currently modified.
- e.Delete()
+ e.Delete ()
// Main JSON file.
- let mainEntry = file.CreateEntry(mainEntryName, CompressionLevel.Fastest)
- use mainEntryWriter = new StreamWriter(mainEntry.Open())
- mainEntryWriter.Write(JsonConvert.SerializeObject({ patientID = data.patientID; fileVersion = currentFileVersion }))
+ let mainEntry = file.CreateEntry (mainEntryName, CompressionLevel.Fastest)
+ use mainEntryWriter = new StreamWriter (mainEntry.Open ())
+ mainEntryWriter.Write (JsonConvert.SerializeObject ({ patientID = data.patientID; fileVersion = currentFileVersion }))
// Write each images and the associated information.
for srcImg in data.images do
let imgFilename = (string srcImg.num) + imageExtension
- let imgEntry = file.CreateEntry(imgFilename, CompressionLevel.NoCompression) // FIXME: It seems a compression is applied to this file despite of the 'NoCompression' flag.
- srcImg.img.ToBitmap().Save(imgEntry.Open(), System.Drawing.Imaging.ImageFormat.Tiff)
+ let imgEntry = file.CreateEntry (imgFilename, CompressionLevel.NoCompression) // FIXME: It seems a compression is applied to this file despite of the 'NoCompression' flag.
+ srcImg.img.ToBitmap().Save (imgEntry.Open (), System.Drawing.Imaging.ImageFormat.Tiff)
- let imgJSONEntry = file.CreateEntry(imgFilename + ".json", CompressionLevel.Fastest)
- use imgJSONFileWriter = new StreamWriter(imgJSONEntry.Open())
- imgJSONFileWriter.Write(
- JsonConvert.SerializeObject(
+ let imgJSONEntry = file.CreateEntry (imgFilename + ".json", CompressionLevel.Fastest)
+ use imgJSONFileWriter = new StreamWriter (imgJSONEntry.Open ())
+ imgJSONFileWriter.Write (
+ JsonConvert.SerializeObject (
{
num = srcImg.num
name = srcImg.name
/// <param name="filePath"></param>
/// <exception cref="System.IOException">If the file cannot be read</exception>
let load (filePath : string) (defaultConfig : ParasitemiaCore.Config.Config) : DocumentData =
- use file = ZipFile.Open(filePath, ZipArchiveMode.Read)
+ use file = ZipFile.Open (filePath, ZipArchiveMode.Read)
- let mainEntry = file.GetEntry(mainEntryName)
- use mainEntryReader = new StreamReader(mainEntry.Open())
- let info = JsonConvert.DeserializeObject<JSONInformation>(mainEntryReader.ReadToEnd())
+ let mainEntry = file.GetEntry (mainEntryName)
+ use mainEntryReader = new StreamReader (mainEntry.Open ())
+ let info = JsonConvert.DeserializeObject<JSONInformation> (mainEntryReader.ReadToEnd ())
updateDocumentData info.fileVersion currentFileVersion
{
[
let mutable imgNum = 0
for imgEntry in file.Entries do
- if imgEntry.Name.EndsWith(imageExtension) then
- use bitmap = new System.Drawing.Bitmap(imgEntry.Open(), false)
- let img = new Image<Bgr, byte>(bitmap)
+ if imgEntry.Name.EndsWith (imageExtension) then
+ use bitmap = new System.Drawing.Bitmap (imgEntry.Open (), false)
+ let img = new Image<Bgr, byte> (bitmap)
imgNum <- imgNum + 1
- let imgJSONEntry = file.GetEntry(imgEntry.Name + ".json")
- use imgJSONFileReader = new StreamReader(imgJSONEntry.Open())
- let imgInfo = JsonConvert.DeserializeObject<JSONSourceImage>(imgJSONFileReader.ReadToEnd())
+ let imgJSONEntry = file.GetEntry (imgEntry.Name + ".json")
+ use imgJSONFileReader = new StreamReader (imgJSONEntry.Open ())
+ let imgInfo = JsonConvert.DeserializeObject<JSONSourceImage> (imgJSONFileReader.ReadToEnd ())
- let config = defaultConfig.Copy()
+ let config = defaultConfig.Copy ()
config.Parameters <-
{
ParasitemiaCore.Config.defaultParameters 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 (if args.Length > 0 && not (args.[0].StartsWith("--")) then Some args.[0] else None)
+ Window (if args.Length > 0 && not (args.[0].StartsWith ("--")) then Some args.[0] else None)
runningMode, Array.exists ((=) "--debug") args
printfn " <document-file> : a PIAZ file to automatically open at startup"
printfn " --debug : output information like intermediate images if set in the current directory"
-[<System.Runtime.InteropServices.DllImport("kernel32.dll")>]
-extern bool AttachConsole(int dwProcessId)
+[<System.Runtime.InteropServices.DllImport "kernel32.dll">]
+extern bool AttachConsole (int dwProcessId)
[<EntryPoint>]
-[<STAThread()>]
+[<STAThread ()>]
let main args =
// To redirect stdout to the attached console.
- AttachConsole(-1) |> ignore // -1 to attach to the parent process.
+ AttachConsole -1 |> ignore // -1 to attach to the parent process.
if Array.exists (fun e -> e = "--help" || e = "-h") args then
showArgsHelp ()
let result =
match parseArgs args with
| mode, debug ->
- let config = Config(defaultParameters)
+ let config = Config defaultParameters
match mode with
| CmdLine (input, output) ->
Directory.CreateDirectory output |> ignore
- use logFile = new StreamWriter(new FileStream(Path.Combine(output, "log.txt"), FileMode.Append, FileAccess.Write))
- let listener = { new IListener with member this.NewEntry severity header mess = logFile.WriteLine(header + " : " + mess) }
- Log.AddListener(listener)
+ use logFile = new StreamWriter (new FileStream (Path.Combine(output, "log.txt"), FileMode.Append, FileAccess.Write))
+ let listener = { new IListener with member this.NewEntry severity header mess = logFile.WriteLine (header + " : " + mess) }
+ Log.AddListener listener
Log.Info "=== New run : %O %s ===" DateTime.Now (if debug then "[DEBUG]" else "[RELEASE]")
| 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))
-
- let images = [ for file in files -> Path.GetFileNameWithoutExtension(FileInfo(file).Name), config.Copy(), new Image<Bgr, byte>(file) ]
-
- Log.LogWithTime Severity.INFO (fun () ->
- match ParasitemiaCore.Analysis.doMultipleAnalysis images None with
- | Some results ->
- for id, cells in results do
- let config, img = images |> List.pick (fun (id', config', img') -> if id' = id then Some (config', img') else None)
- img.Dispose()
- let total, infected = countCells cells
- fprintf resultFile "File: %s %d %d %.2f (diameter: %O)\n" id total infected (100. * (float infected) / (float total)) config.RBCRadius
- | None ->
- fprintf resultFile "Analysis aborted"
- Some ()) "Whole analyze" |> ignore
-
- Log.RmListener(listener)
+ use resultFile = new StreamWriter (new FileStream (Path.Combine (output, "results.txt"), FileMode.Append, FileAccess.Write))
+
+ let images = [ for file in files -> Path.GetFileNameWithoutExtension (FileInfo(file).Name), config.Copy(), new Image<Bgr, byte> (file) ]
+
+ Log.LogWithTime Severity.INFO (
+ fun () ->
+ match ParasitemiaCore.Analysis.doMultipleAnalysis images None with
+ | Some results ->
+ for id, cells in results do
+ let config, img = images |> List.pick (fun (id', config', img') -> if id' = id then Some (config', img') else None)
+ img.Dispose ()
+ let total, infected = countCells cells
+ fprintf resultFile "File: %s %d %d %.2f (diameter: %O)\n" id total infected (100. * (float infected) / (float total)) config.RBCRadius
+ | None ->
+ fprintf resultFile "Analysis aborted"
+ Some ()
+ ) "Whole analyze" |> ignore
+
+ Log.RmListener (listener)
0
| Window fileToOpen ->
open Types
type State (defaultConfig : ParasitemiaCore.Config.Config) =
- let sourceImages = List<SourceImage>()
+ let sourceImages = List<SourceImage> ()
let mutable alteredSinceLastSave = false
let mutable patientID = ""
member this.Load () =
let data = PiaZ.load this.FilePath defaultConfig
this.PatientID <- data.patientID
- sourceImages.Clear()
- sourceImages.InsertRange(0, data.images)
+ sourceImages.Clear ()
+ sourceImages.InsertRange (0, data.images)
this.CurrentImage <- if sourceImages.Count > 0 then Some sourceImages.[0] else None
alteredSinceLastSave <- false
{
num = sourceImages.Count + 1
name = System.IO.FileInfo(filePath).Name
- config = defaultConfig.Copy()
- dateLastAnalysis = DateTime(0L)
+ config = defaultConfig.Copy ()
+ dateLastAnalysis = DateTime (0L)
rbcs = []
- img = new Image<Bgr, byte>(filePath)
+ img = new Image<Bgr, byte> (filePath)
healthyRBCBrightness = 1.f
infectedRBCBrightness = 1.f
}
- sourceImages.Add(srcImg)
+ sourceImages.Add srcImg
if sourceImages.Count = 1 then
this.CurrentImage <- Some sourceImages.[0]
alteredSinceLastSave <- true
| Some srcImg' -> srcImg = srcImg'
| _ -> false
- if sourceImages.Remove(srcImg) then
+ if sourceImages.Remove srcImg then
alteredSinceLastSave <- true
if isCurrent then
this.CurrentImage <- if sourceImages.Count > 0 then Some sourceImages.[0] else None
alteredSinceLastSave <- true
member this.SetResult (imgNum : int) (cells : ParasitemiaCore.Types.Cell list) =
- let sourceImage = sourceImages.Find(fun srcImg -> srcImg.num = imgNum)
+ let sourceImage = sourceImages.Find (fun srcImg -> srcImg.num = imgNum)
let w = sourceImage.img.Width
let h = sourceImage.img.Height
let manuallyAlteredPreviousRBCS = sourceImage.rbcs |> List.filter (fun rbc -> rbc.setManually)
let tolerance = (float sourceImage.config.RBCRadius.Pixel) * 0.5 // +/-.
let getPreviousManuallyAlteredRBC (center : Point) : RBC option =
- manuallyAlteredPreviousRBCS |> List.tryFind (fun rbc -> rbc.center.X > center.X - tolerance && rbc.center.X < center.X + tolerance &&
- rbc.center.Y > center.Y - tolerance && rbc.center.Y < center.Y + tolerance)
+ manuallyAlteredPreviousRBCS
+ |> List.tryFind (
+ fun rbc ->
+ rbc.center.X > center.X - tolerance &&
+ rbc.center.X < center.X + tolerance &&
+ rbc.center.Y > center.Y - tolerance &&
+ rbc.center.Y < center.Y + tolerance
+ )
sourceImage.rbcs <-
cells
|> List.sortByDescending (fun cell -> cell.nucleusArea, (w - cell.center.X) + (h - cell.center.Y))
|> List.mapi (
fun i cell ->
- let center = Point(float cell.center.X, float cell.center.Y)
+ let center = Point (float cell.center.X, float cell.center.Y)
let infected, setManually =
let infected = cell.cellClass = ParasitemiaCore.Types.InfectedRBC
match getPreviousManuallyAlteredRBC center with
infected = infected
setManually = setManually
center = center
- size = Size(float cell.elements.Width, float cell.elements.Height)
+ size = Size (float cell.elements.Width, float cell.elements.Height)
infectedArea = cell.nucleusArea
}
)
this.PatientID <- ""
this.FilePath <- ""
this.CurrentImage <- None
- sourceImages.Clear()
+ sourceImages.Clear ()
alteredSinceLastSave <- false
\ No newline at end of file
open ParasitemiaCore.UnitsOfMeasure
-let healthyRBColor = Color.FromRgb(255uy, 255uy, 0uy) // Yellow-green.
-let infectedRBColor = Color.FromRgb(255uy, 0uy, 40uy) // Red with a bit of blue.
+let healthyRBColor = Color.FromRgb (255uy, 255uy, 0uy) // Yellow-green.
+let infectedRBColor = Color.FromRgb (255uy, 0uy, 40uy) // Red with a bit of blue.
type RBC =
{
member this.HealthyRBCColor : SolidColorBrush =
let mutable color = healthyRBColor * this.healthyRBCBrightness
color.A <- 255uy
- SolidColorBrush(color)
+ SolidColorBrush (color)
member this.InfectedRBCColor : SolidColorBrush =
let mutable color = infectedRBColor * this.infectedRBCBrightness
color.A <- 255uy
- SolidColorBrush(color)
+ SolidColorBrush (color)
type PredefinedPPI =
{
label : string
}
with
- override this.ToString() =
+ override this.ToString () =
sprintf "%s: %d" this.label this.ppi
type SensorSize =
open Types
-let listAsStr (s : 'a seq) =
- s |> Seq.fold (fun acc obj -> acc + (if acc = "" then "" else ", ") + obj.ToString()) ""
+let inline listAsStr (s : 'a seq) =
+ s |> Seq.fold (fun acc obj -> acc + (if acc = "" then "" else ", ") + string obj) ""
let percentText (nbTotal : int, nb : int) : string =
if nbTotal = 0 then
sprintf "%.1f %% (%d / %d)" percent nb nbTotal
let roamingDir =
- Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), "Parasitemia")
+ Path.Combine (System.Environment.GetFolderPath (System.Environment.SpecialFolder.ApplicationData), "Parasitemia")
let predefinedPPIFilename = "predefined-ppi.json"
-let predefinedPPIFilepath = Path.Combine(roamingDir, predefinedPPIFilename)
+let predefinedPPIFilepath = Path.Combine (roamingDir, predefinedPPIFilename)
let sensorSizesFilename = "sensor-sizes.json"
-let sensorSizesFilepath = Path.Combine(roamingDir, sensorSizesFilename)
+let sensorSizesFilepath = Path.Combine (roamingDir, sensorSizesFilename)
let private savePredefinedPPIToFile (predefinedPPI : PredefinedPPI list) =
try
- use file = new StreamWriter(predefinedPPIFilepath)
- file.Write(JsonConvert.SerializeObject(predefinedPPI, JsonSerializerSettings(Formatting = Formatting.Indented)))
+ use file = new StreamWriter (predefinedPPIFilepath)
+ file.Write (JsonConvert.SerializeObject (predefinedPPI, JsonSerializerSettings (Formatting = Formatting.Indented)))
with
ex ->
Logger.Log.Error "Unable to save predefined PPI to file \"%s\": %O" predefinedPPIFilepath ex
let private saveSensorSizesToFile (sensorSizes : SensorSize list) =
try
- use file = new StreamWriter(sensorSizesFilepath)
- file.Write(JsonConvert.SerializeObject(sensorSizes, JsonSerializerSettings(Formatting = Formatting.Indented)))
+ use file = new StreamWriter (sensorSizesFilepath)
+ file.Write (JsonConvert.SerializeObject (sensorSizes, JsonSerializerSettings (Formatting = Formatting.Indented)))
with
ex ->
Logger.Log.Error "Unable to save sensor sizes to file \"%s\": %O" sensorSizesFilepath ex
let predefinedPPI : PredefinedPPI list =
try
- use file = new StreamReader(predefinedPPIFilepath)
- JsonConvert.DeserializeObject<PredefinedPPI list>(file.ReadToEnd())
+ use file = new StreamReader (predefinedPPIFilepath)
+ JsonConvert.DeserializeObject<PredefinedPPI list> (file.ReadToEnd ())
with
| ex ->
savePredefinedPPIToFile defaultPredefinedPPI
let sensorSizes : SensorSize list =
try
- use file = new StreamReader(sensorSizesFilepath)
- JsonConvert.DeserializeObject<SensorSize list>(file.ReadToEnd())
+ use file = new StreamReader (sensorSizesFilepath)
+ JsonConvert.DeserializeObject<SensorSize list> (file.ReadToEnd ())
with
| ex ->
saveSensorSizesToFile defaultSensorSizes
<packages>
<package id="EmguCV" version="3.1.0.1" targetFramework="net452" />
<package id="Expression.Blend.Sdk" version="1.0.2" targetFramework="net46" />
- <package id="FSharp.Core" version="4.1.17" targetFramework="net452" />
+ <package id="FSharp.Core" version="4.2.1" targetFramework="net452" />
<package id="FSharp.ViewModule.Core" version="1.0.7.0" targetFramework="net462" />
<package id="FsXaml.Wpf" version="3.1.6" targetFramework="net462" />
- <package id="Newtonsoft.Json" version="10.0.2" targetFramework="net452" />
+ <package id="Newtonsoft.Json" version="10.0.3" targetFramework="net452" />
<package id="OpenTK" version="2.0.0" targetFramework="net452" />
<package id="OpenTK.GLControl" version="1.1.2349.61993" targetFramework="net452" />
<package id="System.ValueTuple" version="4.3.1" targetFramework="net452" />
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
-[<assembly: AssemblyTitle("ParasitemiaCore.Tests")>]
-[<assembly: AssemblyDescription("")>]
-[<assembly: AssemblyConfiguration("")>]
-[<assembly: AssemblyCompany("HES-SO / CHUV / Grégory Burri")>]
-[<assembly: AssemblyProduct("ParasitemiaCore.Tests")>]
-[<assembly: AssemblyCopyright("Copyright © 2015-2016")>]
-[<assembly: AssemblyTrademark("")>]
-[<assembly: AssemblyCulture("")>]
+[<assembly: AssemblyTitle "ParasitemiaCore.Tests">]
+[<assembly: AssemblyDescription "">]
+[<assembly: AssemblyConfiguration "">]
+[<assembly: AssemblyCompany "HES-SO / CHUV / Grégory Burri">]
+[<assembly: AssemblyProduct "ParasitemiaCore.Tests">]
+[<assembly: AssemblyCopyright "Copyright © 2015-2016">]
+[<assembly: AssemblyTrademark "">]
+[<assembly: AssemblyCulture "">]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
-[<assembly: ComVisible(false)>]
+[<assembly: ComVisible false>]
// The following GUID is for the ID of the typelib if this project is exposed to COM
-[<assembly: Guid("0f8a85f4-9328-40c3-b8ff-44fb39ceb01f")>]
+[<assembly: Guid "0f8a85f4-9328-40c3-b8ff-44fb39ceb01f">]
// Version information for an assembly consists of the following four values:
//
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-// [<assembly: AssemblyVersion("1.0.*")>]
-[<assembly: AssemblyVersion("1.0.0.0")>]
-[<assembly: AssemblyFileVersion("1.0.0.0")>]
+// [<assembly: AssemblyVersion "1.0.*">]
+[<assembly: AssemblyVersion "1.0.0.0">]
+[<assembly: AssemblyFileVersion "1.0.0.0">]
-[<assembly: InternalsVisibleTo("ParasitemiaCore.Tests")>]
+[<assembly: InternalsVisibleTo "ParasitemiaCore.Tests">]
do
()
\ No newline at end of file
member this.test () =
let pts =
[
- Point(1.0f, 1.0f)
- Point(2.0f, 2.0f)
- Point(1.5f, 3.6f)
- Point(3.0f, 3.2f)
- Point(4.0f, 4.0f)
- Point(3.5f, 1.5f)
- Point(2.5f, 0.5f)
+ Point (1.0f, 1.0f)
+ Point (2.0f, 2.0f)
+ Point (1.5f, 3.6f)
+ Point (3.0f, 3.2f)
+ Point (4.0f, 4.0f)
+ Point (3.5f, 1.5f)
+ Point (2.5f, 0.5f)
]
let tree = Tree.BuildTree pts
member this.test2 () =
let pts =
[
- Point(1.0f, 1.0f)
- Point(1.0f, 2.0f)
- Point(1.0f, 3.0f)
+ Point (1.0f, 1.0f)
+ Point (1.0f, 2.0f)
+ Point (1.0f, 3.0f)
]
let tree = Tree.BuildTree pts
</ItemGroup>
<ItemGroup>
<Reference Include="FSharp.Core">
- <HintPath>..\packages\FSharp.Core.4.1.17\lib\net45\FSharp.Core.dll</HintPath>
+ <HintPath>..\..\packages\FSharp.Core.4.2.1\lib\net45\FSharp.Core.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="FSharp.Core" version="4.1.17" targetFramework="net452" />
+ <package id="FSharp.Core" version="4.2.1" targetFramework="net452" />
<package id="System.ValueTuple" version="4.3.1" targetFramework="net452" />
<package id="xunit" version="2.2.0" targetFramework="net452" />
<package id="xunit.abstractions" version="2.0.1" targetFramework="net452" />