Save imported image in the same format (WIP)
[master-thesis.git] / Parasitemia / ParasitemiaUI / PiaZ.fs
1 // ParasitemIA Zipped document format.
2 module ParasitemiaUI.PiaZ
3
4 open System
5 open System.IO
6 open System.IO.Compression
7
8 open Emgu.CV
9 open Emgu.CV.Structure
10
11 open Newtonsoft.Json
12
13 open Types
14
15 let extension = ".piaz"
16 let filter = "PIA|*.piaz"
17
18 // Information associated to a document.
19 type JSONInformation =
20 {
21 patientID : string
22 fileVersion : int
23 }
24
25 // Information associated to each images.
26 type JSONSourceImage =
27 {
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 {
42 patientID : string
43 images : SourceImage list
44 }
45
46 let MAIN_ENTRY_NAME = "info.json"
47 let DEFAULT_IMAGE_EXTENSION = ".tiff"
48 let JSON_EXTENSION = ".json"
49 let CURRENT_FILE_VERSION = 3
50
51 /// <summary>
52 /// Save a document in a give file path. The file may already exist.
53 /// </summary>
54 /// <param name="filePath"></param>
55 /// <param name="data"></param>
56 /// <exception cref="System.IOException">If the file cannot be written</exception>
57 let save (filePath : string) (data : DocumentData) =
58 use file = ZipFile.Open (filePath, ZipArchiveMode.Update)
59
60 // We only delete JSON files and removed images.
61 for e in List.ofSeq file.Entries do // 'ofSeq' to not iterate a collection currently modified.
62 if Path.GetExtension e.Name = JSON_EXTENSION || data.images |> List.exists (fun img -> img.OriginalName = e.Name) |> not then
63 e.Delete ()
64
65 // Main JSON file.
66 let mainEntry = file.CreateEntry (MAIN_ENTRY_NAME, CompressionLevel.Fastest)
67 use mainEntryWriter = new StreamWriter (mainEntry.Open ())
68 mainEntryWriter.Write (JsonConvert.SerializeObject ({ patientID = data.patientID; fileVersion = CURRENT_FILE_VERSION }))
69
70 // Write each images and the associated information as a JSON file.
71 for srcImg in data.images do
72 match srcImg.TempFile with
73 | Some imgTempFile ->
74 let imgEntry = file.CreateEntry (srcImg.OriginalName, CompressionLevel.NoCompression)
75 (File.Open (imgTempFile, FileMode.Open, FileAccess.Read)).CopyTo (imgEntry.Open ())
76 srcImg.TempFile <- None
77
78 | None -> ()
79
80 //let imgFilename = (string srcImg.Num) + DEFAULT_IMAGE_EXTENSION
81 //let imgEntry = file.CreateEntry (imgFilename, CompressionLevel.NoCompression)
82 //srcImg.Img.ToBitmap().Save (imgEntry.Open (), System.Drawing.Imaging.ImageFormat.Tiff)
83
84 let imgJSONEntry = file.CreateEntry (srcImg.OriginalName + JSON_EXTENSION, CompressionLevel.Fastest)
85 use imgJSONFileWriter = new StreamWriter (imgJSONEntry.Open ())
86 imgJSONFileWriter.Write (
87 JsonConvert.SerializeObject (
88 {
89 num = srcImg.Num
90 name = srcImg.Name
91 RBCRadius = srcImg.Config.RBCRadius.Pixel
92 parameters = srcImg.Config.Parameters
93 dateLastAnalysis = srcImg.DateLastAnalysis
94 rbcs = srcImg.RBCs
95 healthyRBCBrightness = srcImg.HealthyRBCBrightness
96 infectedRBCBrightness = srcImg.InfectedRBCBrightness
97 }
98 )
99 )
100
101 let updateDocumentData (fromVersion : int) (toVersion : int) (data : DocumentData) : DocumentData =
102 for v in fromVersion + 1 .. toVersion do
103 match v with
104 | 1 -> // Version 0 -> 1 : set initial brightness for rbc.
105 data.images |> List.iter (fun i -> i.HealthyRBCBrightness <- 1.f; i.InfectedRBCBrightness <- 1.f)
106 | _ -> ()
107 data
108
109 exception VersionFileNewerException of int
110
111 /// <summary>
112 /// Load document from a give file path.
113 /// </summary>
114 /// <param name="filePath">Path to the PiaZ file</param>
115 /// <param name="defaultConfig"></param>
116 /// <exception cref="System.IOException">If the file cannot be read</exception>
117 /// <exception cref="VersionFileNewerException">If the file version is newer than the current supported version</exception>
118 let load (filePath : string) (defaultConfig : ParasitemiaCore.Config.Config) : DocumentData =
119 use file = ZipFile.Open (filePath, ZipArchiveMode.Read)
120
121 let mainEntry = file.GetEntry (MAIN_ENTRY_NAME)
122 use mainEntryReader = new StreamReader (mainEntry.Open ())
123 let info = JsonConvert.DeserializeObject<JSONInformation> (mainEntryReader.ReadToEnd ())
124
125 if info.fileVersion > CURRENT_FILE_VERSION then
126 raise <| VersionFileNewerException info.fileVersion
127
128 updateDocumentData info.fileVersion CURRENT_FILE_VERSION
129 {
130 patientID = info.patientID
131 images =
132 [
133 for imgEntry in file.Entries do
134 if imgEntry.Name.EndsWith JSON_EXTENSION |> not then
135 use bitmap = new System.Drawing.Bitmap (imgEntry.Open (), false)
136 let img = bitmap.ToImage<Bgr, byte> ()
137 let imgJSONEntry = file.GetEntry (imgEntry.Name + JSON_EXTENSION)
138 use imgJSONFileReader = new StreamReader (imgJSONEntry.Open ())
139 let imgInfo = JsonConvert.DeserializeObject<JSONSourceImage> (imgJSONFileReader.ReadToEnd ())
140 let imgNum = imgInfo.num
141
142 let config = defaultConfig.Copy ()
143 config.Parameters <-
144 {
145 ParasitemiaCore.Config.defaultParameters with
146 resolution = imgInfo.parameters.resolution
147 }
148
149 config.SetRBCRadius imgInfo.RBCRadius
150
151 SourceImage (imgNum, imgInfo.name, imgEntry.Name, config, imgInfo.dateLastAnalysis, FromMemory img, imgInfo.rbcs, HealthyRBCBrightness = imgInfo.healthyRBCBrightness, InfectedRBCBrightness = imgInfo.infectedRBCBrightness)
152 ]
153 |> List.sortBy (fun image -> image.Num)
154 }