sample_list.hpp
1 #pragma once
2 
3 #include "../_cexports/c_sample_database.h"
4 
5 #include "../global.hpp"
6 #include "../image.hpp"
7 #include "../string.hpp"
8 #include "../point_2d.hpp"
9 
10 #include <utility>
11 #include <memory>
12 #include <vector>
13 #include <ctime>
14 #include <chrono>
15 
16 namespace Cvb
17 {
18 CVB_BEGIN_INLINE_NS
19 
21 namespace SampleDatabase
22 {
23 
24 namespace Private
25 {
26 // Helpers to validate new/changed labels
27 size_t GetFloatRegressionDimension (CExports::TSIL hSil)
28 {
29  auto labelType = CVB_CALL_CAPI (SilGetLabelType(hSil));
30  size_t dim = 0;
31  CVB_CALL_CAPI_CHECKED (SilGetFloatVectorLabelDim(labelType, dim));
32  return dim;
33 }
34 
35 inline void ValidateLabel (CExports::TSIL /*hSil*/, const String &label)
36 {
37  if (label.empty ())
38  {
39  throw std::invalid_argument ("empty string is not a valid label");
40  }
41 }
42 
43 inline void ValidateLabel (CExports::TSIL hSil, const std::vector<float> &label)
44 {
45  if (label.size () != GetFloatRegressionDimension (hSil))
46  {
47  throw std::invalid_argument ("invalid dimension of the float vector label");
48  }
49 }
50 
51 // Helper to relabel a string label
52 inline void Relabel (CExports::TSIL hSil, int index, const String &label)
53 {
54  ValidateLabel (hSil, label);
55 
56  CVB_CALL_CAPI_CHECKED(SilChangeStringLabelTyped(hSil, index, label.c_str()));
57 }
58 
59 // Helper to relabel a float label
60 inline void Relabel (CExports::TSIL hSil, int index, const std::vector<float> &label)
61 {
62  ValidateLabel (hSil, label);
63 
64  /* Note: need to cast-away const of "label" parameter to match the C-API, the function does not modify it. */
65  CVB_CALL_CAPI_CHECKED(SilChangeVectorLabel(hSil, index, const_cast<float*>(label.data()), label.size()));
66 }
67 
68 // Generic label transformation callback
69 template<typename TLabelOut, typename TLabelIn>
70 using LabelTransform = std::function<TLabelOut (const TLabelIn &labelIn)>;
71 } /* namespace Private */
72 
74 
76 template <class TLabelInformation>
78 {
79 public:
80  LabelInfoCollection (const SharedReleaseObjectGuard &sguardSil)
81  : shandleSil_(sguardSil)
82  {}
83 
84  LabelInfoCollection (const LabelInfoCollection&) = default;
85  LabelInfoCollection& operator= (const LabelInfoCollection&) = default;
86 
87  virtual ~LabelInfoCollection () = default;
88 
89 public:
91  using LabelType = typename TLabelInformation::LabelType;
92 
94 
99  int Count () const
100  {
101  return CVB_CALL_CAPI(SilGetNumLabelEntries(shandleSil_.Handle()));
102  }
103 
105 
111  TLabelInformation ReadInfo (int index) const
112  {
113  return GetInfo (index);
114  }
115 
117 
123  {
124  auto count = Count ();
126  for (decltype(count) i = 0; i < count; ++i)
127  {
128  info.push_back (ReadInfo (i));
129  }
130 
131  return info;
132  }
133 
135 
140  void RemoveAt (int index)
141  {
142  CVB_CALL_CAPI_CHECKED(SilDeleteLabel(shandleSil_.Handle(), index));
143  }
144 
146 
151  void Remove (const LabelType & label)
152  {
153  auto index = LabelToIndex(label);
154  if (index < 0)
155  {
156  throw std::invalid_argument ("cannot remove class because it is not part of the sample database");
157  }
158 
159  RemoveAt(index);
160  }
161 
163 
168  void Clear ()
169  {
170  while (Count () > 0)
171  {
172  RemoveAt (0);
173  }
174  }
175 
177 
185  void MergeClasses (int fromIndex, int toIndex)
186  {
187  if (fromIndex == toIndex)
188  {
189  return;
190  }
191  Private::Relabel (shandleSil_.Handle (), fromIndex, ReadInfo (toIndex).Label ());
192  }
193 
195 
203  void MergeClasses (const LabelType & fromLabel, const LabelType & toLabel)
204  {
205  auto fromIndex = LabelToIndex (fromLabel);
206  auto toIndex = LabelToIndex (toLabel);
207  if (fromIndex < 0 || toIndex < 0)
208  {
209  throw std::invalid_argument ("cannot classes, at least one is not part of the collection");
210  }
211 
212  MergeClasses (fromIndex, toIndex);
213  }
214 
215 
216 protected:
217  virtual TLabelInformation GetInfo (int index) const = 0;
218 
219  int LabelToIndex (const LabelType &label) const
220  {
221  auto count = Count ();
222  for (int i = 0; i < count; ++i)
223  {
224  if (ReadInfo(i).Label() == label)
225  {
226  return i;
227  }
228  }
229  return -1;
230  }
231 protected:
232  SharedReleaseObjectGuard shandleSil_;
233 }; /* class LabelInfoCollection */
234 
236 
238 template <class TData>
240 {
241 public:
242  SampleCollection (const SharedReleaseObjectGuard &sguardSil)
243  : shandleSil_(sguardSil)
244  {}
245 
246  SampleCollection (const SampleCollection&) = default;
247  SampleCollection& operator= (const SampleCollection&) = default;
248 
249  virtual ~SampleCollection () = default;
250 
251 public:
253 
258  int Count () const
259  {
260  auto label = CVB_CALL_CAPI(SilGetLabel (shandleSil_.Handle(), GetLabelIndex()));
261  return CVB_CALL_CAPI(SilGetNumDataReferences(label));
262  }
263 
265 
271  TData ReadData (int index) const
272  {
273  auto data = CVB_CALL_CAPI(SilGetDataByLabel (shandleSil_.Handle(), GetLabelIndex(), index));
274  return GetData (data);
275  }
276 
278 
284  TData RemoveAt (int index)
285  {
286  TData retval = ReadData (index);
287  CVB_CALL_CAPI_CHECKED(SilDeleteDataByLabel(shandleSil_.Handle(), GetLabelIndex(), index));
288  return retval;
289  }
290 
291 protected:
292  std::shared_ptr<Image> GetImage (CExports::TSILDATA dataHandle) const
293  {
294  return Internal::DoBoolCallObjectOut<Image>([&](void* & resimg)
295  {
296  CVB_CALL_CAPI_CHECKED(SilGetImageData (dataHandle, resimg));
297  return CVB_CALL_CAPI(ShareObject (resimg));
298  });
299  }
300 
301  int GetLabelIndex () const
302  {
303  return 0;
304  }
305 
306  virtual TData GetData (CExports::TSILDATA dataHandle) const = 0;
307 
308 protected:
309  SharedReleaseObjectGuard shandleSil_;
310 }; /* class SampleCollection */
311 
313 
319 
321 
327 
329 
335 
337 
343 
345 
351 
353 
360 {
361 protected:
362  SampleList (ReleaseObjectGuard&& guardSil, const String &fileName = String())
363  : shandleSil_(std::move(guardSil)),
364  fileName_ (fileName)
365  {}
366 
367  SampleList (SampleList&&) noexcept = default;
368 
369  SampleList& operator=(SampleList&&) noexcept = default;
370 
371  virtual ~SampleList () = default;
372 
373  // Helper to load a sample list from file
374  static ReleaseObjectGuard LoadInternal (const String & fileName, CExports::TSilLabelType expectedLabelType)
375  {
376  CExports::TSIL sil = nullptr;
377 
378  CVB_CALL_CAPI_CHECKED (SilLoadTyped (fileName.c_str(), sil));
379  ReleaseObjectGuard silGuard (sil);
380 
381  auto dataType = CVB_CALL_CAPI (SilGetDataTypeEnum(silGuard.Handle()));
382  auto labelType = CVB_CALL_CAPI (SilGetLabelTypeEnum(silGuard.Handle()));
383  if (dataType != CExports::SDT_ImageData)
384  {
385  throw std::invalid_argument ("the loaded SIL file does not contain image data type");
386  }
387  if (labelType != expectedLabelType)
388  {
389  throw std::invalid_argument ("the loaded SIL file does not contain expected label type");
390  }
391 
392  return silGuard;
393  }
394 
395 public:
397 
403  void * Handle() const noexcept
404  {
405  return shandleSil_.Handle();
406  }
407 
409 
413  String FileName() const
414  {
415  return fileName_;
416  }
417 
419 
423  String Comment() const
424  {
425  size_t bufferSize = 0;
426  CVB_CALL_CAPI_CHECKED (SilGetCommentTyped(Handle(), static_cast<Char*>(nullptr), bufferSize));
427  std::vector<Char> comment (bufferSize);
428  CVB_CALL_CAPI_CHECKED (SilGetCommentTyped(Handle(), comment.data(), bufferSize));
429  return String (comment.begin(), comment.end());
430  }
431 
433 
437  void SetComment(String comment)
438  {
439  CVB_CALL_CAPI_CHECKED (SilSetCommentTyped (Handle(), comment.c_str()));
440  }
441 
443 
447  std::chrono::system_clock::time_point CreationDate() const
448  {
449  CExports::CV_SYSTEMTIME st;
450  CVB_CALL_CAPI_CHECKED (SilGetCreationDate(Handle(), st));
451  std::tm tm = {};
452  tm.tm_sec = st.wSecond;
453  tm.tm_min = st.wMinute;
454  tm.tm_hour = st.wHour;
455  tm.tm_mday = st.wDay;
456  tm.tm_mon = st.wMonth - 1;
457  tm.tm_year = st.wYear - 1900;
458  tm.tm_isdst = -1;
459 
460  return std::chrono::system_clock::from_time_t (std::mktime (&tm));
461  }
462 
464 
468  std::chrono::system_clock::time_point ModificationDate() const
469  {
470  CExports::CV_SYSTEMTIME st;
471  CVB_CALL_CAPI_CHECKED (SilGetModificationDate(Handle(), st));
472  std::tm tm = {};
473  tm.tm_sec = st.wSecond;
474  tm.tm_min = st.wMinute;
475  tm.tm_hour = st.wHour;
476  tm.tm_mday = st.wDay;
477  tm.tm_mon = st.wMonth - 1;
478  tm.tm_year = st.wYear - 1900;
479  tm.tm_isdst = -1;
480 
481  return std::chrono::system_clock::from_time_t (std::mktime (&tm));
482  }
483 
485 
489  int NumClasses() const
490  {
491  size_t numClasses, dummy1, dummy2;
492  double dummy3;
493  CVB_CALL_CAPI_CHECKED(SilGetStatistics(Handle(), numClasses, dummy1, dummy2, dummy3));
494  return static_cast<int>(numClasses);
495  }
496 
498 
502  int NumSamples() const
503  {
504  return static_cast<int>(CVB_CALL_CAPI(SilGetNumDataEntries(Handle())));
505  }
506 
508 
512  int MinSampleCount() const
513  {
514  size_t minCount, dummy1, dummy2;
515  double dummy3;
516  CVB_CALL_CAPI_CHECKED(SilGetStatistics(Handle(), dummy1, minCount, dummy2, dummy3));
517  return static_cast<int>(minCount);
518  }
519 
521 
525  int MaxSampleCount() const
526  {
527  size_t maxCount, dummy1, dummy2;
528  double dummy3;
529  CVB_CALL_CAPI_CHECKED(SilGetStatistics(Handle(), dummy1, dummy2, maxCount, dummy3));
530  return static_cast<int>(maxCount);
531  }
532 
534 
538  double AverageSampleCount() const
539  {
540  size_t dummy1, dummy2, dummy3;
541  double avgCount;
542  CVB_CALL_CAPI_CHECKED(SilGetStatistics(Handle(), dummy1, dummy2, dummy3, avgCount));
543  return avgCount;
544  }
545 
547 
553  void Save (const String & fileName) const
554  {
555  CVB_CALL_CAPI_CHECKED (SilStoreTyped (Handle(), fileName.c_str()));
556  fileName_ = fileName;
557  }
558 
559 protected:
560  // Sample image list transformation workers
561  template <class TOut>
562  std::unique_ptr<TOut> TransformData (DataTransformImageToImage cbk) const
563  {
564  CExports::TSIL sil = nullptr;
565 
566  CVB_CALL_CAPI_CHECKED (SilTransformDataList (Handle (), NativeDataTransformCallback, &cbk, sil));
567  ReleaseObjectGuard silGuard (sil);
568 
569  return TOut::FromHandle (std::move (silGuard));
570  }
571 
572  template <class TOut, class TLabelOut, class TLabelIn>
573  std::unique_ptr<TOut> TransformLabels (Private::LabelTransform<TLabelOut, TLabelIn> cbk) const
574  {
575  CExports::TSIL sil = nullptr;
576 
577  CVB_CALL_CAPI_CHECKED (SilTransformLabelList (Handle (), NativeLabelTransformCallback<TLabelOut, TLabelIn>, &cbk, sil));
578  ReleaseObjectGuard silGuard (sil);
579 
580  return TOut::FromHandle (std::move (silGuard));
581  }
582 
583 private:
584  static CExports::cvbbool_t __stdcall NativeDataTransformCallback (void* pPrivate, CExports::TSILDATA DataIn, CExports::TSILDATA& DataOut)
585  {
586  try
587  {
588  DataTransformImageToImage *cbk = reinterpret_cast<DataTransformImageToImage*> (pPrivate);
589 
590  auto imgIn = Internal::DoBoolCallObjectOut<Image>([&](void* & resimg)
591  {
592  CVB_CALL_CAPI_CHECKED(SilGetImageData (DataIn, resimg));
593  return CVB_CALL_CAPI(ShareObject (resimg));
594  });
595 
596  auto imgOut = (*cbk) (*imgIn);
597  DataOut = CVB_CALL_CAPI(SilCreateImageData(imgOut->Handle(), 0, 0, imgOut->Size().Width(), imgOut->Size().Height()));
598  return true;
599  }
600  catch (const std::exception &)
601  {
602  return false;
603  }
604  }
605 
606  template <class TLabelOut, class TLabelIn>
607  static CExports::cvbbool_t __stdcall NativeLabelTransformCallback (void* pPrivate, CExports::TSILLABEL LabelIn, CExports::TSILLABEL& LabelOut)
608  {
609  try
610  {
611  Private::LabelTransform<TLabelOut, TLabelIn> *cbk = reinterpret_cast<Private::LabelTransform<TLabelOut, TLabelIn>*> (pPrivate);
612 
613  TLabelIn objectIn;
614  NativeLabelToObject (LabelIn, objectIn);
615 
616  auto objectOut = (*cbk) (objectIn);
617  LabelOut = CreateNativeLabel (objectOut);
618  return true;
619  }
620  catch (const std::exception &)
621  {
622  return false;
623  }
624  }
625 
626  static void NativeLabelToObject (CExports::TSILLABEL label, String &object)
627  {
628  size_t bufferSize = 0;
629  CVB_CALL_CAPI_CHECKED (SilGetStringLabelTyped(label, static_cast<Char*>(nullptr), bufferSize));
630  std::vector<Char> stringLabel (bufferSize);
631  CVB_CALL_CAPI_CHECKED (SilGetStringLabelTyped(label, stringLabel.data(), bufferSize));
632  object.assign (stringLabel.begin (), stringLabel.end ());
633  }
634 
635  static CExports::TSILLABEL CreateNativeLabel (const String &object)
636  {
637  return CVB_CALL_CAPI(SilCreateStringLabelTyped(object.c_str()));
638  }
639 
640  static void NativeLabelToObject (CExports::TSILLABEL label, std::vector<float> &object)
641  {
642  size_t dim = 0;
643  CVB_CALL_CAPI_CHECKED (SilGetFloatVectorLabel(label, static_cast<float*>(nullptr), dim));
644  object.resize (dim);
645  CVB_CALL_CAPI_CHECKED (SilGetFloatVectorLabel(label, object.data(), dim));
646  }
647 
648  static CExports::TSILLABEL CreateNativeLabel (const std::vector<float> &object)
649  {
650  return CVB_CALL_CAPI(SilCreateVectorLabel(object.data(), object.size()));
651  }
652 
653 protected:
654  SharedReleaseObjectGuard shandleSil_;
655 
656 private:
657  mutable String fileName_;
658 }; /* class SampleList */
659 
662 
663 
664 } /* namespace SampleDatabase */
665 CVB_END_INLINE_NS
666 } /* namespace Cvb */
Information collection for class labels.
Definition: sample_list.hpp:77
void * Handle() const noexcept
Classic API SIL handle.
Definition: sample_list.hpp:403
std::string String
String for wide characters or unicode characters.
Definition: string.hpp:45
Base class for sample lists.
Definition: sample_list.hpp:359
TData RemoveAt(int index)
Remove a sample.
Definition: sample_list.hpp:284
double AverageSampleCount() const
Average number samples in per class of the sample list.
Definition: sample_list.hpp:538
void MergeClasses(int fromIndex, int toIndex)
Merge two classes into one class.
Definition: sample_list.hpp:185
int NumClasses() const
Number of distinguishable classes in the sample list.
Definition: sample_list.hpp:489
std::chrono::system_clock::time_point ModificationDate() const
Date on which the sample list was modified.
Definition: sample_list.hpp:468
Collection of data samples.
Definition: sample_list.hpp:239
void Save(const String &fileName) const
Save the sample list to a file.
Definition: sample_list.hpp:553
void MergeClasses(const LabelType &fromLabel, const LabelType &toLabel)
Merge two classes into one class.
Definition: sample_list.hpp:203
std::function< String(const std::vector< float > &labelIn)> LabelTransformVectorToString
Callback for label transformation.
Definition: sample_list.hpp:342
STL class.
std::function< std::vector< float >const String &labelIn)> LabelTransformStringToVector
Callback for label transformation.
Definition: sample_list.hpp:326
Root namespace for the Image Manager interface.
Definition: version.hpp:11
std::vector< TLabelInformation > ReadInfos() const
Retrieves all the items stored in the collection.
Definition: sample_list.hpp:122
The Common Vision Blox image.
Definition: decl_image.hpp:44
String FileName() const
Name of the file from which this image list was loaded (empty string if this image list was neither l...
Definition: sample_list.hpp:413
std::function< String(const String &labelIn)> LabelTransformStringToString
Callback for label transformation.
Definition: sample_list.hpp:318
typename ImageClassificationLabelInfo ::LabelType LabelType
Type of the labels.
Definition: sample_list.hpp:91
String Comment() const
Get the comment text.
Definition: sample_list.hpp:423
int MinSampleCount() const
Number samples in the smallest class of the sample list.
Definition: sample_list.hpp:512
void RemoveAt(int index)
Remove a class by index.
Definition: sample_list.hpp:140
STL class.
void Remove(const LabelType &label)
Remove a class and all the data objects associated with it based on its name.
Definition: sample_list.hpp:151
std::function< std::vector< float >const std::vector< float > &labelIn)> LabelTransformVectorToVector
Callback for label transformation.
Definition: sample_list.hpp:334
int Count() const
Get the number of samples for this collection.
Definition: sample_list.hpp:258
STL class.
std::chrono::system_clock::time_point CreationDate() const
Date on which the sample list was created.
Definition: sample_list.hpp:447
TData ReadData(int index) const
Access one of the sample images.
Definition: sample_list.hpp:271
std::function< std::unique_ptr< Image >const Image &imgIn)> DataTransformImageToImage
Image data transformation callback.
Definition: sample_list.hpp:350
int MaxSampleCount() const
Number samples in the largest class of the sample list.
Definition: sample_list.hpp:525
TLabelInformation ReadInfo(int index) const
Retrieves the indexed item.
Definition: sample_list.hpp:111
void Clear()
Remove all labels (and their associated data) from the sample list.
Definition: sample_list.hpp:168
void SetComment(String comment)
Set the comment text.
Definition: sample_list.hpp:437
int NumSamples() const
Total number of samples in the sample list.
Definition: sample_list.hpp:502
int Count() const
Retrieves the number of elements in the collection.
Definition: sample_list.hpp:99