CVB++ 14.1
classifier.hpp
1#pragma once
2
3#include <memory>
4
5#include "../global.hpp"
6#include "../string.hpp"
7#include "../rect.hpp"
8#include "../angle.hpp"
9#include "../value_range.hpp"
10#include "../_detail/detail_pixel_list.hpp"
11#include "../image.hpp"
12#include "../exception.hpp"
13
14#include "search_result.hpp"
15#include "shapefinder2.hpp"
16
17#include "../_cexports/c_sf_private.h"
18
19
20namespace Cvb
21{
22CVB_BEGIN_INLINE_NS
23
24template <>
25inline HandleGuard<ShapeFinder2::Classifier>::HandleGuard(void * handle) noexcept
26 : HandleGuard<ShapeFinder2::Classifier>(handle, [](void* handle) { CVB_CALL_CAPI(ReleaseObject(handle)); })
27{
28}
29
30namespace ShapeFinder2
31{
32
33
35
37class Classifier final
38{
39public:
40
42
49 static std::unique_ptr<Classifier> FromHandle(HandleGuard<Classifier>&& guard)
50 {
51 if (!guard.Handle())
52 throw std::runtime_error("handle must not be null");
53
54 auto classifier = std::unique_ptr<Classifier>(new Classifier(std::move(guard)));
55 return classifier;
56 }
57
59
64 static std::unique_ptr<Classifier> Create(const String & fileName)
65 {
66 return std::make_unique<Classifier>(fileName);
67 }
68
70
74 explicit Classifier(const String & fileName)
75 : Classifier(std::move(*Load(fileName)))
76 {
77 fileName_ = fileName; // NOLINT(cppcoreguidelines-prefer-member-initializer)
78 Init();
79 }
80
81 Classifier(const Classifier& other) noexcept = delete;
82 Classifier& operator=(const Classifier& other) = delete;
83 Classifier(Classifier&& other) noexcept = default;
84 Classifier& operator=(Classifier && other) = default;
85 ~Classifier() = default;
86
88
94 void * Handle() const noexcept
95 {
96 return handle_.Handle();
97 }
98
100
104 void Save(const String & fileName) const
105 {
106 if (!CVB_CALL_CAPI(StoreSFTyped(Handle(), fileName.c_str())))
107 Utilities::SystemInfo::ThrowLastError();
108 }
109
111
117 {
118 if (layer < -1 || layer >= NumLayers())
119 throw std::out_of_range("layer value must be in [-1.0, <NumLayers]");
120
121 HandleGuard<Image> guard(CExports::GetSFImage(static_cast<CExports::cvbdim_t>(layer), Handle()));
122 return Image::FromHandle<Image>(std::move(guard));
123 }
124
126
130 int NumLayers() const noexcept
131 {
132 return CExports::GetSFClassNumber(Handle());
133 }
134
136
141 {
142 return fileName_;
143 }
144
146
150 void SetComment(const String & comment) noexcept
151 {
152 CVB_CALL_CAPI(SetSFCommentTyped(Handle(), comment.c_str()));
153 }
154
156
160 String Comment() const noexcept
161 {
162 Char *strComment = nullptr;
163 CVB_CALL_CAPI(GetSFCommentTyped(Handle(), strComment));
164 return ((strComment != nullptr) ? String(strComment) : String());
165 }
166
168
173 {
174 int val = CExports::GetSFGradienttype(Handle()) & 0xFF;
175 return static_cast<ShapeFinder2::GradientType>(val);
176 }
177
179
183 Rect<int> FeatureWindow() const noexcept
184 {
185 return featureWindow_;
186 }
187
189
193 int ContrastThreshold() const noexcept
194 {
195 return CExports::GetSFThreshold(Handle());
196 }
197
199
203 void SetContrastThreshold(int threshold)
204 {
205 if (!CExports::SetSFThreshold(Handle(), threshold))
206 Utilities::SystemInfo::ThrowLastError();
207 }
208
210
214 Angle AngularTolerance() const noexcept
215 {
216 auto byteValue = CExports::GetSFAngularTolerance(Handle());
217 auto rad = byteValue < 128 ? static_cast<double>(byteValue) * CVB_M_PI / 127.0 : (static_cast<double>(byteValue) - 255.0) * CVB_M_PI / 127.0;
218 return Cvb::Angle::FromRadians(rad);
219 }
220
222
226 void SetAngularTolerance(Angle angularTolerance)
227 {
228 angularTolerance.SetIsTrimmed(true); // limit to +/- M_PI
229 auto rad = angularTolerance.Rad();
230 auto byteValue = static_cast<std::uint8_t>(std::round(rad > 0 ? rad * 127.0 / CVB_M_PI : 255.0 - (rad * 127.0 / CVB_M_PI)));
231
232 if (!CExports::SetSFAngularTolerance(Handle(), byteValue))
233 Utilities::SystemInfo::ThrowLastError();
234 }
235
237
241 int FeatureCount() const noexcept
242 {
243 return CExports::GetSFFeatureNumber(Handle());
244 }
245
247
253 bool UseCuda(CudaStatus status) const noexcept
254 {
255 return CExports::SF2UseCuda(Handle(), static_cast<CExports::SF2CudaStatus>(status));
256 }
257
259
271 std::vector<SearchResult> SearchAll(const ImagePlane & plane, Rect<int> aoi, PrecisionMode precision, double relativeThreshold, int minimumThreshold, int coarseLocality, ValueRange<Angle> rotationRange, ValueRange<double> scaleRange)
272 {
273 CExports::TSearchAllParams searchParams = GetSearchAllParameters(precision, relativeThreshold, minimumThreshold, coarseLocality);
274 if (!CExports::SetSF2SearchAllPars(Handle(), searchParams))
275 Utilities::SystemInfo::ThrowLastError();
276 CExports::TSymmetryParams symmetryLimits = GetSymmetryParameters(rotationRange, scaleRange);
277
278 CExports::PIXELLIST lst = nullptr;
279 if (!CExports::SF2SearchEx(Handle(), plane.Parent().Handle(), plane.Plane(), aoi.Left(), aoi.Top(), aoi.Right(), aoi.Bottom(), symmetryLimits, lst))
280 Utilities::SystemInfo::ThrowLastError();
281
282 return ResultListFromPixelList(precision, lst);
283 }
284
286
296 std::vector<SearchResult> SearchAll(const ImagePlane & plane, Rect<int> aoi, PrecisionMode precision, double relativeThreshold, int minimumThreshold, int coarseLocality)
297 {
298 CExports::TSearchAllParams searchParams = GetSearchAllParameters(precision, relativeThreshold, minimumThreshold, coarseLocality);
299 if (!CExports::SetSF2SearchAllPars(Handle(), searchParams))
300 Utilities::SystemInfo::ThrowLastError();
301
302 CExports::PIXELLIST lst = nullptr;
303 if (!CExports::SF2Search(Handle(), plane.Parent().Handle(), plane.Plane(), aoi.Left(), aoi.Top(), aoi.Right(), aoi.Bottom(), lst))
304 Utilities::SystemInfo::ThrowLastError();
305
306 return ResultListFromPixelList(precision, lst);
307 }
308
310
314 Rect<int> TrainingWindow() const noexcept
315 {
316 return trainingWindow_;
317 }
318
320
325 {
326 return fineFeatures_->ToPoints();
327 }
328
330
335 {
336 return coarseFeatures_->ToPoints();
337 }
338
340
344 int CoarseScale() const noexcept
345 {
346 return coarseScale_;
347 }
348
350
355 {
356 return rotation_;
357 }
358
360
365 {
366 return scale_;
367 }
368
370
375 {
376 return contrastMode_;
377 }
378
380
385 {
386 return CExports::GetSF2ASteps(Handle());
387 }
388
390
394 double ScaleStep()
395 {
396 return CExports::GetSF2RSteps(Handle());
397 }
398
399
400private:
401
402 explicit Classifier(HandleGuard<Classifier>&& guard) noexcept
403 : handle_(std::move(guard))
404 {
405 }
406
407
408
409
410 static ValueRange<Angle> RotationRangeDefault() noexcept
411 {
413 }
414
415 static ValueRange<double> ScaleRangeDefault() noexcept
416 {
417 return ValueRange<double>(1.0, 1.0);
418 }
419
420 inline void Init()
421 {
422 // feature window
423 CExports::cvbdim_t left = 0;
424 CExports::cvbdim_t top = 0;
425 CExports::cvbdim_t right = 0;
426 CExports::cvbdim_t bottom = 0;
427 CVB_CALL_CAPI_CHECKED(GetSFFeatureWindow(Handle(), left, top, right, bottom));
428 featureWindow_ = Cvb::Rect<int>(left, top, right, bottom);
429
430 // classifier extent
431 left = 0;
432 top = 0;
433 right = 0;
434 bottom = 0;
435 CVB_CALL_CAPI_CHECKED(GetSF2TrainingWindow(Handle(), left, top, right, bottom));
436 trainingWindow_ = Cvb::Rect<int>(left, top, right, bottom);
437
438 // classifier features
439 CExports::PIXELLIST fineFeatures = nullptr;
440 CExports::PIXELLIST coarseFeatures = nullptr;
441 CExports::cvbval_t coarseScale = coarseScale_;
442 CVB_CALL_CAPI_CHECKED(GetSF2Features(Handle(), fineFeatures, coarseFeatures, coarseScale));
443 fineFeatures_ = Internal::PixelList::FromHandle(HandleGuard<Internal::PixelList>(fineFeatures));
444 coarseFeatures_ = Internal::PixelList::FromHandle(HandleGuard<Internal::PixelList>(coarseFeatures));
445
446 // other classifier properties
447 CExports::TSymmetryParams tmp = { 0 };
448 CVB_CALL_CAPI_CHECKED(GetSF2Symmetries(Handle(), tmp));
450 scale_ = Cvb::ValueRange<double>(tmp.R0, tmp.R1);
451 contrastMode_ = (Cvb::ShapeFinder2::ContrastMode)tmp.ContrastMode;
452 }
453
454 static std::vector<Cvb::ShapeFinder2::SearchResult> ResultListFromPixelList(PrecisionMode precision, CExports::PIXELLIST pixelList)
455 {
456 auto pl = Internal::PixelList::FromHandle(HandleGuard<Internal::PixelList>(pixelList));
457 int plCount = pl->Count();
459 for (int i = 0; i < plCount; i++)
460 {
461 res[i] = Cvb::ShapeFinder2::SearchResult(precision, pl->ToValues(i));
462 }
463 return res;
464 }
465
466 static CExports::TSearchAllParams GetSearchAllParameters(PrecisionMode precision, double relativeThreshold, int minimumThreshold, int coarseLocality)
467 {
468 CExports::TSearchAllParams p = { 0 };
469 p.Precision = (int)precision;
470 p.LocXY = coarseLocality;
471 p.LocA = 0x7FFFFFFF;
472 p.LocR = 0x7FFFFFFF;
473 p.RelativeThreshold = static_cast<int>(relativeThreshold * 100 + 0.5); // NOLINT(bugprone-incorrect-roundings)
474 p.MinimalThreshold = minimumThreshold;
475 p.MaxNumSolutions = SearchAllResultCountMax;
476 return p;
477 }
478
479 static CExports::TSymmetryParams GetSymmetryParameters(ValueRange<Angle> rotationRange, ValueRange<double> scaleRange)
480 {
481 CExports::TSymmetryParams p = { 0 };
482 p.ContrastMode = (int)Cvb::ShapeFinder2::ContrastMode::Normal;
483 p.A0 = rotationRange.Min().Deg();
484 p.A1 = rotationRange.Max().Deg();
485 p.R0 = scaleRange.Min();
486 p.R1 = scaleRange.Max();
487 return p;
488 }
489
490 static inline std::unique_ptr<Classifier> Load(const String & fileName)
491 {
492 return Internal::DoBoolCallObjectOut<Classifier>([&](void* & handle)
493 {
494 return CVB_CALL_CAPI(LoadSFTyped(handle, fileName.c_str()));
495 });
496 }
497
498
499private:
500
501 static const int SearchAllResultCountMax = 10000;
502
503 HandleGuard<Classifier> handle_;
504
505 String fileName_;
506
507 int coarseScale_ = 0;
508 Cvb::Rect<int> featureWindow_;
509 Cvb::Rect<int> trainingWindow_;
515
516};
517
518}
519
520using ShapeFinder2::Classifier;
521
522CVB_END_INLINE_NS
523
524}
525
526
Object for convenient and type - safe handling of angles.
Definition: angle.hpp:19
static Angle FromRadians(double rad, bool trim=false) noexcept
Create an angle in radians.
Definition: angle.hpp:44
double Rad() const noexcept
Get the value in radians.
Definition: angle.hpp:66
void SetIsTrimmed(bool trim) noexcept
Set trimming of the value of the angle to the range -PI...PI.
Definition: angle.hpp:119
static Angle FromDegrees(double deg, bool trim=false) noexcept
Create an angle in degrees.
Definition: angle.hpp:30
Image plane information container.
Definition: decl_image_plane.hpp:33
ShapeFinder2 classifier object.
Definition: classifier.hpp:38
static std::unique_ptr< Classifier > Create(const String &fileName)
Creates a classifier object loading a classifier file.
Definition: classifier.hpp:64
double RotationStep()
Step size at which the rotations in the classifier have been generated.
Definition: classifier.hpp:384
String Comment() const noexcept
Get the comment assigned to the classifier.
Definition: classifier.hpp:160
ValueRange< Angle > Rotation()
Range of rotations for which this classifier has been generated.
Definition: classifier.hpp:354
int ContrastThreshold() const noexcept
Get the threshold for the gradient slope.
Definition: classifier.hpp:193
static std::unique_ptr< Classifier > FromHandle(HandleGuard< Classifier > &&guard)
Creates a classifier from a classic API handle.
Definition: classifier.hpp:49
void SetContrastThreshold(int threshold)
Set the threshold for the gradient slope.
Definition: classifier.hpp:203
ValueRange< double > Scale()
Range of scales for which this classifier has been generated.
Definition: classifier.hpp:364
Cvb::ShapeFinder2::ContrastMode ContrastMode()
Contrast mode for which this classifier has been created.
Definition: classifier.hpp:374
Cvb::ShapeFinder2::GradientType GradientType() const noexcept
Get the gradient type this classifier uses for feature extraction.
Definition: classifier.hpp:172
double ScaleStep()
Step size at which the scales in the classifier have been generated.
Definition: classifier.hpp:394
int NumLayers() const noexcept
Number of layers in the classifier.
Definition: classifier.hpp:130
std::vector< SearchResult > SearchAll(const ImagePlane &plane, Rect< int > aoi, PrecisionMode precision, double relativeThreshold, int minimumThreshold, int coarseLocality, ValueRange< Angle > rotationRange, ValueRange< double > scaleRange)
Use this classifier to perform a ShapeFinder search on an image plane.
Definition: classifier.hpp:271
Rect< int > FeatureWindow() const noexcept
Get the feature window of this classifier.
Definition: classifier.hpp:183
void SetAngularTolerance(Angle angularTolerance)
Set the acceptance parameter for feature gradient angles.
Definition: classifier.hpp:226
void Save(const String &fileName) const
Writes the classifier to a file.
Definition: classifier.hpp:104
int FeatureCount() const noexcept
Get the number of features this classifier contains.
Definition: classifier.hpp:241
Classifier(const String &fileName)
Loads a classifier with the given file name.
Definition: classifier.hpp:74
std::unique_ptr< Image > Visualization(int layer=-1) const
Creates and returns a color coded image representation of this ShapeFinder classifier.
Definition: classifier.hpp:116
std::vector< Point2D< double > > CoarseFeatures() const noexcept
Features the classifier uses on the coarsely granular level.
Definition: classifier.hpp:334
Angle AngularTolerance() const noexcept
Get the acceptance parameter for feature gradient angles.
Definition: classifier.hpp:214
Rect< int > TrainingWindow() const noexcept
Training window of the classes in the classifier relative to the anchor point.
Definition: classifier.hpp:314
bool UseCuda(CudaStatus status) const noexcept
Set the flag to use CUDA if possible or to force not using CUDA.
Definition: classifier.hpp:253
std::vector< Point2D< double > > FineFeatures() const noexcept
The features the classifier uses on the finely granular level.
Definition: classifier.hpp:324
String FileName() const
Gets the name of the file, from which this classifier was loaded.
Definition: classifier.hpp:140
std::vector< SearchResult > SearchAll(const ImagePlane &plane, Rect< int > aoi, PrecisionMode precision, double relativeThreshold, int minimumThreshold, int coarseLocality)
Use this classifier to perform a ShapeFinder search on an image plane.
Definition: classifier.hpp:296
void * Handle() const noexcept
Classic API classifier handle.
Definition: classifier.hpp:94
void SetComment(const String &comment) noexcept
Set the comment assigned to the classifier.
Definition: classifier.hpp:150
int CoarseScale() const noexcept
Scale factor between the fine and the coarse feature level.
Definition: classifier.hpp:344
Search result as returned by the classifier.
Definition: search_result.hpp:24
Container for range definitions.
Definition: value_range.hpp:17
GradientType
Type of Gradient used for feature extraction.
Definition: shapefinder2.hpp:59
CudaStatus
ShapeFinder2 CUDA status enum.
Definition: shapefinder2.hpp:68
PrecisionMode
Controls precision over accuracy for ShapeFinder 1 type searches.
Definition: shapefinder2.hpp:47
ContrastMode
Normal contrast features.
Definition: shapefinder2.hpp:37
@ Normal
Normal contrast features.
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