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{
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()),
66 label.size())); // NOLINT(cppcoreguidelines-pro-type-const-cast)
67 }
68
69 // Generic label transformation callback
70 template <typename TLabelOut, typename TLabelIn>
71 using LabelTransform = std::function<TLabelOut(const TLabelIn &labelIn)>;
72 } /* namespace Private */
73
75
77 template <class TLabelInformation>
78 class LabelInfoCollection
79 {
80 public:
81 explicit LabelInfoCollection(const SharedReleaseObjectGuard &sguardSil)
82 : shandleSil_(sguardSil)
83 {
84 }
85
86 LabelInfoCollection(const LabelInfoCollection &other) = delete;
87 LabelInfoCollection &operator=(const LabelInfoCollection &other) = delete;
88 LabelInfoCollection(LabelInfoCollection &&other) = delete;
89 LabelInfoCollection &operator=(LabelInfoCollection &&other) = delete;
90
91 virtual ~LabelInfoCollection() = default;
92
93 public:
95 using LabelType = typename TLabelInformation::LabelType;
96
98
103 int Count() const
104 {
105 return CVB_CALL_CAPI(SilGetNumLabelEntries(shandleSil_.Handle()));
106 }
107
109
116 {
117 return GetInfo(index);
118 }
119
121
127 {
128 auto count = Count();
130 for (decltype(count) i = 0; i < count; ++i)
131 {
132 info.push_back(ReadInfo(i));
133 }
134
135 return info;
136 }
137
139
144 void RemoveAt(int index)
145 {
146 CVB_CALL_CAPI_CHECKED(SilDeleteLabel(shandleSil_.Handle(), index));
147 }
148
150
155 void Remove(const LabelType &label)
156 {
157 auto index = LabelToIndex(label);
158 if (index < 0)
159 {
160 throw std::invalid_argument("cannot remove class because it is not part of the sample database");
161 }
162
163 RemoveAt(index);
164 }
165
167
172 void Clear()
173 {
174 while (Count() > 0)
175 {
176 RemoveAt(0);
177 }
178 }
179
181
189 void MergeClasses(int fromIndex, int toIndex)
190 {
191 if (fromIndex == toIndex)
192 {
193 return;
194 }
195 Private::Relabel(shandleSil_.Handle(), fromIndex, ReadInfo(toIndex)->Label());
196 }
197
199
207 void MergeClasses(const LabelType &fromLabel, const LabelType &toLabel)
208 {
209 auto fromIndex = LabelToIndex(fromLabel);
210 auto toIndex = LabelToIndex(toLabel);
211 if (fromIndex < 0 || toIndex < 0)
212 {
213 throw std::invalid_argument("cannot classes, at least one is not part of the collection");
214 }
215
216 MergeClasses(fromIndex, toIndex);
217 }
218
219 protected:
220 virtual std::unique_ptr<TLabelInformation> GetInfo(int index) const = 0;
221
222 int LabelToIndex(const LabelType &label) const
223 {
224 auto count = Count();
225 for (int i = 0; i < count; ++i)
226 {
227 if (ReadInfo(i)->Label() == label)
228 {
229 return i;
230 }
231 }
232 return -1;
233 }
234
235 protected:
236 SharedReleaseObjectGuard shandleSil_; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
237 }; /* class LabelInfoCollection */
238
240
242 template <class TData>
243 class SampleCollection
244 {
245 public:
246 explicit SampleCollection(const SharedReleaseObjectGuard &sguardSil)
247 : shandleSil_(sguardSil)
248 {
249 }
250
251 SampleCollection(const SampleCollection &other) = delete;
252 SampleCollection &operator=(const SampleCollection &other) = delete;
253 SampleCollection(SampleCollection &&other) = delete;
254 SampleCollection &operator=(SampleCollection &&other) = delete;
255 virtual ~SampleCollection() = default;
256
257 public:
259
264 int Count() const
265 {
266 auto label = CVB_CALL_CAPI(SilGetLabel(shandleSil_.Handle(), GetLabelIndex()));
267 return CVB_CALL_CAPI(SilGetNumDataReferences(label));
268 }
269
271
277 TData ReadData(int index) const
278 {
279 auto data = CVB_CALL_CAPI(SilGetDataByLabel(shandleSil_.Handle(), GetLabelIndex(), index));
280 return GetData(data);
281 }
282
284
290 TData RemoveAt(int index)
291 {
292 TData retval = ReadData(index);
293 CVB_CALL_CAPI_CHECKED(SilDeleteDataByLabel(shandleSil_.Handle(), GetLabelIndex(), index));
294 return retval;
295 }
296
297 protected:
298 std::shared_ptr<Image> GetImage(CExports::TSILDATA dataHandle) const
299 {
300 return Internal::DoBoolCallObjectOut<Image>([&](void *&resimg) {
301 CVB_CALL_CAPI_CHECKED(SilGetImageData(dataHandle, resimg));
302 return CVB_CALL_CAPI(ShareObject(resimg));
303 });
304 }
305
306 int GetLabelIndex() const
307 {
308 return 0;
309 }
310
311 virtual TData GetData(CExports::TSILDATA dataHandle) const = 0;
312
313 private:
314 SharedReleaseObjectGuard shandleSil_;
315 }; /* class SampleCollection */
316
318
324
326
332
334
340
342
348
350
356
358
364 class SampleList
365 {
366
367 public:
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
374 protected:
375 explicit SampleList(ReleaseObjectGuard &&guardSil, const String &fileName = String())
376 : shandleSil_(std::move(guardSil))
377 , fileName_(fileName)
378 {
379 }
380
381 // Helper to load a sample list from file
382 static ReleaseObjectGuard LoadInternal(const String &fileName, CExports::TSilLabelType expectedLabelType)
383 {
384 CExports::TSIL sil = nullptr;
385
386 CVB_CALL_CAPI_CHECKED(SilLoadTyped(fileName.c_str(), sil));
387 ReleaseObjectGuard silGuard(sil);
388
389 auto dataType = CVB_CALL_CAPI(SilGetDataTypeEnum(silGuard.Handle()));
390 auto labelType = CVB_CALL_CAPI(SilGetLabelTypeEnum(silGuard.Handle()));
391 if (dataType != CExports::SDT_ImageData)
392 {
393 throw std::invalid_argument("the loaded SIL file does not contain image data type");
394 }
395 if (labelType != expectedLabelType)
396 {
397 throw std::invalid_argument("the loaded SIL file does not contain expected label type");
398 }
399
400 return silGuard;
401 }
402
403 public:
405
411 void *Handle() const noexcept
412 {
413 return shandleSil_.Handle();
414 }
415
418
423 {
424 return fileName_;
425 }
426
428
433 {
434 size_t bufferSize = 0;
435 CVB_CALL_CAPI_CHECKED(SilGetCommentTyped(Handle(), static_cast<Char *>(nullptr), bufferSize));
436 std::vector<Char> comment(bufferSize);
437 CVB_CALL_CAPI_CHECKED(SilGetCommentTyped(Handle(), comment.data(), bufferSize));
438 return String(comment.begin(), comment.end());
439 }
440
442
446 void SetComment(String comment)
447 {
448 CVB_CALL_CAPI_CHECKED(SilSetCommentTyped(Handle(), comment.c_str()));
449 }
450
452
456 std::chrono::system_clock::time_point CreationDate() const
457 {
458 CExports::CV_SYSTEMTIME st = {0};
459 CVB_CALL_CAPI_CHECKED(SilGetCreationDate(Handle(), st));
460 std::tm tm = {};
461 tm.tm_sec = st.wSecond;
462 tm.tm_min = st.wMinute;
463 tm.tm_hour = st.wHour;
464 tm.tm_mday = st.wDay;
465 tm.tm_mon = st.wMonth - 1;
466 tm.tm_year = st.wYear - 1900;
467 tm.tm_isdst = -1;
468
470 }
471
473
477 std::chrono::system_clock::time_point ModificationDate() const
478 {
479 CExports::CV_SYSTEMTIME st = {0};
480 CVB_CALL_CAPI_CHECKED(SilGetModificationDate(Handle(), st));
481 std::tm tm = {};
482 tm.tm_sec = st.wSecond;
483 tm.tm_min = st.wMinute;
484 tm.tm_hour = st.wHour;
485 tm.tm_mday = st.wDay;
486 tm.tm_mon = st.wMonth - 1;
487 tm.tm_year = st.wYear - 1900;
488 tm.tm_isdst = -1;
489
491 }
492
494
498 int NumClasses() const
499 {
500 size_t numClasses = 0, dummy1 = 0, dummy2 = 0;
502 CVB_CALL_CAPI_CHECKED(SilGetStatistics(Handle(), numClasses, dummy1, dummy2, dummy3));
503 return static_cast<int>(numClasses);
504 }
505
507
511 int NumSamples() const
512 {
513 return static_cast<int>(CVB_CALL_CAPI(SilGetNumDataEntries(Handle())));
514 }
515
517
521 int MinSampleCount() const
522 {
523 size_t minCount = 0, dummy1 = 0, dummy2 = 0;
525 CVB_CALL_CAPI_CHECKED(SilGetStatistics(Handle(), dummy1, minCount, dummy2, dummy3));
526 return static_cast<int>(minCount);
527 }
528
530
534 int MaxSampleCount() const
535 {
536 size_t maxCount = 0, dummy1 = 0, dummy2 = 0;
538 CVB_CALL_CAPI_CHECKED(SilGetStatistics(Handle(), dummy1, dummy2, maxCount, dummy3));
539 return static_cast<int>(maxCount);
540 }
541
543
547 double AverageSampleCount() const
548 {
549 size_t dummy1 = 0, dummy2 = 0, dummy3 = 0;
550 double avgCount = std::numeric_limits<double>::quiet_NaN();
551 CVB_CALL_CAPI_CHECKED(SilGetStatistics(Handle(), dummy1, dummy2, dummy3, avgCount));
552 return avgCount;
553 }
554
556
562 void Save(const String &fileName) const
563 {
564 CVB_CALL_CAPI_CHECKED(SilStoreTyped(Handle(), fileName.c_str()));
565 fileName_ = fileName;
566 }
567
568 protected:
569 // Sample image list transformation workers
570 template <class TOut>
571 std::unique_ptr<TOut> TransformData(DataTransformImageToImage cbk) const
572 {
573 CExports::TSIL sil = nullptr;
574
575 CVB_CALL_CAPI_CHECKED(SilTransformDataList(Handle(), NativeDataTransformCallback, &cbk, sil));
576 ReleaseObjectGuard silGuard(sil);
577
578 return TOut::FromHandle(std::move(silGuard));
579 }
580
581 template <class TOut, class TLabelOut, class TLabelIn>
582 std::unique_ptr<TOut> TransformLabels(Private::LabelTransform<TLabelOut, TLabelIn> cbk) const
583 {
584 CExports::TSIL sil = nullptr;
585
586 CVB_CALL_CAPI_CHECKED(
587 SilTransformLabelList(Handle(), NativeLabelTransformCallback<TLabelOut, TLabelIn>, &cbk, sil));
588 ReleaseObjectGuard silGuard(sil);
589
590 return TOut::FromHandle(std::move(silGuard));
591 }
592
593 private:
594 static CExports::cvbbool_t __stdcall NativeDataTransformCallback(void *pPrivate, CExports::TSILDATA DataIn,
595 CExports::TSILDATA &DataOut)
596 {
597 try
598 {
599 DataTransformImageToImage *cbk = reinterpret_cast<DataTransformImageToImage *>(pPrivate);
600
601 auto imgIn = Internal::DoBoolCallObjectOut<Image>([&](void *&resimg) {
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(
608 SilCreateImageData(imgOut->Handle(), 0, 0, imgOut->Size().Width(), imgOut->Size().Height()));
609 return true;
610 }
611 catch (const std::exception &)
612 {
613 return false;
614 }
615 }
616
617 template <class TLabelOut, class TLabelIn>
618 static CExports::cvbbool_t __stdcall NativeLabelTransformCallback(void *pPrivate, CExports::TSILLABEL LabelIn,
619 CExports::TSILLABEL &LabelOut)
620 {
621 try
622 {
623 Private::LabelTransform<TLabelOut, TLabelIn> *cbk =
624 reinterpret_cast<Private::LabelTransform<TLabelOut, TLabelIn> *>(pPrivate);
625
626 TLabelIn objectIn;
627 NativeLabelToObject(LabelIn, objectIn);
628
629 auto objectOut = (*cbk)(objectIn);
630 LabelOut = CreateNativeLabel(objectOut);
631 return true;
632 }
633 catch (const std::exception &)
634 {
635 return false;
636 }
637 }
638
639 static void NativeLabelToObject(CExports::TSILLABEL label, String &object)
640 {
641 size_t bufferSize = 0;
642 CVB_CALL_CAPI_CHECKED(SilGetStringLabelTyped(label, static_cast<Char *>(nullptr), bufferSize));
643 std::vector<Char> stringLabel(bufferSize);
644 CVB_CALL_CAPI_CHECKED(SilGetStringLabelTyped(label, stringLabel.data(), bufferSize));
645 object.assign(stringLabel.begin(), stringLabel.end());
646 }
647
648 static CExports::TSILLABEL CreateNativeLabel(const String &object)
649 {
650 return CVB_CALL_CAPI(SilCreateStringLabelTyped(object.c_str()));
651 }
652
653 static void NativeLabelToObject(CExports::TSILLABEL label, std::vector<float> &object)
654 {
655 size_t dim = 0;
656 CVB_CALL_CAPI_CHECKED(SilGetFloatVectorLabel(label, static_cast<float *>(nullptr), dim));
657 object.resize(dim);
658 CVB_CALL_CAPI_CHECKED(SilGetFloatVectorLabel(label, object.data(), dim));
659 }
660
661 static CExports::TSILLABEL CreateNativeLabel(const std::vector<float> &object)
662 {
663 return CVB_CALL_CAPI(SilCreateVectorLabel(object.data(), object.size()));
664 }
665
666 protected:
667 SharedReleaseObjectGuard shandleSil_; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
668
669 private:
670 mutable String fileName_;
671 }; /* class SampleList */
672
675
676 } /* namespace SampleDatabase */
677 CVB_END_INLINE_NS
678} /* namespace Cvb */
The Common Vision Blox image.
Definition decl_image.hpp:50
void MergeClasses(const LabelType &fromLabel, const LabelType &toLabel)
Merge two classes into one class.
Definition sample_list.hpp:207
std::unique_ptr< TLabelInformation > ReadInfo(int index) const
Retrieves the indexed item.
Definition sample_list.hpp:115
typename TLabelInformation::LabelType LabelType
Type of the labels.
Definition sample_list.hpp:95
void Remove(const LabelType &label)
Remove a class and all the data objects associated with it based on its name.
Definition sample_list.hpp:155
int Count() const
Retrieves the number of elements in the collection.
Definition sample_list.hpp:103
void Clear()
Remove all labels (and their associated data) from the sample list.
Definition sample_list.hpp:172
void MergeClasses(int fromIndex, int toIndex)
Merge two classes into one class.
Definition sample_list.hpp:189
void RemoveAt(int index)
Remove a class by index.
Definition sample_list.hpp:144
std::vector< std::shared_ptr< TLabelInformation > > ReadInfos() const
Retrieves all the items stored in the collection.
Definition sample_list.hpp:126
TData RemoveAt(int index)
Remove a sample.
Definition sample_list.hpp:290
int Count() const
Get the number of samples for this collection.
Definition sample_list.hpp:264
TData ReadData(int index) const
Access one of the sample images.
Definition sample_list.hpp:277
int NumClasses() const
Number of distinguishable classes in the sample list.
Definition sample_list.hpp:498
std::chrono::system_clock::time_point CreationDate() const
Date on which the sample list was created.
Definition sample_list.hpp:456
String Comment() const
Get the comment text.
Definition sample_list.hpp:432
void Save(const String &fileName) const
Save the sample list to a file.
Definition sample_list.hpp:562
double AverageSampleCount() const
Average number samples in per class of the sample list.
Definition sample_list.hpp:547
void SetComment(String comment)
Set the comment text.
Definition sample_list.hpp:446
std::chrono::system_clock::time_point ModificationDate() const
Date on which the sample list was modified.
Definition sample_list.hpp:477
int MaxSampleCount() const
Number samples in the largest class of the sample list.
Definition sample_list.hpp:534
int NumSamples() const
Total number of samples in the sample list.
Definition sample_list.hpp:511
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:422
int MinSampleCount() const
Number samples in the smallest class of the sample list.
Definition sample_list.hpp:521
void * Handle() const noexcept
Classic API SIL handle.
Definition sample_list.hpp:411
cvbbool_t ShareObject(OBJ Object)
T mktime(T... args)
T move(T... args)
Namespace for the SampleDatabase package.
Definition decl_classification_sil.hpp:20
std::function< std::vector< float >(const std::vector< float > &labelIn)> LabelTransformVectorToVector
Callback for label transformation.
Definition sample_list.hpp:339
std::shared_ptr< SampleList > SampleListPtr
Convenience shared pointer for SampleList.
Definition sample_list.hpp:674
std::function< std::vector< float >(const String &labelIn)> LabelTransformStringToVector
Callback for label transformation.
Definition sample_list.hpp:331
std::function< String(const std::vector< float > &labelIn)> LabelTransformVectorToString
Callback for label transformation.
Definition sample_list.hpp:347
std::function< std::unique_ptr< Image >(const Image &imgIn)> DataTransformImageToImage
Image data transformation callback.
Definition sample_list.hpp:355
std::function< String(const String &labelIn)> LabelTransformStringToString
Callback for label transformation.
Definition sample_list.hpp:323
Root namespace for the Image Manager interface.
Definition c_bayer_to_rgb.h:17
char Char
Character type for wide characters or unicode characters.
Definition string.hpp:63
std::string String
String for wide characters or unicode characters.
Definition string.hpp:49
T quiet_NaN(T... args)