open Config
open Types
+let warningRatioDifferenceRBCDiameter = 1.2
+
/// <summary>
/// Analyze the given image and detect reb blood cell (RBC) in it.
/// </summary>
/// The first call returning 'false' will cancel the analysis.
/// The 'int' parameter correspond to the progression from 0 to 100</param>
/// <returns>A list of detected cells or nothing if the process has been cancelled</returns>
-let doAnalysis (img : Image<Bgr, byte>) (name : string) (config : Config) (reportProgress : (int -> bool) option) : Cell list option =
+let doAnalysis (img : Image<Bgr, byte>) (name : string) (config : Config) (reportProgress : (int -> bool) option) : AnalysisResult option =
// To report the progress of this function from 0 to 100.
// Return 'None' if the process must be aborted.
let! cells = logTimeWithName "Classifier" (fun () -> reportWithVal 100 (Classifier.findCells prunedEllipses parasites img.Width img.Height config))
+ do
+ if config.RBCRadiusByResolution.μm / config.RBCRadius.μm > warningRatioDifferenceRBCDiameter then
+ logWithName (sprintf "Warning: erythrocyte diameter found is too low compared to the nominal erythrocyte diameter, maybe the PPI image resolution is lesser than %.0f ppi" config.Parameters.resolution)
+ elif config.RBCRadius.μm / config.RBCRadiusByResolution.μm > warningRatioDifferenceRBCDiameter then
+ logWithName (sprintf "Warning: erythrocyte diameter found is too high compared to the nominal erythrocyte diameter, maybe the PPI image resolution is higher than %.0f" config.Parameters.resolution)
+
logWithName "Analysis finished"
do
IO.saveImg img_float.[0] (buildFileName " - source - blue.png")
| _ -> ()
- return cells
+ return
+ {
+ Cells = cells
+ RBCSize_μm = config.RBCRadius.μm
+ RBCSize_px = config.RBCRadius.Pixel
+ }
+
+ //return cells
}
/// <summary>
/// The first call returning 'false' will cancel the analysis.
/// The 'int' parameter correspond to the progression from 0 to 100</param>
/// <returns>'None' if the process has been cancelled or the list of result as (name * cells), 'name' corresponds to the given name<returns>
-let doMultipleAnalysis (imgs : (string * Config * Image<Bgr, byte>) list) (reportProgress : (int -> bool) option) : (string * Cell list) list option =
+let doMultipleAnalysis (imgs : (string * Config * Image<Bgr, byte>) list) (reportProgress : (int -> bool) option) : (string * AnalysisResult) list option =
let report (percent : int) : bool =
match reportProgress with
| Some f -> f percent
// 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.0.12">]
+[<assembly: AssemblyFileVersion "1.0.0.12">]
do
()
\ No newline at end of file
<Private>True</Private>
</Reference>
<Reference Include="FSharp.Core">
- <HintPath>..\packages\FSharp.Core.4.2.1\lib\net45\FSharp.Core.dll</HintPath>
+ <HintPath>..\packages\FSharp.Core.4.2.3\lib\net45\FSharp.Core.dll</HintPath>
</Reference>
<Reference Include="MathNet.Numerics">
- <HintPath>..\packages\MathNet.Numerics.3.19.0\lib\net40\MathNet.Numerics.dll</HintPath>
+ <HintPath>..\packages\MathNet.Numerics.3.20.0\lib\net40\MathNet.Numerics.dll</HintPath>
</Reference>
<Reference Include="MathNet.Numerics.FSharp">
- <HintPath>..\packages\MathNet.Numerics.FSharp.3.19.0\lib\net40\MathNet.Numerics.FSharp.dll</HintPath>
+ <HintPath>..\packages\MathNet.Numerics.FSharp.3.20.0\lib\net40\MathNet.Numerics.FSharp.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="OpenTK">
<Reference Include="System.Drawing" />
<Reference Include="System.Numerics" />
<Reference Include="System.ValueTuple">
- <HintPath>..\packages\System.ValueTuple.4.3.1\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
+ <HintPath>..\packages\System.ValueTuple.4.4.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
open Emgu.CV.Structure
open Const
+open UnitsOfMeasure
type Points = HashSet<Point>
member this.ReturnFrom (x) = x
-let result = ResultBuilder ()
\ No newline at end of file
+let result = ResultBuilder ()
+
+type AnalysisResult =
+ {
+ Cells : Cell list
+ RBCSize_μm : float<μm>
+ RBCSize_px : float32
+ }
\ No newline at end of file
<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.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="FSharp.Core" version="4.2.3" targetFramework="net452" />
+ <package id="MathNet.Numerics" version="3.20.0" targetFramework="net452" />
+ <package id="MathNet.Numerics.FSharp" version="3.20.0" 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" />
+ <package id="System.ValueTuple" version="4.4.0" targetFramework="net452" />
<package id="ZedGraph" version="5.1.7" targetFramework="net452" />
</packages>
\ No newline at end of file
let imageSourceSelection = Views.ImageSourceSelection (Tag = srcImg, Margin = Thickness 3.)
imageSourceSelection.Tag <- srcImg
- 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 string srcImg.dateLastAnalysis
+ 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 string srcImg.DateLastAnalysis
- imageSourceSelection.txtResolution.Text <- if srcImg.dateLastAnalysis.Ticks = 0L then "" else string srcImg.config.Parameters.resolution
+ imageSourceSelection.txtResolution.Text <- if srcImg.DateLastAnalysis.Ticks = 0L then "" else string srcImg.Config.Parameters.resolution
for ppi in Utils.predefinedPPI do
let menu = MenuItem ()
let isChecked = srcImgCtrl.chkSelection.IsChecked
match parseAndValidatePPI srcImgCtrl.txtResolution.Text with
| Some resolution ->
- yield Some (srcImg, isChecked.HasValue && isChecked.Value, { srcImg.config.Parameters with resolution = resolution * 1.<ppi> })
+ 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
let imagesToProcess =
[
for srcImg, selected, parameters in imagesParameters do
- srcImg.config.Parameters <- parameters // Save parameters.
+ srcImg.Config.Parameters <- parameters // Save parameters.
if selected then
- yield string srcImg.num, srcImg.config, srcImg.img
+ yield string srcImg.Num, srcImg.Config, srcImg.Img
]
if imagesToProcess.IsEmpty then
win.stackSourceImagesSelection.IsEnabled <- false
analysisPerformed <- false
win.butStart.IsEnabled <- false
+ win.textLog.Text <- ""
win.butClose.Content <- "Abort"
async {
// 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.0.12">]
+[<assembly: AssemblyFileVersion "1.0.0.12">]
do
()
\ No newline at end of file
--- /dev/null
+module ParasitemiaUI.CommandLineArguments
+
+open System
+open System.Windows
+open System.Windows.Controls
+open System.Diagnostics
+
+let showWindow (parent : Window) =
+ let win = Views.CommandLineArgumentsWindow ()
+ 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.
+
+ win.txtCommandLineArguments.Text <- Utils.argsHelp
+
+ win.butClose.Click.AddHandler (fun obj args -> win.Close ())
+
+ win.ShowDialog () |> ignore
+
for srcImg in state.SourceImages do
fprintfn writer ""
- fprintfn writer "Image name: %s" srcImg.name
- fprintfn writer "Parasitemia: %s" (Utils.percentText (state.ImageParasitemia srcImg))
- fprintfn writer "Added infected erythrocyte: %s %s" (state.ImageNbManuallyChangedRBCStr srcImg true) (state.ImageManuallyChangedRBCStr srcImg true)
- fprintfn writer "Removed infected erythrocyte: %s %s" (state.ImageNbManuallyChangedRBCStr srcImg false) (state.ImageManuallyChangedRBCStr srcImg false)
+ fprintfn writer "Image name: %s" srcImg.Name
+ fprintfn writer "Parasitemia: %s" (Utils.percentText srcImg.ImageParasitemia)
+ fprintfn writer "Added infected erythrocyte: %s %s" (srcImg.ImageNbManuallyChangedRBCStr true) (srcImg.ImageManuallyChangedRBCStr true)
+ fprintfn writer "Removed infected erythrocyte: %s %s" (srcImg.ImageNbManuallyChangedRBCStr false) (srcImg.ImageManuallyChangedRBCStr false)
()
\ No newline at end of file
frame.manuallyAdded.Fill <- color
frame.border.Stroke <- color
- let RBCFrameFromExisting (srcImg : SourceImage) (rbc : RBC) (frame : Views.RBCFrame) : Views.RBCFrame =
+ let frameStrokeThickness (averageRBCSize : float) =
+ max 1. (averageRBCSize / 60.)
+
+ let frameFontSize (averageRBCSize : float) =
+ max 1. (averageRBCSize / 8.)
+
+ let RBCFrameFromExisting (srcImg : SourceImage) (rbc : RBC) (frame : Views.RBCFrame) (frameThickness : float) (fontSize : float) : Views.RBCFrame =
frame.Visibility <- Visibility.Visible
- frame.Height <- rbc.size.Height
frame.Width <- rbc.size.Width
+ frame.Height <- rbc.size.Height
frame.Tag <- rbc
setRBCFrameStyle srcImg rbc frame
- frame.border.StrokeThickness <- 1.
+ frame.border.StrokeThickness <- frameThickness
frame.txtRBCNumber.Text <- string rbc.num
+ frame.txtRBCNumber.FontSize <- fontSize
frame
let updateDocumentStatus () =
let statusMessageTimer = Threading.DispatcherTimer ()
statusMessageTimer.Tick.AddHandler (fun obj args -> statusMessageTimer.Stop (); win.txtMessageStatus.Text <- "")
statusMessageTimer.Interval <- TimeSpan (0, 0, 2)
+
+ // To show a use message while a short period of time.
let displayStatusMessage (message : string) =
win.txtMessageStatus.Text <- message
statusMessageTimer.Stop ()
let highlightRBCFrame (frame : Views.RBCFrame) (highlight : bool) =
let rbc = frame.Tag :?> RBC
if highlight then
- frame.border.StrokeThickness <- 3.
+ frame.border.StrokeThickness <- 3. * frame.border.StrokeThickness
if not rbc.infected && not rbc.setManually && not displayHealthy then frame.Opacity <- 1.
else
- frame.border.StrokeThickness <- 1.
+ frame.border.StrokeThickness <- frame.border.StrokeThickness / 3.
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)
-
let txtImageName_TextChanged =
TextChangedEventHandler (fun obj args -> state.CurrentImage |> Option.iter (fun srcImg -> state.SetName srcImg win.txtImageName.Text))
match state.CurrentImage with
| Some srcImg ->
win.gridImageInformation.Visibility <- Visibility.Visible
- win.txtImageName.Text <- srcImg.name
+ win.txtImageName.Text <- srcImg.Name
win.txtImageName.TextChanged.AddHandler txtImageName_TextChanged
// The left part.
- let parasitemiaStr = Utils.percentText (state.ImageParasitemia srcImg)
+ let parasitemiaStr = Utils.percentText srcImg.ImageParasitemia
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 string (srcImg.dateLastAnalysis.ToLocalTime())))
+ 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.Run ((srcImg.ImageNbManuallyChangedRBCStr true) + " " + (srcImg.ImageManuallyChangedRBCStr 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 ((srcImg.ImageNbManuallyChangedRBCStr false) + " " + (srcImg.ImageManuallyChangedRBCStr false)))
| _ ->
win.gridImageInformation.Visibility <- Visibility.Hidden
updateCurrentImageInformation ()
updateGlobalParasitemia ()
- and RBCFrame (srcImg : SourceImage) (rbc : RBC) : Views.RBCFrame =
- let frame = RBCFrameFromExisting srcImg rbc (Views.RBCFrame ())
+ and RBCFrame (srcImg : SourceImage) (rbc : RBC) (frameThickness : float) (fontSize : float) : Views.RBCFrame =
+ let frame = RBCFrameFromExisting srcImg rbc (Views.RBCFrame ()) frameThickness fontSize
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)
match state.CurrentImage with
| Some srcImg ->
let mutable currentPreview = 0
- for rbc in srcImg.rbcs |> List.filter (fun rbc -> displayHealthy || rbc.infected) do
+ for rbc in srcImg.RBCs |> List.filter (fun rbc -> displayHealthy || rbc.infected) do
let previewInfected =
if currentPreview < win.stackRBC.Children.Count then
- RBCFrameFromExisting srcImg rbc (win.stackRBC.Children.[currentPreview] :?> Views.RBCFrame)
+ RBCFrameFromExisting srcImg rbc (win.stackRBC.Children.[currentPreview] :?> Views.RBCFrame) 1. 12.
else
- let f = RBCFrame srcImg rbc
+ let f = RBCFrame srcImg rbc 1. 12.
f.MouseLeftButtonUp.AddHandler (fun obj args -> zoomToRBC (f.Tag :?> RBC))
win.stackRBC.Children.Add f |> ignore
f
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)
| _ -> ()
match state.CurrentImage with
| Some srcImg ->
let mutable currentCanvas = 0
- for rbc in srcImg.rbcs do
+ let strokeThickness = frameStrokeThickness srcImg.AverageRBCSize
+ let fontSize = frameFontSize srcImg.AverageRBCSize
+ for rbc in srcImg.RBCs do
let frame =
if currentCanvas < win.canvasCurrentImage.Children.Count then
- RBCFrameFromExisting srcImg rbc (win.canvasCurrentImage.Children.[currentCanvas] :?> Views.RBCFrame)
+ RBCFrameFromExisting srcImg rbc (win.canvasCurrentImage.Children.[currentCanvas] :?> Views.RBCFrame) strokeThickness fontSize
else
- let f = RBCFrame srcImg rbc
+ let f = RBCFrame srcImg rbc strokeThickness fontSize
win.canvasCurrentImage.Children.Add f |> ignore
f
|> Seq.cast<Views.ImageSourcePreview>
|> 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.Height <- float srcImg.Img.Height
+ win.canvasCurrentImage.Width <- float srcImg.Img.Width
+ win.canvasCurrentImage.Background <- ImageBrush (BitmapSourceConvert.ToBitmapSource (srcImg.Img))
updateRBCFramesCurrent ()
updateRBCFramesPreview ()
updateGlobalParasitemia ()
// Update image numbers.
- win.stackPreviews.Children |> Seq.cast<Views.ImageSourcePreview> |> Seq.iter (fun imgPreview -> imgPreview.txtImageNumber.Text <- (imgPreview.Tag :?> SourceImage).num.ToString ())
+ 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 <- string srcImg.num
+ 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))
+ 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
// Zoom to a mouse position into the control 'imgCtrl'.
win.menuAbout.Click.AddHandler (fun obj args -> About.showWindow win)
+ win.menuCommandLineArguments.Click.AddHandler (fun obj args -> CommandLineArguments.showWindow win)
+
win.Closing.AddHandler (fun obj args -> askSaveCurrent ())
// Zoom on the current image.
let currentImageScaleTransform = ScaleTransform ()
win.canvasCurrentImage.LayoutTransform <- currentImageScaleTransform
win.borderCurrentImage.PreviewMouseWheel.AddHandler (
- fun obj args ->
+ 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
let mutable scrollStartOffsetX = 0.
let mutable scrollStartOffsetY = 0.
win.borderCurrentImage.PreviewMouseLeftButtonDown.AddHandler (
- fun obj args ->
+ fun _obj args ->
scrollStartPosition <- args.GetPosition win.scrollViewCurrentImage
scrollStartOffsetX <- win.scrollViewCurrentImage.HorizontalOffset
scrollStartOffsetY <- win.scrollViewCurrentImage.VerticalOffset
)
win.borderCurrentImage.PreviewMouseMove.AddHandler (
- fun obj args ->
+ fun _obj args ->
if win.borderCurrentImage.IsMouseCaptured then
let position = args.GetPosition win.scrollViewCurrentImage
let deltaX = scrollStartPosition.X - position.X
)
win.borderCurrentImage.PreviewMouseLeftButtonUp.AddHandler (
- fun obj args ->
+ fun _obj args ->
if win.borderCurrentImage.IsMouseCaptured then
win.borderCurrentImage.Cursor <- Input.Cursors.Arrow
win.borderCurrentImage.ReleaseMouseCapture ()
<Compile Include="XAML\PPICalculatorWindow.xaml.fs" />
<Resource Include="XAML\AnalysisWindow.xaml" />
<Compile Include="XAML\AnalysisWindow.xaml.fs" />
+ <Resource Include="XAML\CommandLineArgumentsWindow.xaml" />
+ <Compile Include="XAML\CommandLineArgumentsWindow.xaml.fs" />
<Resource Include="XAML\AboutWindow.xaml" />
<Compile Include="XAML\AboutWindow.xaml.fs" />
<Resource Include="XAML\MainWindow.xaml" />
<Compile Include="XAML\MainWindow.xaml.fs" />
<Compile Include="Types.fs" />
<Compile Include="Utils.fs" />
+ <Compile Include="SourceImage.fs" />
<Compile Include="PiaZ.fs" />
<Compile Include="State.fs" />
<Compile Include="Export.fs" />
<Compile Include="DPICalculator.fs" />
<Compile Include="Analysis.fs" />
+ <Compile Include="CommandLineArguments.fs" />
<Compile Include="About.fs" />
<Compile Include="GUI.fs" />
<None Include="App.config" />
<HintPath>..\packages\EmguCV.3.1.0.1\lib\net30\Emgu.CV.World.dll</HintPath>
</Reference>
<Reference Include="FSharp.Core">
- <HintPath>..\packages\FSharp.Core.4.2.1\lib\net45\FSharp.Core.dll</HintPath>
+ <HintPath>..\packages\FSharp.Core.4.2.3\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 Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Numerics" />
<Reference Include="System.ValueTuple">
- <HintPath>..\packages\System.ValueTuple.4.3.1\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
+ <HintPath>..\packages\System.ValueTuple.4.4.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Windows.Interactivity">
// Write each images and the associated information.
for srcImg in data.images do
- let imgFilename = (string srcImg.num) + imageExtension
+ 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)
+ 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 (
{
- num = srcImg.num
- name = srcImg.name
- RBCRadius = srcImg.config.RBCRadius.Pixel
- parameters = srcImg.config.Parameters
- dateLastAnalysis = srcImg.dateLastAnalysis
- rbcs = srcImg.rbcs
- healthyRBCBrightness = srcImg.healthyRBCBrightness
- infectedRBCBrightness = srcImg.infectedRBCBrightness
+ num = srcImg.Num
+ name = srcImg.Name
+ RBCRadius = srcImg.Config.RBCRadius.Pixel
+ parameters = srcImg.Config.Parameters
+ dateLastAnalysis = srcImg.DateLastAnalysis
+ rbcs = srcImg.RBCs
+ healthyRBCBrightness = srcImg.HealthyRBCBrightness
+ infectedRBCBrightness = srcImg.InfectedRBCBrightness
}
)
)
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.images |> List.iter (fun i -> i.HealthyRBCBrightness <- 1.f; i.InfectedRBCBrightness <- 1.f)
| _ -> ()
data
}
config.SetRBCRadius imgInfo.RBCRadius
- yield
- {
- num = imgNum
- name = imgInfo.name
- config = config
- dateLastAnalysis = imgInfo.dateLastAnalysis
- img = img
- rbcs = imgInfo.rbcs
- healthyRBCBrightness = imgInfo.healthyRBCBrightness
- infectedRBCBrightness = imgInfo.infectedRBCBrightness
- }
+
+ yield SourceImage (imgNum, imgInfo.name, config, imgInfo.dateLastAnalysis, img, imgInfo.rbcs, HealthyRBCBrightness = imgInfo.healthyRBCBrightness, InfectedRBCBrightness = imgInfo.infectedRBCBrightness)
]
}
\ No newline at end of file
| CmdLine of Input * string // A file or a directory to process and the output directory.
| Window of string option // An optional path to a file to open can be given in window mode.
-type Arguments = RunningMode * bool
+type Arguments = RunningMode * bool // bool : true if in debug mode.
let parseArgs (args : string[]) : Arguments =
runningMode, Array.exists ((=) "--debug") args
let showArgsHelp () =
- printfn "Usage of Parasitemia :"
- printfn "Non-interactive mode:"
- printfn " %s (--folder <folder>|--file <file>) --output <folder> [--debug]" System.AppDomain.CurrentDomain.FriendlyName
- printfn " --folder <folder> : an input folder containing images to analyze"
- printfn " --file <file> : an image file to be analyzed"
- printfn " --output <folder> : a folder to put the results"
- printfn " --debug : output more information like intermediate images if set"
-
- printfn "Interactive mode:"
- printfn " %s [<document-file>] [--debug]" System.AppDomain.CurrentDomain.FriendlyName
- printfn " <document-file> : a PIAZ file to automatically open at startup"
- printfn " --debug : output information like intermediate images if set in the current directory"
+ Console.WriteLine Utils.argsHelp
[<System.Runtime.InteropServices.DllImport "kernel32.dll">]
extern bool AttachConsole (int dwProcessId)
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) ]
+ 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
+ for id, result 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
+ let total, infected = countCells result.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)
+ Log.RmListener listener
0
| Window fileToOpen ->
--- /dev/null
+namespace ParasitemiaUI
+
+open System
+open System.Windows
+open System.Windows.Media
+
+open Emgu.CV
+open Emgu.CV.Structure
+
+open Types
+
+type SourceImage (num : int, name : string, config : ParasitemiaCore.Config.Config, dateLastAnalysis : DateTime, img : Image<Bgr, byte>, rbcs : RBC list) =
+ let mutable num = num
+ let mutable name = name
+ let mutable config = config
+ let mutable dateLastAnalysis = dateLastAnalysis // UTC.
+ let img = img
+ let mutable rbcs = rbcs
+ let mutable healthyRBCBrightness = 1.f
+ let mutable infectedRBCBrightness = 1.f
+
+ let mutable averageRBCSize = 1.
+
+ let healthyRBColor = Color.FromRgb (255uy, 255uy, 0uy) // Yellow-green.
+ let infectedRBColor = Color.FromRgb (255uy, 0uy, 40uy) // Red with a bit of blue.
+
+ let updateAverageRBCSize () =
+ averageRBCSize <-
+ rbcs
+ |> List.collect (fun rbc -> [ rbc.size.Width; rbc.size.Height ])
+ |> List.average
+
+ do
+ updateAverageRBCSize ()
+
+ member this.Num with get () = num and set value = num <- value
+
+ member this.Name with get () = name and set value = name <- value
+
+ member this.Config = config
+
+ member this.DateLastAnalysis with get () = dateLastAnalysis and set value = dateLastAnalysis <- value
+
+ member this.Img = img
+
+ member this.RBCs
+ with get () = rbcs
+ and set value = rbcs <- value
+
+ member this.ImageParasitemia : int * int =
+ List.length rbcs,
+ rbcs |> List.fold (fun nbInfected rbc -> if rbc.infected then nbInfected + 1 else nbInfected) 0
+
+ member this.ImageNbManuallyChangedRBC (setAsInfected : bool) : int * int =
+ List.length rbcs,
+ rbcs |> List.fold (fun nb rbc -> if rbc.setManually && rbc.infected = setAsInfected then nb + 1 else nb) 0
+
+ member this.ImageNbManuallyChangedRBCStr (setAsInfected : bool) : string =
+ Utils.percentText (this.ImageNbManuallyChangedRBC setAsInfected)
+
+ member this.ImageManuallyChangedRBC (setAsInfected : bool) : int seq =
+ query {
+ for rbc in rbcs do
+ where (rbc.setManually && rbc.infected = setAsInfected)
+ select rbc.num
+ }
+
+ member this.ImageManuallyChangedRBCStr (setAsInfected : bool) : string =
+ let listStr = Utils.listAsStr <| this.ImageManuallyChangedRBC setAsInfected
+ if listStr = "" then
+ ""
+ else
+ "[" + listStr + "]"
+
+ member this.HealthyRBCBrightness with get () = healthyRBCBrightness and set value = healthyRBCBrightness <- value
+ member this.InfectedRBCBrightness with get () = infectedRBCBrightness and set value = infectedRBCBrightness <- value
+
+ member this.HealthyRBCColor : SolidColorBrush =
+ let mutable color = healthyRBColor * healthyRBCBrightness
+ color.A <- 255uy
+ SolidColorBrush (color)
+
+ member this.InfectedRBCColor : SolidColorBrush =
+ let mutable color = infectedRBColor * infectedRBCBrightness
+ color.A <- 255uy
+ SolidColorBrush (color)
+
+ member this.AverageRBCSize = averageRBCSize
\ No newline at end of file
alteredSinceLastSave <- true
patientID <- id
- member this.ImageParasitemia (srcImg : SourceImage) : int * int =
- List.length srcImg.rbcs,
- srcImg.rbcs |> List.fold (fun nbInfected rbc -> if rbc.infected then nbInfected + 1 else nbInfected) 0
-
- member this.ImageNbManuallyChangedRBC (srcImg : SourceImage) (setAsInfected : bool) : int * int =
- List.length srcImg.rbcs,
- srcImg.rbcs |> List.fold (fun nb rbc -> if rbc.setManually && rbc.infected = setAsInfected then nb + 1 else nb) 0
-
- member this.ImageNbManuallyChangedRBCStr (srcImg : SourceImage) (setAsInfected : bool) : string =
- Utils.percentText (this.ImageNbManuallyChangedRBC srcImg setAsInfected)
-
- member this.ImageManuallyChangedRBC (srcImg : SourceImage) (setAsInfected : bool) : int seq =
- query {
- for rbc in srcImg.rbcs do
- where (rbc.setManually && rbc.infected = setAsInfected)
- select rbc.num
- }
-
- member this.ImageManuallyChangedRBCStr (srcImg : SourceImage) (setAsInfected : bool) : string =
- let listStr = Utils.listAsStr <| this.ImageManuallyChangedRBC srcImg setAsInfected
- if listStr = "" then
- ""
- else
- "[" + listStr + "]"
-
member this.GlobalParasitemia : int * int =
sourceImages
|> Seq.fold (
fun (nbTotal, nbTotalInfected) srcImg ->
- let nb, nbInfected = this.ImageParasitemia srcImg
+ let nb, nbInfected = srcImg.ImageParasitemia
nbTotal + nb, nbTotalInfected + nbInfected
) (0, 0)
/// </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
- name = System.IO.FileInfo(filePath).Name
- config = defaultConfig.Copy ()
- dateLastAnalysis = DateTime (0L)
- rbcs = []
- img = new Image<Bgr, byte> (filePath)
- healthyRBCBrightness = 1.f
- infectedRBCBrightness = 1.f
- }
-
+ let srcImg = SourceImage (sourceImages.Count + 1, System.IO.FileInfo(filePath).Name, defaultConfig.Copy (), DateTime (0L), new Image<Bgr, byte> (filePath), [])
sourceImages.Add srcImg
if sourceImages.Count = 1 then
this.CurrentImage <- Some sourceImages.[0]
if isCurrent then
this.CurrentImage <- if sourceImages.Count > 0 then Some sourceImages.[0] else None
// Re-numbered the images.
- sourceImages |> Seq.iteri (fun i srcImg -> srcImg.num <- i + 1)
+ sourceImages |> Seq.iteri (fun i srcImg -> srcImg.Num <- i + 1)
member this.SetName (srcImg : SourceImage) (name : string) =
- if name <> srcImg.name then
- srcImg.name <- name
+ if name <> srcImg.Name then
+ srcImg.Name <- name
alteredSinceLastSave <- true
- member this.SetResult (imgNum : int) (cells : ParasitemiaCore.Types.Cell list) =
- let sourceImage = sourceImages.Find (fun srcImg -> srcImg.num = imgNum)
+ member this.SetResult (imgNum : int) (result : ParasitemiaCore.Types.AnalysisResult) =
+ let sourceImage = sourceImages.Find (fun srcImg -> srcImg.Num = imgNum)
- let w = sourceImage.img.Width
- let h = sourceImage.img.Height
+ let w = sourceImage.Img.Width
+ let h = sourceImage.Img.Height
- sourceImage.dateLastAnalysis <- DateTime.UtcNow
+ sourceImage.DateLastAnalysis <- DateTime.UtcNow
// To match with previously manually altered RBC.
- let manuallyAlteredPreviousRBCS = sourceImage.rbcs |> List.filter (fun rbc -> rbc.setManually)
- let tolerance = (float sourceImage.config.RBCRadius.Pixel) * 0.5 // +/-.
+ 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 (
rbc.center.Y < center.Y + tolerance
)
- sourceImage.rbcs <-
- cells
+ sourceImage.RBCs <-
+ result.Cells
|> List.filter (fun cell -> match cell.cellClass with ParasitemiaCore.Types.HealthyRBC | ParasitemiaCore.Types.InfectedRBC -> true | _ -> false )
|> List.sortByDescending (fun cell -> cell.nucleusArea, (w - cell.center.X) + (h - cell.center.Y))
|> List.mapi (
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.
-
type RBC =
{
num : int
infectedArea : int
}
-type SourceImage =
- {
- mutable num : int
- mutable name : string
-
- mutable config : ParasitemiaCore.Config.Config
- mutable dateLastAnalysis : DateTime // UTC.
- img : Image<Bgr, byte>
- 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)
-
type PredefinedPPI =
{
ppi : int<ppi>
let private savePredefinedPPIToFile (predefinedPPI : PredefinedPPI list) =
try
+ Directory.CreateDirectory roamingDir |> ignore
use file = new StreamWriter (predefinedPPIFilepath)
file.Write (JsonConvert.SerializeObject (predefinedPPI, JsonSerializerSettings (Formatting = Formatting.Indented)))
with
let private saveSensorSizesToFile (sensorSizes : SensorSize list) =
try
+ Directory.CreateDirectory roamingDir |> ignore
use file = new StreamWriter (sensorSizesFilepath)
file.Write (JsonConvert.SerializeObject (sensorSizes, JsonSerializerSettings (Formatting = Formatting.Indented)))
with
use file = new StreamReader (predefinedPPIFilepath)
JsonConvert.DeserializeObject<PredefinedPPI list> (file.ReadToEnd ())
with
- | ex ->
+ | _ex ->
savePredefinedPPIToFile defaultPredefinedPPI
defaultPredefinedPPI
use file = new StreamReader (sensorSizesFilepath)
JsonConvert.DeserializeObject<SensorSize list> (file.ReadToEnd ())
with
- | ex ->
+ | _ex ->
saveSensorSizesToFile defaultSensorSizes
defaultSensorSizes
+
+let argsHelp =
+ let programName = System.AppDomain.CurrentDomain.FriendlyName
+ "Usage of Parasitemia:\n" +
+ "Non-interactive mode:\n" +
+ (sprintf " %s (--folder <folder>|--file <file>) --output <folder> [--debug]\n" programName) +
+ " --folder <folder> : an input folder containing images to analyze\n" +
+ " --file <file> : an image file to be analyzed\n" +
+ " --output <folder> : a folder to put the results\n" +
+ " --debug : output more information like intermediate images (it takes more CPU and memory)\n" +
+
+ "Interactive mode:\n" +
+ (sprintf " %s [<document-file>] [--debug]\n" programName) +
+ " <document-file> : a PIAZ file to automatically open at startup\n" +
+ " --debug : output information like intermediate images in the current directory (it takes more CPU and memory)"
\ No newline at end of file
--- /dev/null
+<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ mc:Ignorable="d"
+ x:Name="CommandLineArgumentsWindow" Height="420" Width="620" Title="Command Line Arguments" Icon="pack://application:,,,/Resources/icon.ico" ResizeMode="CanResizeWithGrip">
+ <Grid Margin="3">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="*"/>
+ <RowDefinition Height="Auto"/>
+ </Grid.RowDefinitions>
+ <TextBlock Margin="3">Parasitemia can be launched via a command line, here are the possible arguments</TextBlock>
+ <TextBox x:Name="txtCommandLineArguments" Margin="6" Grid.Row="1" TextWrapping="Wrap" FontFamily="Courier New" FontSize="11" IsReadOnly="True" />
+ <Button x:Name="butClose" Content="Close" HorizontalAlignment="Right" Margin="3" VerticalAlignment="Bottom" Width="75" Grid.Row="2" Height="20"/>
+ </Grid>
+</Window>
\ No newline at end of file
--- /dev/null
+namespace ParasitemiaUI.Views
+
+open FsXaml
+
+type CommandLineArgumentsWindow = XAML<"XAML/CommandLineArgumentsWindow.xaml">
+
<MenuItem x:Name="menuHightlightRBC" Header="_Highlight All Erythrocytes" IsCheckable="True" InputGestureText="Ctrl+H" />
</MenuItem>
<MenuItem x:Name="menuHelp" Header="_Help">
+ <MenuItem x:Name="menuCommandLineArguments" Header="_Command Line Arguments" />
<MenuItem x:Name="menuAbout" Header="_About" />
</MenuItem>
</Menu>
<Rectangle x:Name="border" Fill="#00000000" />
<Polygon x:Name="manuallyAdded" Points="0,0 12,0, 12,12" Fill="Black" HorizontalAlignment="Right" VerticalAlignment="Top" />
<Border HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,3,3" Background="#66000000" CornerRadius="5">
- <TextBlock x:Name="txtRBCNumber" Padding="2" Text="42" Foreground="White" />
+ <TextBlock x:Name="txtRBCNumber" Padding="2" Text="42" Foreground="White" FontSize="12" />
</Border>
</Grid>
</UserControl>
\ No newline at end of file
<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.2.1" targetFramework="net452" />
+ <package id="FSharp.Core" version="4.2.3" 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.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" />
+ <package id="System.ValueTuple" version="4.4.0" targetFramework="net452" />
<package id="ZedGraph" version="5.1.7" targetFramework="net452" />
</packages>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Project="..\..\packages\xunit.runner.visualstudio.2.2.0\build\net20\xunit.runner.visualstudio.props" Condition="Exists('..\..\packages\xunit.runner.visualstudio.2.2.0\build\net20\xunit.runner.visualstudio.props')" />
+ <Import Project="..\..\packages\xunit.runner.visualstudio.2.3.0\build\net20\xunit.runner.visualstudio.props" Condition="Exists('..\..\packages\xunit.runner.visualstudio.2.3.0\build\net20\xunit.runner.visualstudio.props')" />
+ <Import Project="..\..\packages\xunit.core.2.3.0\build\xunit.core.props" Condition="Exists('..\..\packages\xunit.core.2.3.0\build\xunit.core.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
</ItemGroup>
<ItemGroup>
<Reference Include="FSharp.Core">
- <HintPath>..\..\packages\FSharp.Core.4.2.1\lib\net45\FSharp.Core.dll</HintPath>
+ <HintPath>..\..\packages\FSharp.Core.4.2.3\lib\net45\FSharp.Core.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.ValueTuple">
- <HintPath>..\..\packages\System.ValueTuple.4.3.1\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
+ <HintPath>..\..\packages\System.ValueTuple.4.4.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="xunit.abstractions">
<HintPath>..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll</HintPath>
</Reference>
<Reference Include="xunit.assert">
- <HintPath>..\..\packages\xunit.assert.2.2.0\lib\netstandard1.1\xunit.assert.dll</HintPath>
+ <HintPath>..\..\packages\xunit.assert.2.3.0\lib\netstandard1.1\xunit.assert.dll</HintPath>
</Reference>
<Reference Include="xunit.core">
- <HintPath>..\..\packages\xunit.extensibility.core.2.2.0\lib\netstandard1.1\xunit.core.dll</HintPath>
+ <HintPath>..\..\packages\xunit.extensibility.core.2.3.0\lib\netstandard1.1\xunit.core.dll</HintPath>
</Reference>
<Reference Include="xunit.execution.desktop">
- <HintPath>..\..\packages\xunit.extensibility.execution.2.2.0\lib\net452\xunit.execution.desktop.dll</HintPath>
+ <HintPath>..\..\packages\xunit.extensibility.execution.2.3.0\lib\net452\xunit.execution.desktop.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
- <Error Condition="!Exists('..\..\packages\xunit.runner.visualstudio.2.2.0\build\net20\xunit.runner.visualstudio.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\xunit.runner.visualstudio.2.2.0\build\net20\xunit.runner.visualstudio.props'))" />
+ <Error Condition="!Exists('..\..\packages\xunit.core.2.3.0\build\xunit.core.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\xunit.core.2.3.0\build\xunit.core.props'))" />
+ <Error Condition="!Exists('..\..\packages\xunit.core.2.3.0\build\xunit.core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\xunit.core.2.3.0\build\xunit.core.targets'))" />
+ <Error Condition="!Exists('..\..\packages\xunit.runner.visualstudio.2.3.0\build\net20\xunit.runner.visualstudio.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\xunit.runner.visualstudio.2.3.0\build\net20\xunit.runner.visualstudio.props'))" />
</Target>
+ <Import Project="..\..\packages\xunit.core.2.3.0\build\xunit.core.targets" Condition="Exists('..\..\packages\xunit.core.2.3.0\build\xunit.core.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <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="FSharp.Core" version="4.2.3" targetFramework="net452" />
+ <package id="System.ValueTuple" version="4.4.0" targetFramework="net452" />
+ <package id="xunit" version="2.3.0" targetFramework="net452" />
<package id="xunit.abstractions" version="2.0.1" targetFramework="net452" />
- <package id="xunit.assert" version="2.2.0" targetFramework="net452" />
- <package id="xunit.core" version="2.2.0" targetFramework="net452" />
- <package id="xunit.extensibility.core" version="2.2.0" targetFramework="net452" />
- <package id="xunit.extensibility.execution" version="2.2.0" targetFramework="net452" />
- <package id="xunit.runner.visualstudio" version="2.2.0" targetFramework="net452" developmentDependency="true" />
+ <package id="xunit.analyzers" version="0.7.0" targetFramework="net452" />
+ <package id="xunit.assert" version="2.3.0" targetFramework="net452" />
+ <package id="xunit.core" version="2.3.0" targetFramework="net452" />
+ <package id="xunit.extensibility.core" version="2.3.0" targetFramework="net452" />
+ <package id="xunit.extensibility.execution" version="2.3.0" targetFramework="net452" />
+ <package id="xunit.runner.visualstudio" version="2.3.0" targetFramework="net452" developmentDependency="true" />
</packages>
\ No newline at end of file