[<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("")>]
// 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
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.
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
let μmToInch(x: float<μm>) : float<inch> = x / μmInchRatio
let inchToμm(x: float<inch>) : float<μm> = x * μmInchRatio
-
-
-
-
// 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
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
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
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>
(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
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
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
updateRBCFramesCurrent ()
updateRBCFramesPreview ()
+
| None ->
imgLogos.Visibility <- Visibility.Visible
+
stackRBC.Children.Clear()
canvasCurrentImage.Children.Clear()
canvasCurrentImage.Background <- canvasCurrentImageColor
| Some filepath -> loadFile filepath
| None -> ()
- app.Run()
\ No newline at end of file
+ app.Run()
<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" />
// Information associated to a document.
type JSONInformation = {
patientID: string
+ fileVersion: int
}
// Information associated to each images.
parameters: ParasitemiaCore.Config.Parameters
dateLastAnalysis: DateTime
rbcs: RBC List
+
+ healthyRBCBrightness: float32 // 0 to 1.
+ infectedRBCBrightness: float32 // 0 to 1.
}
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.
// 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
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.
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
/// </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]
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
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
<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>