CVB++ 15.0
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
16namespace Cvb
17{
18CVB_BEGIN_INLINE_NS
19
21namespace SampleDatabase
22{
23
24namespace Private
25{
26// Helpers to validate new/changed labels
27size_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
35inline 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
43inline 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
52inline 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
60inline 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())); // NOLINT(cppcoreguidelines-pro-type-const-cast)
66}
67
68// Generic label transformation callback
69template<typename TLabelOut, typename TLabelIn>
70using LabelTransform = std::function<TLabelOut (const TLabelIn &labelIn)>;
71} /* namespace Private */
72
74
76template <class TLabelInformation>
78{
79public:
80 explicit LabelInfoCollection (const SharedReleaseObjectGuard &sguardSil)
81 : shandleSil_(sguardSil)
82 {}
83
84 LabelInfoCollection (const LabelInfoCollection& other) = delete;
85 LabelInfoCollection& operator= (const LabelInfoCollection& other) = delete;
87 LabelInfoCollection& operator= (LabelInfoCollection && other) = delete;
88
89 virtual ~LabelInfoCollection () = default;
90
91public:
93 using LabelType = typename TLabelInformation::LabelType;
94
96
101 int Count () const
102 {
103 return CVB_CALL_CAPI(SilGetNumLabelEntries(shandleSil_.Handle()));
104 }
105
107
114 {
115 return GetInfo (index);
116 }
117
119
125 {
126 auto count = Count ();
128 for (decltype(count) i = 0; i < count; ++i)
129 {
130 info.push_back (ReadInfo (i));
131 }
132
133 return info;
134 }
135
137
142 void RemoveAt (int index)
143 {
144 CVB_CALL_CAPI_CHECKED(SilDeleteLabel(shandleSil_.Handle(), index));
145 }
146
148
153 void Remove (const LabelType & label)
154 {
155 auto index = LabelToIndex(label);
156 if (index < 0)
157 {
158 throw std::invalid_argument ("cannot remove class because it is not part of the sample database");
159 }
160
161 RemoveAt(index);
162 }
163
165
170 void Clear ()
171 {
172 while (Count () > 0)
173 {
174 RemoveAt (0);
175 }
176 }
177
179
187 void MergeClasses (int fromIndex, int toIndex)
188 {
189 if (fromIndex == toIndex)
190 {
191 return;
192 }
193 Private::Relabel (shandleSil_.Handle (), fromIndex, ReadInfo (toIndex)->Label());
194 }
195
197
205 void MergeClasses (const LabelType & fromLabel, const LabelType & toLabel)
206 {
207 auto fromIndex = LabelToIndex (fromLabel);
208 auto toIndex = LabelToIndex (toLabel);
209 if (fromIndex < 0 || toIndex < 0)
210 {
211 throw std::invalid_argument ("cannot classes, at least one is not part of the collection");
212 }
213
214 MergeClasses (fromIndex, toIndex);
215 }
216
217
218protected:
219 virtual std::unique_ptr<TLabelInformation> GetInfo (int index) const = 0;
220
221 int LabelToIndex (const LabelType &label) const
222 {
223 auto count = Count ();
224 for (int i = 0; i < count; ++i)
225 {
226 if (ReadInfo(i)->Label() == label)
227 {
228 return i;
229 }
230 }
231 return -1;
232 }
233
234protected:
235 SharedReleaseObjectGuard shandleSil_; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
236}; /* class LabelInfoCollection */
237
239
241template <class TData>
243{
244public:
245 explicit SampleCollection (const SharedReleaseObjectGuard &sguardSil)
246 : shandleSil_(sguardSil)
247 {}
248
249 SampleCollection (const SampleCollection& other) = delete;
250 SampleCollection& operator= (const SampleCollection& other) = delete;
251 SampleCollection(SampleCollection&& other) = delete;
252 SampleCollection& operator= (SampleCollection && other) = delete;
253 virtual ~SampleCollection () = default;
254
255public:
257
262 int Count () const
263 {
264 auto label = CVB_CALL_CAPI(SilGetLabel (shandleSil_.Handle(), GetLabelIndex()));
265 return CVB_CALL_CAPI(SilGetNumDataReferences(label));
266 }
267
269
275 TData ReadData (int index) const
276 {
277 auto data = CVB_CALL_CAPI(SilGetDataByLabel (shandleSil_.Handle(), GetLabelIndex(), index));
278 return GetData (data);
279 }
280
282
288 TData RemoveAt (int index)
289 {
290 TData retval = ReadData (index);
291 CVB_CALL_CAPI_CHECKED(SilDeleteDataByLabel(shandleSil_.Handle(), GetLabelIndex(), index));
292 return retval;
293 }
294
295protected:
296 std::shared_ptr<Image> GetImage (CExports::TSILDATA dataHandle) const
297 {
298 return Internal::DoBoolCallObjectOut<Image>([&](void* & resimg)
299 {
300 CVB_CALL_CAPI_CHECKED(SilGetImageData (dataHandle, resimg));
301 return CVB_CALL_CAPI(ShareObject (resimg));
302 });
303 }
304
305 int GetLabelIndex () const
306 {
307 return 0;
308 }
309
310 virtual TData GetData (CExports::TSILDATA dataHandle) const = 0;
311
312private:
313 SharedReleaseObjectGuard shandleSil_;
314}; /* class SampleCollection */
315
317
323
325
331
333
339
341
347
349
355
357
364{
365
366public:
367
368 SampleList(const SampleList& other) = delete;
369 SampleList& operator=(const SampleList& other) = delete;
370 SampleList(SampleList&& other) = delete;
371 SampleList& operator=(SampleList&& other) = delete;
372 virtual ~SampleList() = default;
373
374protected:
375 explicit SampleList (ReleaseObjectGuard&& guardSil, const String &fileName = String())
376 : shandleSil_(std::move(guardSil)),
377 fileName_ (fileName)
378 {}
379
380
381
382
383 // Helper to load a sample list from file
384 static ReleaseObjectGuard LoadInternal (const String & fileName, CExports::TSilLabelType expectedLabelType)
385 {
386 CExports::TSIL sil = nullptr;
387
388 CVB_CALL_CAPI_CHECKED (SilLoadTyped (fileName.c_str(), sil));
389 ReleaseObjectGuard silGuard (sil);
390
391 auto dataType = CVB_CALL_CAPI (SilGetDataTypeEnum(silGuard.Handle()));
392 auto labelType = CVB_CALL_CAPI (SilGetLabelTypeEnum(silGuard.Handle()));
393 if (dataType != CExports::SDT_ImageData)
394 {
395 throw std::invalid_argument ("the loaded SIL file does not contain image data type");
396 }
397 if (labelType != expectedLabelType)
398 {
399 throw std::invalid_argument ("the loaded SIL file does not contain expected label type");
400 }
401
402 return silGuard;
403 }
404
405public:
407
413 void * Handle() const noexcept
414 {
415 return shandleSil_.Handle();
416 }
417
419
424 {
425 return fileName_;
426 }
427
429
434 {
435 size_t bufferSize = 0;
436 CVB_CALL_CAPI_CHECKED (SilGetCommentTyped(Handle(), static_cast<Char*>(nullptr), bufferSize));
437 std::vector<Char> comment (bufferSize);
438 CVB_CALL_CAPI_CHECKED (SilGetCommentTyped(Handle(), comment.data(), bufferSize));
439 return String (comment.begin(), comment.end());
440 }
441
443
447 void SetComment(String comment)
448 {
449 CVB_CALL_CAPI_CHECKED (SilSetCommentTyped (Handle(), comment.c_str()));
450 }
451
453
457 std::chrono::system_clock::time_point CreationDate() const
458 {
459 CExports::CV_SYSTEMTIME st = { 0 };
460 CVB_CALL_CAPI_CHECKED (SilGetCreationDate(Handle(), st));
461 std::tm tm = {};
462 tm.tm_sec = st.wSecond;
463 tm.tm_min = st.wMinute;
464 tm.tm_hour = st.wHour;
465 tm.tm_mday = st.wDay;
466 tm.tm_mon = st.wMonth - 1;
467 tm.tm_year = st.wYear - 1900;
468 tm.tm_isdst = -1;
469
470 return std::chrono::system_clock::from_time_t (std::mktime (&tm));
471 }
472
474
478 std::chrono::system_clock::time_point ModificationDate() const
479 {
480 CExports::CV_SYSTEMTIME st = { 0 };
481 CVB_CALL_CAPI_CHECKED (SilGetModificationDate(Handle(), st));
482 std::tm tm = {};
483 tm.tm_sec = st.wSecond;
484 tm.tm_min = st.wMinute;
485 tm.tm_hour = st.wHour;
486 tm.tm_mday = st.wDay;
487 tm.tm_mon = st.wMonth - 1;
488 tm.tm_year = st.wYear - 1900;
489 tm.tm_isdst = -1;
490
491 return std::chrono::system_clock::from_time_t (std::mktime (&tm));
492 }
493
495
499 int NumClasses() const
500 {
501 size_t numClasses = 0, dummy1 = 0, dummy2 = 0;
503 CVB_CALL_CAPI_CHECKED(SilGetStatistics(Handle(), numClasses, dummy1, dummy2, dummy3));
504 return static_cast<int>(numClasses);
505 }
506
508
512 int NumSamples() const
513 {
514 return static_cast<int>(CVB_CALL_CAPI(SilGetNumDataEntries(Handle())));
515 }
516
518
522 int MinSampleCount() const
523 {
524 size_t minCount = 0, dummy1 = 0, dummy2 = 0;
526 CVB_CALL_CAPI_CHECKED(SilGetStatistics(Handle(), dummy1, minCount, dummy2, dummy3));
527 return static_cast<int>(minCount);
528 }
529
531
535 int MaxSampleCount() const
536 {
537 size_t maxCount = 0, dummy1 = 0, dummy2 = 0;
539 CVB_CALL_CAPI_CHECKED(SilGetStatistics(Handle(), dummy1, dummy2, maxCount, dummy3));
540 return static_cast<int>(maxCount);
541 }
542
544
548 double AverageSampleCount() const
549 {
550 size_t dummy1 = 0, dummy2 = 0, dummy3 = 0;
551 double avgCount = std::numeric_limits<double>::quiet_NaN();
552 CVB_CALL_CAPI_CHECKED(SilGetStatistics(Handle(), dummy1, dummy2, dummy3, avgCount));
553 return avgCount;
554 }
555
557
563 void Save (const String & fileName) const
564 {
565 CVB_CALL_CAPI_CHECKED (SilStoreTyped (Handle(), fileName.c_str()));
566 fileName_ = fileName;
567 }
568
569protected:
570 // Sample image list transformation workers
571 template <class TOut>
572 std::unique_ptr<TOut> TransformData (DataTransformImageToImage cbk) const
573 {
574 CExports::TSIL sil = nullptr;
575
576 CVB_CALL_CAPI_CHECKED (SilTransformDataList (Handle (), NativeDataTransformCallback, &cbk, sil));
577 ReleaseObjectGuard silGuard (sil);
578
579 return TOut::FromHandle (std::move (silGuard));
580 }
581
582 template <class TOut, class TLabelOut, class TLabelIn>
583 std::unique_ptr<TOut> TransformLabels (Private::LabelTransform<TLabelOut, TLabelIn> cbk) const
584 {
585 CExports::TSIL sil = nullptr;
586
587 CVB_CALL_CAPI_CHECKED (SilTransformLabelList (Handle (), NativeLabelTransformCallback<TLabelOut, TLabelIn>, &cbk, sil));
588 ReleaseObjectGuard silGuard (sil);
589
590 return TOut::FromHandle (std::move (silGuard));
591 }
592
593private:
594 static CExports::cvbbool_t __stdcall NativeDataTransformCallback (void* pPrivate, CExports::TSILDATA DataIn, CExports::TSILDATA& DataOut)
595 {
596 try
597 {
598 DataTransformImageToImage *cbk = reinterpret_cast<DataTransformImageToImage*> (pPrivate);
599
600 auto imgIn = Internal::DoBoolCallObjectOut<Image>([&](void* & resimg)
601 {
602 CVB_CALL_CAPI_CHECKED(SilGetImageData (DataIn, resimg));
603 return CVB_CALL_CAPI(ShareObject (resimg));
604 });
605
606 auto imgOut = (*cbk) (*imgIn);
607 DataOut = CVB_CALL_CAPI(SilCreateImageData(imgOut->Handle(), 0, 0, imgOut->Size().Width(), imgOut->Size().Height()));
608 return true;
609 }
610 catch (const std::exception &)
611 {
612 return false;
613 }
614 }
615
616 template <class TLabelOut, class TLabelIn>
617 static CExports::cvbbool_t __stdcall NativeLabelTransformCallback (void* pPrivate, CExports::TSILLABEL LabelIn, CExports::TSILLABEL& LabelOut)
618 {
619 try
620 {
621 Private::LabelTransform<TLabelOut, TLabelIn> *cbk = reinterpret_cast<Private::LabelTransform<TLabelOut, TLabelIn>*> (pPrivate);
622
623 TLabelIn objectIn;
624 NativeLabelToObject (LabelIn, objectIn);
625
626 auto objectOut = (*cbk) (objectIn);
627 LabelOut = CreateNativeLabel (objectOut);
628 return true;
629 }
630 catch (const std::exception &)
631 {
632 return false;
633 }
634 }
635
636 static void NativeLabelToObject (CExports::TSILLABEL label, String &object)
637 {
638 size_t bufferSize = 0;
639 CVB_CALL_CAPI_CHECKED (SilGetStringLabelTyped(label, static_cast<Char*>(nullptr), bufferSize));
640 std::vector<Char> stringLabel (bufferSize);
641 CVB_CALL_CAPI_CHECKED (SilGetStringLabelTyped(label, stringLabel.data(), bufferSize));
642 object.assign (stringLabel.begin (), stringLabel.end ());
643 }
644
645 static CExports::TSILLABEL CreateNativeLabel (const String &object)
646 {
647 return CVB_CALL_CAPI(SilCreateStringLabelTyped(object.c_str()));
648 }
649
650 static void NativeLabelToObject (CExports::TSILLABEL label, std::vector<float> &object)
651 {
652 size_t dim = 0;
653 CVB_CALL_CAPI_CHECKED (SilGetFloatVectorLabel(label, static_cast<float*>(nullptr), dim));
654 object.resize (dim);
655 CVB_CALL_CAPI_CHECKED (SilGetFloatVectorLabel(label, object.data(), dim));
656 }
657
658 static CExports::TSILLABEL CreateNativeLabel (const std::vector<float> &object)
659 {
660 return CVB_CALL_CAPI(SilCreateVectorLabel(object.data(), object.size()));
661 }
662
663protected:
664 SharedReleaseObjectGuard shandleSil_; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
665
666private:
667 mutable String fileName_;
668}; /* class SampleList */
669
672
673
674} /* namespace SampleDatabase */
675CVB_END_INLINE_NS
676} /* namespace Cvb */
The Common Vision Blox image.
Definition: decl_image.hpp:45
Information collection for class labels.
Definition: sample_list.hpp:78
void MergeClasses(const LabelType &fromLabel, const LabelType &toLabel)
Merge two classes into one class.
Definition: sample_list.hpp:205
std::unique_ptr< TLabelInformation > ReadInfo(int index) const
Retrieves the indexed item.
Definition: sample_list.hpp:113
typename TLabelInformation::LabelType LabelType
Type of the labels.
Definition: sample_list.hpp:93
void Remove(const LabelType &label)
Remove a class and all the data objects associated with it based on its name.
Definition: sample_list.hpp:153
int Count() const
Retrieves the number of elements in the collection.
Definition: sample_list.hpp:101
void Clear()
Remove all labels (and their associated data) from the sample list.
Definition: sample_list.hpp:170
void MergeClasses(int fromIndex, int toIndex)
Merge two classes into one class.
Definition: sample_list.hpp:187
void RemoveAt(int index)
Remove a class by index.
Definition: sample_list.hpp:142
std::vector< std::shared_ptr< TLabelInformation > > ReadInfos() const
Retrieves all the items stored in the collection.
Definition: sample_list.hpp:124
Collection of data samples.
Definition: sample_list.hpp:243
TData RemoveAt(int index)
Remove a sample.
Definition: sample_list.hpp:288
int Count() const
Get the number of samples for this collection.
Definition: sample_list.hpp:262
TData ReadData(int index) const
Access one of the sample images.
Definition: sample_list.hpp:275
Base class for sample lists.
Definition: sample_list.hpp:364
int NumClasses() const
Number of distinguishable classes in the sample list.
Definition: sample_list.hpp:499
std::chrono::system_clock::time_point CreationDate() const
Date on which the sample list was created.
Definition: sample_list.hpp:457
String Comment() const
Get the comment text.
Definition: sample_list.hpp:433
void Save(const String &fileName) const
Save the sample list to a file.
Definition: sample_list.hpp:563
double AverageSampleCount() const
Average number samples in per class of the sample list.
Definition: sample_list.hpp:548
void SetComment(String comment)
Set the comment text.
Definition: sample_list.hpp:447
std::chrono::system_clock::time_point ModificationDate() const
Date on which the sample list was modified.
Definition: sample_list.hpp:478
int MaxSampleCount() const
Number samples in the largest class of the sample list.
Definition: sample_list.hpp:535
int NumSamples() const
Total number of samples in the sample list.
Definition: sample_list.hpp:512
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:423
int MinSampleCount() const
Number samples in the smallest class of the sample list.
Definition: sample_list.hpp:522
void * Handle() const noexcept
Classic API SIL handle.
Definition: sample_list.hpp:413
@ Private
Private name space.
std::function< std::vector< float >(const std::vector< float > &labelIn)> LabelTransformVectorToVector
Callback for label transformation.
Definition: sample_list.hpp:338
std::function< String(const String &labelIn)> LabelTransformStringToString
Callback for label transformation.
Definition: sample_list.hpp:322
std::function< String(const std::vector< float > &labelIn)> LabelTransformVectorToString
Callback for label transformation.
Definition: sample_list.hpp:346
std::function< std::vector< float >(const String &labelIn)> LabelTransformStringToVector
Callback for label transformation.
Definition: sample_list.hpp:330
std::function< std::unique_ptr< Image >(const Image &imgIn)> DataTransformImageToImage
Image data transformation callback.
Definition: sample_list.hpp:354
Root namespace for the Image Manager interface.
Definition: c_barcode.h:24
char Char
Character type for wide characters or unicode characters.
Definition: string.hpp:70
std::string String
String for wide characters or unicode characters.
Definition: string.hpp:56
T quiet_NaN(T... args)