Add an option to change the brightness of the highlight box color (healthy/infected...
authorGreg Burri <greg.burri@gmail.com>
Thu, 21 Jan 2016 12:50:59 +0000 (13:50 +0100)
committerGreg Burri <greg.burri@gmail.com>
Thu, 21 Jan 2016 12:50:59 +0000 (13:50 +0100)
Parasitemia/ParasitemiaCore/AssemblyInfo.fs
Parasitemia/ParasitemiaCore/Types.fs
Parasitemia/ParasitemiaCore/UnitsOfMeasure.fs
Parasitemia/ParasitemiaUI/AssemblyInfo.fs
Parasitemia/ParasitemiaUI/GUI.fs
Parasitemia/ParasitemiaUI/ParasitemiaUI.fsproj
Parasitemia/ParasitemiaUI/PiaZ.fs
Parasitemia/ParasitemiaUI/State.fs
Parasitemia/ParasitemiaUI/Types.fs
Parasitemia/ParasitemiaUI/XAML/MainWindow.xaml

index 268f060..89d76f0 100644 (file)
@@ -10,9 +10,9 @@ open System.Runtime.InteropServices
 [<assembly: AssemblyTitle("ParasitemiaCore")>]
 [<assembly: AssemblyDescription("")>]
 [<assembly: AssemblyConfiguration("")>]
-[<assembly: AssemblyCompany("")>]
+[<assembly: AssemblyCompany("HES-SO / CHUV / Grégory Burri")>]
 [<assembly: AssemblyProduct("ParasitemiaCore")>]
-[<assembly: AssemblyCopyright("Copyright © 2016")>]
+[<assembly: AssemblyCopyright("Copyright © 2015-2016")>]
 [<assembly: AssemblyTrademark("")>]
 [<assembly: AssemblyCulture("")>]
 
@@ -34,8 +34,8 @@ open System.Runtime.InteropServices
 // 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.1")>]
-[<assembly: AssemblyFileVersion("1.0.0.1")>]
+[<assembly: AssemblyVersion("1.0.0.3")>]
+[<assembly: AssemblyFileVersion("1.0.0.3")>]
 
 do
     ()
\ No newline at end of file
index e2accb7..7bfbd7f 100644 (file)
@@ -35,7 +35,7 @@ type Ellipse (cx: float32, cy: float32, a: float32, b: float32, alpha: float32)
         this.CutAVericalLine 0.f || this.CutAVericalLine width ||
         this.CutAnHorizontalLine 0.f || this.CutAnHorizontalLine height
 
-    member this.Scale (factor: float32) =
+    member this.Scale (factor: float32) : Ellipse =
         Ellipse(this.Cx, this.Cy, this.A * factor, this.B * factor, alpha)
 
     // Approximation of Ramanujan.
@@ -68,8 +68,10 @@ type MaybeBuilder () =
     member this.ReturnFrom (x) = x
 
     member this.TryFinally (body, compensation) =
-        try this.ReturnFrom(body())
-        finally compensation()
+        try
+            this.ReturnFrom(body())
+        finally
+            compensation()
 
     member this.Using (disposable: 'a when 'a :> IDisposable, body) =
         let body' = fun () -> body disposable
index 81ce51f..0d84d16 100644 (file)
@@ -10,7 +10,3 @@ let μmInchRatio = 25.4e3<μm/inch>
 let μmToInch(x: float<μm>) : float<inch> = x / μmInchRatio
 let inchToμm(x: float<inch>) : float<μm> = x * μmInchRatio
 
-
-
-
-
index 16cfbfc..004f87f 100644 (file)
@@ -34,8 +34,8 @@ open System.Runtime.InteropServices
 // 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.2")>]
-[<assembly: AssemblyFileVersion("1.0.0.2")>]
+[<assembly: AssemblyVersion("1.0.0.3")>]
+[<assembly: AssemblyFileVersion("1.0.0.3")>]
 
 do
     ()
\ No newline at end of file
index a71aa96..2ff3116 100644 (file)
@@ -24,9 +24,6 @@ let run (defaultConfig: Config) (fileToOpen: string option) =
     let mainWindow = Views.MainWindow()
     let ctrl (name: string): 'a = mainWindow.Root.FindName(name) :?> 'a
 
-    let colorRBCHealthy = Brushes.YellowGreen
-    let colorRBCInfected = Brushes.Red
-
     let state = State.State()
     let mutable currentScale = 1.
     let mutable displayHealthy = false
@@ -78,19 +75,19 @@ let run (defaultConfig: Config) (fileToOpen: string option) =
                                                 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 (rbc: RBC) (frame: Views.RBCFrame) =
+    let setRBCFrameStyle (srcImg: SourceImage) (rbc: RBC) (frame: Views.RBCFrame) =
         frame.Opacity <- if displayHealthy || rbc.setManually || rbc.infected then 1. else 0.
-        let color = if rbc.infected then colorRBCInfected else colorRBCHealthy
+        let color = if rbc.infected then srcImg.InfectedRBCColor else srcImg.HealthyRBCColor
         frame.manuallyAdded.Visibility <- if rbc.setManually then Visibility.Visible else Visibility.Hidden
         frame.manuallyAdded.Fill <- color
         frame.border.Stroke <- color
 
-    let RBCFrameFromExisting (rbc: RBC) (frame: Views.RBCFrame) : Views.RBCFrame =
+    let RBCFrameFromExisting (srcImg: SourceImage) (rbc: RBC) (frame: Views.RBCFrame) : Views.RBCFrame =
         frame.Visibility <- Visibility.Visible
         frame.Height <- rbc.size.Height
         frame.Width <- rbc.size.Width
         frame.Tag <- rbc
-        setRBCFrameStyle rbc frame
+        setRBCFrameStyle srcImg rbc frame
         frame.border.StrokeThickness <- 1.
         frame.txtRBCNumber.Text <- rbc.num.ToString()
         frame
@@ -179,7 +176,7 @@ let run (defaultConfig: Config) (fileToOpen: string option) =
             else
                 preview.viewport.Visibility <- Visibility.Hidden
 
-    let rec setAsInfected (rbc: RBC) (infected: bool) =
+    let rec setAsInfected (srcImg: SourceImage) (rbc: RBC) (infected: bool) =
         state.SetAsInfected rbc infected
         canvasCurrentImage.Children
         |> Seq.cast<Views.RBCFrame>
@@ -187,16 +184,16 @@ let run (defaultConfig: Config) (fileToOpen: string option) =
             (fun frame ->
                 if (frame.Tag :?> RBC) = rbc
                 then
-                    setRBCFrameStyle rbc frame)
+                    setRBCFrameStyle srcImg rbc frame)
         updateRBCFramesPreview ()
         updateCurrentImageInformation ()
         updateGlobalParasitemia ()
 
-    and RBCFrame (rbc: RBC) : Views.RBCFrame =
-        let frame = RBCFrameFromExisting rbc (Views.RBCFrame())
+    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 (frame.Tag :?> RBC) false)
-        frame.menuRBCSetAsInfected.Click.AddHandler(fun obj args -> setAsInfected (frame.Tag :?> RBC) true)
+        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
@@ -220,9 +217,9 @@ let run (defaultConfig: Config) (fileToOpen: string option) =
                 let previewInfected =
                     if currentPreview < stackRBC.Children.Count
                     then
-                        RBCFrameFromExisting rbc (stackRBC.Children.[currentPreview] :?> Views.RBCFrame)
+                        RBCFrameFromExisting srcImg rbc (stackRBC.Children.[currentPreview] :?> Views.RBCFrame)
                     else
-                        let f = RBCFrame rbc
+                        let f = RBCFrame srcImg rbc
                         f.MouseLeftButtonUp.AddHandler(fun obj args -> zoomToRBC (f.Tag :?> RBC))
                         stackRBC.Children.Add(f) |> ignore
                         f
@@ -246,9 +243,9 @@ let run (defaultConfig: Config) (fileToOpen: string option) =
                 let frame =
                     if currentCanvas < canvasCurrentImage.Children.Count
                     then
-                        RBCFrameFromExisting rbc (canvasCurrentImage.Children.[currentCanvas] :?> Views.RBCFrame)
+                        RBCFrameFromExisting srcImg rbc (canvasCurrentImage.Children.[currentCanvas] :?> Views.RBCFrame)
                     else
-                        let f = RBCFrame rbc
+                        let f = RBCFrame srcImg rbc
                         f.Root.Opacity <- 0.7
                         canvasCurrentImage.Children.Add(f) |> ignore
                         f
@@ -327,8 +324,10 @@ let run (defaultConfig: Config) (fileToOpen: string option) =
 
             updateRBCFramesCurrent ()
             updateRBCFramesPreview ()
+
         | None ->
             imgLogos.Visibility <- Visibility.Visible
+
             stackRBC.Children.Clear()
             canvasCurrentImage.Children.Clear()
             canvasCurrentImage.Background <- canvasCurrentImageColor
@@ -591,4 +590,4 @@ let run (defaultConfig: Config) (fileToOpen: string option) =
     | Some filepath -> loadFile filepath
     | None -> ()
 
-    app.Run()
\ No newline at end of file
+    app.Run()
index 483888f..0859274 100644 (file)
@@ -68,6 +68,7 @@
     <Resource Include="Resources\chuv_logo.png" />
     <Resource Include="Resources\hes-so_logo.png" />
     <Resource Include="Resources\icon.ico" />
+    <Resource Include="Resources\p5-type5-tiling.png" />
     <Resource Include="XAML\NumericUpDown.xaml" />
     <Compile Include="XAML\NumericUpDown.xaml.fs" />
     <Resource Include="XAML\ImageSourcePreview.xaml" />
index d4ea46f..c9dfd5b 100644 (file)
@@ -20,6 +20,7 @@ let filter = "PIA|*.piaz"
 // Information associated to a document.
 type JSONInformation = {
     patientID: string
+    fileVersion: int
 }
 
 // Information associated to each images.
@@ -29,6 +30,9 @@ type JSONSourceImage = {
     parameters: ParasitemiaCore.Config.Parameters
     dateLastAnalysis: DateTime
     rbcs: RBC List
+
+    healthyRBCBrightness: float32 // 0 to 1.
+    infectedRBCBrightness: float32 // 0 to 1.
 }
 
 type DocumentData = {
@@ -38,6 +42,7 @@ type DocumentData = {
 
 let mainEntryName = "info.json"
 let imageExtension = ".tiff"
+let currentFileVersion = 1
 
 /// <summary>
 /// Save a document in a give file path. The file may already exist.
@@ -54,7 +59,7 @@ let save (filePath: string) (data: DocumentData) =
     // Main JSON file.
     let mainEntry = file.CreateEntry(mainEntryName, CompressionLevel.Fastest)
     use mainEntryWriter = new StreamWriter(mainEntry.Open())
-    mainEntryWriter.Write(JsonConvert.SerializeObject({ JSONInformation.patientID = data.patientID }))
+    mainEntryWriter.Write(JsonConvert.SerializeObject({ patientID = data.patientID; fileVersion = currentFileVersion }))
 
     // Write each images and the associated information.
     for srcImg in data.images do
@@ -64,7 +69,23 @@ let save (filePath: string) (data: DocumentData) =
 
         let imgJSONEntry = file.CreateEntry(imgFilename + ".json", CompressionLevel.Fastest)
         use imgJSONFileWriter = new StreamWriter(imgJSONEntry.Open())
-        imgJSONFileWriter.Write(JsonConvert.SerializeObject({ num = srcImg.num; RBCRadius = srcImg.config.RBCRadius.Pixel; parameters = srcImg.config.Parameters; dateLastAnalysis = srcImg.dateLastAnalysis; rbcs = srcImg.rbcs }))
+        imgJSONFileWriter.Write(
+            JsonConvert.SerializeObject(
+                { num = srcImg.num
+                  RBCRadius = srcImg.config.RBCRadius.Pixel
+                  parameters = srcImg.config.Parameters
+                  dateLastAnalysis = srcImg.dateLastAnalysis
+                  rbcs = srcImg.rbcs
+                  healthyRBCBrightness = srcImg.healthyRBCBrightness
+                  infectedRBCBrightness = srcImg.infectedRBCBrightness }))
+
+let updateDocumentData (fromVersion: int) (toVersion: int) (data: DocumentData) : DocumentData =
+    for v in fromVersion + 1 .. toVersion do
+        match v with
+        | 1 -> // Version 0 -> 1 : set initial brightness for rbc.
+            data.images |> List.iter (fun i -> i.healthyRBCBrightness <- 1.f; i.infectedRBCBrightness <- 1.f)
+        | _ -> ()
+    data
 
 /// <summary>
 /// Load document from a give file path.
@@ -78,20 +99,24 @@ let load (filePath: string) : DocumentData =
     use mainEntryReader = new StreamReader(mainEntry.Open())
     let info = JsonConvert.DeserializeObject<JSONInformation>(mainEntryReader.ReadToEnd())
 
-    { patientID = info.patientID
-      images = [ let mutable imgNum = 0
-                 for imgEntry in file.Entries do
-                    if imgEntry.Name.EndsWith(imageExtension)
-                    then
-                        let img = new Image<Bgr, byte>(new System.Drawing.Bitmap(imgEntry.Open(), false)) // FIXME: Should we dispose the bitmap?
-                        imgNum <- imgNum + 1
-                        let imgEntry = file.GetEntry(imgEntry.Name + ".json")
-                        use imgEntryFileReader = new StreamReader(imgEntry.Open())
-                        let imgInfo = JsonConvert.DeserializeObject<JSONSourceImage>(imgEntryFileReader.ReadToEnd())
-                        let config = ParasitemiaCore.Config.Config(imgInfo.parameters)
-                        config.SetRBCRadius imgInfo.RBCRadius
-                        yield { num = imgNum
-                                config = config
-                                dateLastAnalysis = imgInfo.dateLastAnalysis
-                                img = img
-                                rbcs = imgInfo.rbcs } ] }
\ No newline at end of file
+    updateDocumentData info.fileVersion currentFileVersion
+        { patientID = info.patientID
+          images = [ 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)
+                            imgNum <- imgNum + 1
+                            let imgEntry = file.GetEntry(imgEntry.Name + ".json")
+                            use imgEntryFileReader = new StreamReader(imgEntry.Open())
+                            let imgInfo = JsonConvert.DeserializeObject<JSONSourceImage>(imgEntryFileReader.ReadToEnd())
+                            let config = ParasitemiaCore.Config.Config(imgInfo.parameters)
+                            config.SetRBCRadius imgInfo.RBCRadius
+                            yield { num = imgNum
+                                    config = config
+                                    dateLastAnalysis = imgInfo.dateLastAnalysis
+                                    img = img
+                                    rbcs = imgInfo.rbcs
+                                    healthyRBCBrightness = imgInfo.healthyRBCBrightness
+                                    infectedRBCBrightness = imgInfo.infectedRBCBrightness } ] }
\ No newline at end of file
index f133640..63b9bbf 100644 (file)
@@ -73,7 +73,15 @@ type State () =
     /// </summary>
     /// <exception cref="System.IOException">If the image cannot be read</exception>
     member this.AddSourceImage (filePath: string) (defaultConfig: ParasitemiaCore.Config.Config) : SourceImage =
-        let srcImg = { num = sourceImages.Count + 1; config = defaultConfig.Copy(); dateLastAnalysis = DateTime(0L); rbcs = []; img = new Image<Bgr, byte>(filePath) }
+        let srcImg =
+            { num = sourceImages.Count + 1
+              config = defaultConfig.Copy()
+              dateLastAnalysis = DateTime(0L)
+              rbcs = []
+              img = new Image<Bgr, byte>(filePath)
+              healthyRBCBrightness = 1.f
+              infectedRBCBrightness = 1.f }
+
         sourceImages.Add(srcImg)
         if sourceImages.Count = 1
         then this.CurrentImage <- Some sourceImages.[0]
index 7d80294..5de71e6 100644 (file)
@@ -2,10 +2,14 @@
 
 open System
 open System.Windows
+open System.Windows.Media
 
 open Emgu.CV
 open Emgu.CV.Structure
 
+let healthyRBColor = Color.FromRgb(255uy, 255uy, 0uy) // Yellow-green.
+let infectedRBColor = Color.FromRgb(255uy, 0uy, 40uy) // Red with a bit of blue.
+
 type RBC = {
     num: int
 
@@ -21,4 +25,17 @@ type SourceImage = {
     mutable config: ParasitemiaCore.Config.Config
     mutable dateLastAnalysis: DateTime // UTC.
     img: Image<Bgr, byte>
-    mutable rbcs: RBC list }
\ No newline at end of file
+    mutable rbcs: RBC list
+
+    mutable healthyRBCBrightness: float32
+    mutable infectedRBCBrightness: float32 } with
+
+    member this.HealthyRBCColor: SolidColorBrush =
+        let mutable color = healthyRBColor * this.healthyRBCBrightness
+        color.A <- 255uy;
+        SolidColorBrush(color)
+
+    member this.InfectedRBCColor: SolidColorBrush =
+        let mutable color = infectedRBColor * this.infectedRBCBrightness
+        color.A <- 255uy;
+        SolidColorBrush(color)
\ No newline at end of file
index 2b43c86..e763bea 100644 (file)
@@ -70,7 +70,7 @@
                <RowDefinition/>
                <RowDefinition Height="Auto"/>
             </Grid.RowDefinitions>
-            <ScrollViewer x:Name="scrollViewCurrentImage" Grid.Row="1" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible" Background="#FF535353" MinHeight="100" MinWidth="100">
+            <ScrollViewer x:Name="scrollViewCurrentImage" Grid.Row="1" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible" MinHeight="100" MinWidth="100" Background="#FF3E3E3E">
                <Border x:Name="borderCurrentImage" BorderBrush="Transparent">
                   <Canvas x:Name="canvasCurrentImage" Height="100" Width="100" />
                </Border>