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