df722125d1562ee5afee7c104fba2a031d053659
[master-thesis.git] / Parasitemia / ParasitemiaUI / PiaZ.fs
1 // ParasitemIA Zipped document format.
2 module ParasitemiaUI.PiaZ
3
4 open System
5 open System.Windows
6 open System.IO
7 open System.IO.Compression
8
9 open Emgu.CV
10 open Emgu.CV.Structure
11
12 open Newtonsoft.Json
13 open Newtonsoft.Json.Converters
14
15 open Types
16
17 let extension = ".piaz"
18 let filter = "PIA|*.piaz"
19
20 // Information associated to a document.
21 type JSONInformation =
22 {
23 patientID : string
24 fileVersion : int
25 }
26
27 // Information associated to each images.
28 type JSONSourceImage =
29 {
30 num : int
31 name : string
32
33 RBCRadius : float32 // The RBC Radius found by granulometry.
34 parameters : ParasitemiaCore.Config.Parameters
35 dateLastAnalysis : DateTime
36 rbcs : RBC List
37
38 healthyRBCBrightness : float32 // 0 to 1.
39 infectedRBCBrightness : float32 // 0 to 1.
40 }
41
42 type DocumentData =
43 {
44 patientID : string
45 images : SourceImage list
46 }
47
48 let mainEntryName = "info.json"
49 let imageExtension = ".tiff"
50 let currentFileVersion = 2
51
52 /// <summary>
53 /// Save a document in a give file path. The file may already exist.
54 /// </summary>
55 /// <param name="filePath"></param>
56 /// <param name="data"></param>
57 /// <exception cref="System.IOException">If the file cannot be written</exception>
58 let save (filePath : string) (data : DocumentData) =
59 use file = ZipFile.Open (filePath, ZipArchiveMode.Update)
60
61 for e in List.ofSeq file.Entries do // 'ofSeq' to not iterate a collection currently modified.
62 e.Delete ()
63
64 // Main JSON file.
65 let mainEntry = file.CreateEntry (mainEntryName, CompressionLevel.Fastest)
66 use mainEntryWriter = new StreamWriter (mainEntry.Open ())
67 mainEntryWriter.Write (JsonConvert.SerializeObject ({ patientID = data.patientID; fileVersion = currentFileVersion }))
68
69 // Write each images and the associated information.
70 for srcImg in data.images do
71 let imgFilename = (string srcImg.Num) + imageExtension
72 let imgEntry = file.CreateEntry (imgFilename, CompressionLevel.NoCompression) // FIXME: It seems a compression is applied to this file despite of the 'NoCompression' flag.
73 srcImg.Img.ToBitmap().Save (imgEntry.Open (), System.Drawing.Imaging.ImageFormat.Tiff)
74
75 let imgJSONEntry = file.CreateEntry (imgFilename + ".json", CompressionLevel.Fastest)
76 use imgJSONFileWriter = new StreamWriter (imgJSONEntry.Open ())
77 imgJSONFileWriter.Write (
78 JsonConvert.SerializeObject (
79 {
80 num = srcImg.Num
81 name = srcImg.Name
82 RBCRadius = srcImg.Config.RBCRadius.Pixel
83 parameters = srcImg.Config.Parameters
84 dateLastAnalysis = srcImg.DateLastAnalysis
85 rbcs = srcImg.RBCs
86 healthyRBCBrightness = srcImg.HealthyRBCBrightness
87 infectedRBCBrightness = srcImg.InfectedRBCBrightness
88 }
89 )
90 )
91
92 let updateDocumentData (fromVersion : int) (toVersion : int) (data : DocumentData) : DocumentData =
93 for v in fromVersion + 1 .. toVersion do
94 match v with
95 | 1 -> // Version 0 -> 1 : set initial brightness for rbc.
96 data.images |> List.iter (fun i -> i.HealthyRBCBrightness <- 1.f; i.InfectedRBCBrightness <- 1.f)
97 | _ -> ()
98 data
99
100 /// <summary>
101 /// Load document from a give file path.
102 /// </summary>
103 /// <param name="filePath"></param>
104 /// <exception cref="System.IOException">If the file cannot be read</exception>
105 let load (filePath : string) (defaultConfig : ParasitemiaCore.Config.Config) : DocumentData =
106 use file = ZipFile.Open (filePath, ZipArchiveMode.Read)
107
108 let mainEntry = file.GetEntry (mainEntryName)
109 use mainEntryReader = new StreamReader (mainEntry.Open ())
110 let info = JsonConvert.DeserializeObject<JSONInformation> (mainEntryReader.ReadToEnd ())
111
112 updateDocumentData info.fileVersion currentFileVersion
113 {
114 patientID = info.patientID
115 images =
116 [
117 let mutable imgNum = 0
118 for imgEntry in file.Entries do
119 if imgEntry.Name.EndsWith (imageExtension) then
120 use bitmap = new System.Drawing.Bitmap (imgEntry.Open (), false)
121 let img = new Image<Bgr, byte> (bitmap)
122 imgNum <- imgNum + 1
123 let imgJSONEntry = file.GetEntry (imgEntry.Name + ".json")
124 use imgJSONFileReader = new StreamReader (imgJSONEntry.Open ())
125 let imgInfo = JsonConvert.DeserializeObject<JSONSourceImage> (imgJSONFileReader.ReadToEnd ())
126
127 let config = defaultConfig.Copy ()
128 config.Parameters <-
129 {
130 ParasitemiaCore.Config.defaultParameters with
131 resolution = imgInfo.parameters.resolution
132 }
133
134 config.SetRBCRadius imgInfo.RBCRadius
135
136 yield SourceImage (imgNum, imgInfo.name, config, imgInfo.dateLastAnalysis, img, imgInfo.rbcs, HealthyRBCBrightness = imgInfo.healthyRBCBrightness, InfectedRBCBrightness = imgInfo.infectedRBCBrightness)
137 ]
138 }