MyCaffe  1.12.2.41
Deep learning software for Windows C# programmers.
VOCDataLoader.cs
1using System;
2using System.Collections.Generic;
3using System.Diagnostics;
4using System.IO;
5using System.IO.Compression;
6using System.Linq;
7using System.Text;
8using System.Threading.Tasks;
9using MyCaffe.basecode;
10using MyCaffe.db.image;
11using System.Drawing;
13using System.Threading;
14using MyCaffe.param.ssd;
15using System.Xml;
16using System.Xml.Linq;
17
18namespace MyCaffe.data
19{
26 public class VOCDataLoader
27 {
28 List<SimpleDatum> m_rgImg = new List<SimpleDatum>();
29 VOCDataParameters m_param;
30 DatasetFactory m_factory = new DatasetFactory();
31 CancelEvent m_evtCancel = null;
32 Log m_log;
33
37 public event EventHandler<ProgressArgs> OnProgress;
41 public event EventHandler<ProgressArgs> OnError;
45 public event EventHandler OnCompleted;
46
53 public VOCDataLoader(VOCDataParameters param, Log log, CancelEvent evtCancel)
54 {
55 m_param = param;
56 m_log = log;
57 m_evtCancel = evtCancel;
58 m_evtCancel.Reset();
59 }
60
61 private string dataset_name
62 {
63 get { return "VOC0712"; }
64 }
65
71 public bool LoadDatabase(int nCreatorID = 0)
72 {
73 try
74 {
75 reportProgress(0, 0, "Loading " + dataset_name + " database...");
76
77 int nIdx = 0;
78 int nTotal = 5011 + 17125;
79 int nExtractIdx = 0;
80 int nExtractTotal = 10935 + 40178;
81
82 // Get the label map.
83 LabelMap labelMap = loadLabelMap();
84 Dictionary<string, int> rgNameToLabel = labelMap.MapToLabel(m_log, true);
85 string strSrc = dataset_name + ".training";
86
87 int nSrcId = m_factory.GetSourceID(strSrc);
88 if (nSrcId > 0)
89 m_factory.DeleteSourceData(nSrcId);
90
91 List<Tuple<int, string, Size>> rgFileSizes = new List<Tuple<int, string, Size>>();
92
93 if (!loadFile(m_param.DataBatchFileTrain2007, strSrc, nExtractTotal, ref nExtractIdx, nTotal, ref nIdx, m_log, m_param.ExtractFiles, rgNameToLabel, rgFileSizes))
94 return false;
95
96 if (!loadFile(m_param.DataBatchFileTrain2012, strSrc, nExtractTotal, ref nExtractIdx, nTotal, ref nIdx, m_log, m_param.ExtractFiles, rgNameToLabel, rgFileSizes))
97 return false;
98
99 string strDir = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\MyCaffe\\test_data\\data\\ssd\\VOC0712\\";
100 if (!Directory.Exists(strDir))
101 Directory.CreateDirectory(strDir);
102
103 saveFileSizes(rgFileSizes, strDir + "train_name_size.txt");
104
105 SourceDescriptor srcTrain = m_factory.LoadSource(strSrc);
106
107 rgFileSizes = new List<Tuple<int, string, Size>>();
108 m_rgImg = new List<SimpleDatum>();
109 nIdx = 0;
110 nTotal = 4952;
111 nExtractIdx = 0;
112 nExtractTotal = 10347;
113
114 strSrc = dataset_name + ".testing";
115
116 nSrcId = m_factory.GetSourceID(strSrc);
117 if (nSrcId > 0)
118 m_factory.DeleteSourceData(nSrcId);
119
120 if (!loadFile(m_param.DataBatchFileTest2007, strSrc, nExtractTotal, ref nExtractIdx, nTotal, ref nIdx, m_log, m_param.ExtractFiles, rgNameToLabel, rgFileSizes))
121 return false;
122
123 saveFileSizes(rgFileSizes, strDir + "test_name_size.txt");
124
125 SourceDescriptor srcTest = m_factory.LoadSource(strSrc);
126
127 DatasetDescriptor ds = new DatasetDescriptor(nCreatorID, dataset_name, null, null, srcTrain, srcTest, dataset_name, dataset_name + " Dataset");
128 m_factory.AddDataset(ds);
129 m_factory.UpdateDatasetCounts(ds.ID);
130
131 return true;
132 }
133 catch (Exception excpt)
134 {
135 throw excpt;
136 }
137 finally
138 {
139 if (OnCompleted != null)
140 OnCompleted(this, new EventArgs());
141 }
142 }
143
144 private void saveFileSizes(List<Tuple<int, string, Size>> rgFileSizes, string strFile)
145 {
146 if (File.Exists(strFile))
147 File.Delete(strFile);
148
149 using (StreamWriter sw = new StreamWriter(strFile))
150 {
151 foreach (Tuple<int, string, Size> item in rgFileSizes)
152 {
153 string strLine = item.Item1.ToString() + ", ";
154 strLine += item.Item2.ToString() + ", ";
155 strLine += item.Item3.Height.ToString() + ", ";
156 strLine += item.Item3.Width.ToString();
157 sw.WriteLine(strLine);
158 }
159 }
160 }
161
162 private void addLabels(int nSrcId, Dictionary<string, int> rgNameToLabel)
163 {
164 foreach (KeyValuePair<string, int> kv in rgNameToLabel)
165 {
166 m_factory.AddLabel(kv.Value, kv.Key, nSrcId);
167 }
168 }
169
170 private bool loadFile(string strImagesFile, string strSourceName, int nExtractTotal, ref int nExtractIdx, int nTotal, ref int nIdx, Log log, bool bExtractFiles, Dictionary<string, int> rgNameToLabel, List<Tuple<int, string, Size>> rgFileSizes)
171 {
172 Stopwatch sw = new Stopwatch();
173
174 reportProgress(nIdx, nTotal, " Source: " + strSourceName);
175 reportProgress(nIdx, nTotal, " loading " + strImagesFile + "...");
176
177 FileStream fs = null;
178
179 try
180 {
181 int nSrcId = m_factory.AddSource(strSourceName, 3, -1, -1, false);
182 addLabels(nSrcId, rgNameToLabel);
183 m_factory.Open(nSrcId, 500, Database.FORCE_LOAD.NONE, log);
184
185 int nPos = strImagesFile.ToLower().LastIndexOf(".tar");
186 string strPath = strImagesFile.Substring(0, nPos);
187
188 if (!Directory.Exists(strPath))
189 Directory.CreateDirectory(strPath);
190
191 if (bExtractFiles)
192 {
193 log.Progress = (double)nIdx / nExtractTotal;
194 log.WriteLine("Extracting files from '" + strImagesFile + "'...");
195
196 if ((nExtractIdx = TarFile.ExtractTar(strImagesFile, strPath, m_evtCancel, log, nExtractTotal, nExtractIdx)) == 0)
197 {
198 log.WriteLine("Aborted.");
199 return false;
200 }
201 }
202
203 // Load the annotations.
205 int nResizeHeight = 0;
206 int nResizeWidth = 0;
207
208 // Create the training database images.
209 // Create the master list file.
210 List<Tuple<string, string>> rgFiles = createFileList(log, strPath);
211
212 sw.Start();
213 for (int i = 0; i < rgFiles.Count; i++)
214 {
215 SimpleDatum datum = loadDatum(log, rgFiles[i].Item1, rgFiles[i].Item2, nResizeHeight, nResizeWidth, type, rgNameToLabel);
216 m_factory.PutRawImageCache(nIdx, datum);
217 nIdx++;
218
219 if (m_evtCancel.WaitOne(0))
220 {
221 log.WriteLine("Aborted.");
222 return false;
223 }
224
225 if (sw.Elapsed.TotalMilliseconds > 1000)
226 {
227 log.Progress = (double)nIdx / nTotal;
228 log.WriteLine("Loading file " + i.ToString() + " of " + rgFiles.Count.ToString() + "...");
229 sw.Restart();
230 }
231
232 rgFileSizes.Add(new Tuple<int, string, Size>(nIdx, rgFiles[i].Item1, new Size(datum.Width, datum.Height)));
233 }
234
235 m_factory.ClearImageCache(true);
236 m_factory.Close();
237 }
238 finally
239 {
240 if (fs != null)
241 fs.Dispose();
242 }
243
244 return true;
245 }
246
247 private SimpleDatum loadDatum(Log log, string strImgFile, string strAnnotationFile, int nResizeHeight, int nResizeWidth, SimpleDatum.ANNOTATION_TYPE type, Dictionary<string, int> rgNameToLabel)
248 {
249 Bitmap bmp = new Bitmap(strImgFile);
250
251 if (nResizeHeight == 0)
252 nResizeHeight = bmp.Height;
253
254 if (nResizeWidth == 0)
255 nResizeWidth = bmp.Width;
256
257 if (nResizeHeight != bmp.Height || nResizeWidth != bmp.Width)
258 {
259 Bitmap bmpNew = ImageTools.ResizeImage(bmp, nResizeWidth, nResizeHeight);
260 bmp.Dispose();
261 bmp = bmpNew;
262 }
263
264 SimpleDatum datum = ImageData.GetImageDataD(bmp, 3, false, 0, false);
265 loadAnnotationFile(log, strAnnotationFile, datum, type, rgNameToLabel);
266
267 return datum;
268 }
269
270 private bool loadAnnotationFile(Log log, string strFile, SimpleDatum datum, SimpleDatum.ANNOTATION_TYPE type, Dictionary<string, int> rgNameToLabel)
271 {
272 if (type != SimpleDatum.ANNOTATION_TYPE.BBOX)
273 {
274 log.FAIL("Unknown annotation type '" + type.ToString() + "'!");
275 return false;
276 }
277
279 datum.annotation_type = type;
280
281 string strExt = Path.GetExtension(strFile).ToLower();
282
283 switch (strExt)
284 {
285 case ".xml":
286 return loadXmlAnnotationFile(log, strFile, datum, rgNameToLabel);
287
288 default:
289 log.FAIL("Unknown annotation file type '" + strExt + "'!");
290 break;
291 }
292
293 return true;
294 }
295
296 private bool loadXmlAnnotationFile(Log log, string strFile, SimpleDatum datum, Dictionary<string, int> rgNameToLabel)
297 {
298 XDocument doc = XDocument.Load(strFile);
299 XElement size = doc.Descendants("size").First();
300 XElement val;
301
302 val = size.Descendants("width").First();
303 int nWidth = int.Parse(val.Value);
304
305 val = size.Descendants("height").First();
306 int nHeight = int.Parse(val.Value);
307
308 val = size.Descendants("depth").First();
309 int nChannels = int.Parse(val.Value);
310
311 if (datum.Height != nHeight || datum.Width != nWidth || datum.Channels != nChannels)
312 log.FAIL("Inconsistent image size, expected (" + datum.Channels.ToString() + "," + datum.Height.ToString() + "," + datum.Width.ToString() + ") but annotation has size (" + nChannels.ToString() + "," + nHeight.ToString() + "," + nWidth.ToString() + ").");
313
314 int nInstanceId = 0;
315
316 List<XElement> objects = doc.Descendants("object").ToList();
317 foreach (XElement obj in objects)
318 {
319 val = obj.Descendants("name").First();
320 string strName = val.Value;
321
322 val = obj.Descendants("difficult").First();
323 bool bDifficult = (val.Value == "0") ? false : true;
324
325 XElement bndbox = obj.Descendants("bndbox").First();
326
327 val = bndbox.Descendants("xmin").First();
328 float fxmin = BaseParameter.ParseFloat(val.Value);
329 if (fxmin > nWidth || fxmin < 0)
330 log.WriteLine("WARNING: '" + strFile + "' bounding box exceeds image boundary.");
331
332 val = bndbox.Descendants("ymin").First();
333 float fymin = BaseParameter.ParseFloat(val.Value);
334 if (fymin > nHeight || fymin < 0)
335 log.WriteLine("WARNING: '" + strFile + "' bounding box exceeds image boundary.");
336
337 val = bndbox.Descendants("xmax").First();
338 float fxmax = BaseParameter.ParseFloat(val.Value);
339 if (fxmax > nWidth || fxmax < 0)
340 log.WriteLine("WARNING: '" + strFile + "' bounding box exceeds image boundary.");
341
342 val = bndbox.Descendants("ymax").First();
343 float fymax = BaseParameter.ParseFloat(val.Value);
344 if (fymax > nHeight || fymax < 0)
345 log.WriteLine("WARNING: '" + strFile + "' bounding box exceeds image boundary.");
346
347 if (!rgNameToLabel.ContainsKey(strName))
348 {
349 log.FAIL("Could not find the label '" + strName + "' in the label mapping!");
350 return false;
351 }
352
353 int nLabel = rgNameToLabel[strName];
354 NormalizedBBox bbox = new NormalizedBBox(fxmin / nWidth, fymin / nHeight, fxmax / nWidth, fymax / nHeight, nLabel, bDifficult);
355 datum.SetLabel(nLabel);
356
357 foreach (AnnotationGroup g in datum.annotation_group)
358 {
359 if (nLabel == g.group_label)
360 {
361 if (g.annotations.Count == 0)
362 nInstanceId = 0;
363 else
364 nInstanceId = g.annotations[g.annotations.Count - 1].instance_id + 1;
365
366 g.annotations.Add(new Annotation(bbox, nInstanceId));
367 bbox = null;
368 break;
369 }
370 }
371
372 if (bbox != null)
373 {
374 nInstanceId = 0;
375 AnnotationGroup grp = new AnnotationGroup(null, nLabel);
376 grp.annotations.Add(new Annotation(bbox, nInstanceId));
377 datum.annotation_group.Add(grp);
378 bbox = null;
379 }
380 }
381
382 return true;
383 }
384
385 private List<Tuple<string, string>> createFileList(Log log, string strFile)
386 {
387 List<Tuple<string, string>> rgFiles = new List<Tuple<string, string>>();
388
389 string strPath = strFile;
390 int nPos = strFile.ToLower().LastIndexOf(".tar");
391 if (nPos > 0)
392 strPath = strFile.Substring(0, nPos);
393
394 strPath += "\\VOCdevkit\\VOC";
395
396 if (strPath.Contains("2012"))
397 strPath += "2012";
398
399 if (strPath.Contains("2007"))
400 strPath += "2007";
401
402 loadFileList(log, strPath, rgFiles);
403 return rgFiles;
404 }
405
406 private void loadFileList(Log log, string strPath, List<Tuple<string, string>> rgFiles)
407 {
408 log.WriteLine("Creating the list file for " + dataset_name + " dataset...");
409
410 string strImgPath = strPath + "\\JPEGImages";
411 string strLabelPath = strPath + "\\Annotations";
412
413 string[] rgImgFiles = Directory.GetFiles(strImgPath);
414 string[] rgLabelFiles = Directory.GetFiles(strLabelPath);
415
416 if (rgImgFiles.Length != rgLabelFiles.Length)
417 {
418 log.FAIL("The image path '" + strImgPath + "' has " + rgImgFiles.Length.ToString() + " files and label path '" + strLabelPath + "' has " + rgLabelFiles.Length.ToString() + " files - both paths should have the same number of files!");
419 return;
420 }
421
422 for (int i = 0; i < rgImgFiles.Length; i++)
423 {
424 rgFiles.Add(new Tuple<string, string>(rgImgFiles[i], rgLabelFiles[i]));
425 }
426 }
427
428 private string test_data_path
429 {
430 get
431 {
432 string strPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData).TrimEnd('\\');
433 strPath += "\\MyCaffe\\test_data";
434 return strPath;
435 }
436 }
437
438 private string getDataFile(string strSubDir, string strFileName)
439 {
440 string strPath = test_data_path;
441 strPath += "\\data\\ssd\\" + strSubDir + "\\" + strFileName;
442 return strPath;
443 }
444
445 private LabelMap loadLabelMap()
446 {
447 string strFile = getDataFile(dataset_name, "labelmap_voc.prototxt");
448 RawProto proto = RawProtoFile.LoadFromFile(strFile);
449 return LabelMap.FromProto(proto);
450 }
451
452 private void reportProgress(int nIdx, int nTotal, string strMsg)
453 {
454 if (OnProgress != null)
455 OnProgress(this, new ProgressArgs(new ProgressInfo(nIdx, nTotal, strMsg)));
456 }
457
458 private void reportError(int nIdx, int nTotal, Exception err)
459 {
460 if (OnError != null)
461 OnError(this, new ProgressArgs(new ProgressInfo(nIdx, nTotal, "ERROR", err)));
462 }
463 }
464}
Defines a collection of AnnotationGroups.
Definition: Annotation.cs:256
void Add(AnnotationGroupCollection col)
Add another AnnotationGroupCollection to this one.
Definition: Annotation.cs:369
The AnnoationGroup class manages a group of annotations.
Definition: Annotation.cs:124
int group_label
Get/set the group label.
Definition: Annotation.cs:211
List< Annotation > annotations
Get/set the group annoations.
Definition: Annotation.cs:202
The Annotation class is used by annotations attached to SimpleDatum's and used in SSD.
Definition: Annotation.cs:22
The BaseParameter class is the base class for all other parameter classes.
static float ParseFloat(string strVal)
Parse float values using the US culture if the decimal separator = '.', then using the native culture...
The CancelEvent provides an extension to the manual cancel event that allows for overriding the manua...
Definition: CancelEvent.cs:17
void Reset()
Resets the event clearing any signaled state.
Definition: CancelEvent.cs:279
bool WaitOne(int nMs=int.MaxValue)
Waits for the signal state to occur.
Definition: CancelEvent.cs:290
The ImageData class is a helper class used to convert between Datum, other raw data,...
Definition: ImageData.cs:14
static Datum GetImageDataD(Bitmap bmp, int nChannels, bool bDataIsReal, int nLabel, bool bUseLockBitmap=true, int[] rgFocusMap=null)
The GetImageDataD function converts a Bitmap into a Datum using the double type for real data.
Definition: ImageData.cs:44
The ImageTools class is a helper class used to manipulate image data.
Definition: ImageTools.cs:16
static Bitmap ResizeImage(Image image, int width, int height)
Resize the image to the specified width and height.
Definition: ImageTools.cs:39
The Log class provides general output in text form.
Definition: Log.cs:13
void WriteLine(string str, bool bOverrideEnabled=false, bool bHeader=false, bool bError=false, bool bDisable=false)
Write a line of output.
Definition: Log.cs:80
void FAIL(string str)
Causes a failure which throws an exception with the desciptive text.
Definition: Log.cs:394
double Progress
Get/set the progress associated with the Log.
Definition: Log.cs:147
The NormalizedBBox manages a bounding box used in SSD.
The RawProtoFile class writes and reads prototxt to and from a file.
Definition: RawProtoFile.cs:13
static RawProto LoadFromFile(string strFileName)
Loads a RawProto from a prototxt file.
Definition: RawProtoFile.cs:54
The RawProto class is used to parse and output Google prototxt file data.
Definition: RawProto.cs:17
The SimpleDatum class holds a data input within host memory.
Definition: SimpleDatum.cs:161
ANNOTATION_TYPE
Specifies the annotation type when using annotations.
Definition: SimpleDatum.cs:204
void SetLabel(int nLabel)
Sets the label.
int Channels
Return the number of channels of the data.
AnnotationGroupCollection annotation_group
When using annoations, each annotation group contains an annotation for a particular class used with ...
ANNOTATION_TYPE annotation_type
When using annotations, the annotation type specifies the type of annotation. Currently,...
int Width
Return the width of the data.
int Height
Return the height of the data.
The TarFile functions are used to expand tar files.
Definition: TarFile.cs:20
static int ExtractTar(string strFileName, string strOutputDir, CancelEvent evtCancel=null, Log log=null, int nExpectedTotal=0, int nIdx=0)
Extract a Tar (*.tar) file to a specified output directory.
Definition: TarFile.cs:38
int ID
Get/set the database ID of the item.
The DatasetDescriptor class describes a dataset which contains both a training data source and testin...
The SourceDescriptor class contains all information describing a data source.
The VOCDataLoader is used to create the VOC0712 (VOC2007 and VOC2012) dataset and load it into the da...
EventHandler OnCompleted
The OnComplete event fires once the dataset creation has completed.
EventHandler< ProgressArgs > OnProgress
The OnProgress event fires during the creation process to show the progress.
EventHandler< ProgressArgs > OnError
The OnError event fires when an error occurs.
VOCDataLoader(VOCDataParameters param, Log log, CancelEvent evtCancel)
The constructor.
bool LoadDatabase(int nCreatorID=0)
Create the dataset and load it into the database.
Contains the dataset parameters used to create the VOC0712 dataset.
string DataBatchFileTest2007
Returns the testing file 'VOCtest_06-Nov-2007.tar'.
string DataBatchFileTrain2007
Returns the training file 'VOCtrain_06-Nov-2007.tar'.
string DataBatchFileTrain2012
Specifies the training file 'OCtrain_11-May-2012.tar'.
bool ExtractFiles
Returns whether or not to extract the tar files.
The Database class manages the actual connection to the physical database using Entity Framworks from...
Definition: Database.cs:23
FORCE_LOAD
Defines the force load type.
Definition: Database.cs:57
The DatasetFactory manages the connection to the Database object.
void PutRawImageCache(int nIdx, SimpleDatum sd, int nBackgroundWritingThreadCount=0, string strDescription=null, bool bActive=true, params ParameterData[] rgParams)
Add a SimpleDatum to the RawImage cache.
int GetSourceID(string strName)
Returns the ID of a data source given its name.
int AddLabel(int nLabel, string strName, int nSrcId=0, ConnectInfo ci=null)
Add a label to the database for a data source.
void DeleteSourceData(int nSrcId=0)
Delete the data source data (images, means, results and parameters) from the database.
int AddSource(SourceDescriptor src, ConnectInfo ci=null, bool? bSaveImagesToFileOverride=null)
Adds a new data source to the database.
int AddDataset(DatasetDescriptor ds, ConnectInfo ci=null, bool? bSaveImagesToFileOverride=null)
Adds or updates the training source, testing source, dataset creator and dataset to the database.
void Close()
Close the current data source used.
void ClearImageCache(bool bSave)
Clear the RawImage cache and optionally save the images.
SourceDescriptor LoadSource(string strSource)
Load the source descriptor from a data source name.
void UpdateDatasetCounts(int nDsId, ConnectInfo ci=null)
Updates the dataset counts, and training/testing source counts.
void Open(SourceDescriptor src, int nCacheMax=500, ConnectInfo ci=null)
Open a given data source.
Specifies the LabelMap used with SSD.
Definition: LabelMap.cs:22
Dictionary< string, int > MapToLabel(Log log, bool bStrict)
Map the names to their labels.
Definition: LabelMap.cs:105
static LabelMap FromProto(RawProto rp)
Parses the parameter from a RawProto.
Definition: LabelMap.cs:191
The descriptors namespace contains all descriptor used to describe various items stored within the da...
The MyCaffe.basecode contains all generic types used throughout MyCaffe.
Definition: Annotation.cs:12
The MyCaffe.data namespace contains dataset creators used to create common testing datasets such as M...
Definition: BinaryFile.cs:16
The MyCaffe.db.image namespace contains all image database related classes.
Definition: Database.cs:18
The MyCaffe.param.ssd namespace contains all SSD related parameter objects that correspond to the nat...
The MyCaffe.param namespace contains parameters used to create models.
The MyCaffe namespace contains the main body of MyCaffe code that closesly tracks the C++ Caffe open-...
Definition: Annotation.cs:12