CVB++ 15.0
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
19namespace Cvb
20{
21 CVB_BEGIN_INLINE_NS
22
23 template <>
24 inline HandleGuard<ShapeFinder2::Classifier>::HandleGuard(void *handle) noexcept
25 : HandleGuard<ShapeFinder2::Classifier>(handle, [](void *handle) { CVB_CALL_CAPI(ReleaseObject(handle)); })
26 {
27 }
28
29 namespace ShapeFinder2
30 {
31
33
35 class Classifier final
36 {
37 public:
39
46 static std::unique_ptr<Classifier> FromHandle(HandleGuard<Classifier> &&guard)
47 {
48 if (!guard.Handle())
49 throw std::runtime_error("handle must not be null");
50
51 auto classifier = std::unique_ptr<Classifier>(new Classifier(std::move(guard)));
52 return classifier;
53 }
54
56
62 {
63 return std::make_unique<Classifier>(fileName);
64 }
65
67
71 explicit Classifier(const String &fileName)
72 : Classifier(std::move(*Load(fileName)))
73 {
74 fileName_ = fileName; // NOLINT(cppcoreguidelines-prefer-member-initializer)
75 Init();
76 }
77
78 Classifier(const Classifier &other) noexcept = delete;
79 Classifier &operator=(const Classifier &other) = delete;
80 Classifier(Classifier &&other) noexcept = default;
81 Classifier &operator=(Classifier &&other) = default;
82 ~Classifier() = default;
83
85
91 void *Handle() const noexcept
92 {
93 return handle_.Handle();
94 }
95
97
101 void Save(const String &fileName) const
102 {
103 if (!CVB_CALL_CAPI(StoreSFTyped(Handle(), fileName.c_str())))
104 Utilities::SystemInfo::ThrowLastError();
105 }
106
108
114 {
115 if (layer < -1 || layer >= NumLayers())
116 throw std::out_of_range("layer value must be in [-1.0, <NumLayers]");
117
118 HandleGuard<Image> guard(CExports::GetSFImage(static_cast<CExports::cvbdim_t>(layer), Handle()));
119 return Image::FromHandle<Image>(std::move(guard));
120 }
121
123
127 int NumLayers() const noexcept
128 {
129 return CExports::GetSFClassNumber(Handle());
130 }
131
133
138 {
139 return fileName_;
140 }
141
143
147 void SetComment(const String &comment) noexcept
148 {
149 CVB_CALL_CAPI(SetSFCommentTyped(Handle(), comment.c_str()));
150 }
151
153
157 String Comment() const noexcept
158 {
159 Char *strComment = nullptr;
160 CVB_CALL_CAPI(GetSFCommentTyped(Handle(), strComment));
161 return ((strComment != nullptr) ? String(strComment) : String());
162 }
163
165
170 {
171 int val = CExports::GetSFGradienttype(Handle()) & 0xFF;
172 return static_cast<ShapeFinder2::GradientType>(val);
173 }
174
176
180 Rect<int> FeatureWindow() const noexcept
181 {
182 return featureWindow_;
183 }
184
186
190 int ContrastThreshold() const noexcept
191 {
192 return CExports::GetSFThreshold(Handle());
193 }
194
196
200 void SetContrastThreshold(int threshold)
201 {
202 if (!CExports::SetSFThreshold(Handle(), threshold))
203 Utilities::SystemInfo::ThrowLastError();
204 }
205
207
211 Angle AngularTolerance() const noexcept
212 {
213 auto byteValue = CExports::GetSFAngularTolerance(Handle());
214 auto rad = byteValue < 128 ? static_cast<double>(byteValue) * CVB_M_PI / 127.0
215 : (static_cast<double>(byteValue) - 255.0) * CVB_M_PI / 127.0;
216 return Cvb::Angle::FromRadians(rad);
217 }
218
220
224 void SetAngularTolerance(Angle angularTolerance)
225 {
226 angularTolerance.SetIsTrimmed(true); // limit to +/- M_PI
227 auto rad = angularTolerance.Rad();
228 auto byteValue =
229 static_cast<std::uint8_t>(std::round(rad > 0 ? rad * 127.0 / CVB_M_PI : 255.0 - (rad * 127.0 / CVB_M_PI)));
230
231 if (!CExports::SetSFAngularTolerance(Handle(), byteValue))
232 Utilities::SystemInfo::ThrowLastError();
233 }
234
236
240 int FeatureCount() const noexcept
241 {
242 return CExports::GetSFFeatureNumber(Handle());
243 }
244
246
252 bool UseCuda(CudaStatus status) const noexcept
253 {
254 return CExports::SF2UseCuda(Handle(), static_cast<CExports::SF2CudaStatus>(status));
255 }
256
258
274 double relativeThreshold, int minimumThreshold, int coarseLocality,
275 ValueRange<Angle> rotationRange, ValueRange<double> scaleRange)
276 {
277 CExports::TSearchAllParams searchParams =
278 GetSearchAllParameters(precision, relativeThreshold, minimumThreshold, coarseLocality);
279 if (!CExports::SetSF2SearchAllPars(Handle(), searchParams))
280 Utilities::SystemInfo::ThrowLastError();
281 CExports::TSymmetryParams symmetryLimits = GetSymmetryParameters(rotationRange, scaleRange);
282
283 CExports::PIXELLIST lst = nullptr;
284 if (!CExports::SF2SearchEx(Handle(), plane.Parent().Handle(), plane.Plane(), aoi.Left(), aoi.Top(), aoi.Right(),
285 aoi.Bottom(), symmetryLimits, lst))
286 Utilities::SystemInfo::ThrowLastError();
287
288 return ResultListFromPixelList(precision, lst);
289 }
290
292
306 double relativeThreshold, int minimumThreshold, int coarseLocality)
307 {
308 CExports::TSearchAllParams searchParams =
309 GetSearchAllParameters(precision, relativeThreshold, minimumThreshold, coarseLocality);
310 if (!CExports::SetSF2SearchAllPars(Handle(), searchParams))
311 Utilities::SystemInfo::ThrowLastError();
312
313 CExports::PIXELLIST lst = nullptr;
314 if (!CExports::SF2Search(Handle(), plane.Parent().Handle(), plane.Plane(), aoi.Left(), aoi.Top(), aoi.Right(),
315 aoi.Bottom(), lst))
316 Utilities::SystemInfo::ThrowLastError();
317
318 return ResultListFromPixelList(precision, lst);
319 }
320
322
326 Rect<int> TrainingWindow() const noexcept
327 {
328 return trainingWindow_;
329 }
330
332
337 {
338 return fineFeatures_->ToPoints();
339 }
340
342
347 {
348 return coarseFeatures_->ToPoints();
349 }
350
352
356 int CoarseScale() const noexcept
357 {
358 return coarseScale_;
359 }
360
362
367 {
368 return rotation_;
369 }
370
372
377 {
378 return scale_;
379 }
380
382
387 {
388 return contrastMode_;
389 }
390
392
397 {
398 return CExports::GetSF2ASteps(Handle());
399 }
400
402
406 double ScaleStep()
407 {
408 return CExports::GetSF2RSteps(Handle());
409 }
410
411 private:
412 explicit Classifier(HandleGuard<Classifier> &&guard) noexcept
413 : handle_(std::move(guard))
414 {
415 }
416
417 static ValueRange<Angle> RotationRangeDefault() noexcept
418 {
420 }
421
422 static ValueRange<double> ScaleRangeDefault() noexcept
423 {
424 return ValueRange<double>(1.0, 1.0);
425 }
426
427 inline void Init()
428 {
429 // feature window
430 CExports::cvbdim_t left = 0;
431 CExports::cvbdim_t top = 0;
432 CExports::cvbdim_t right = 0;
433 CExports::cvbdim_t bottom = 0;
434 CVB_CALL_CAPI_CHECKED(GetSFFeatureWindow(Handle(), left, top, right, bottom));
435 featureWindow_ = Cvb::Rect<int>(left, top, right, bottom);
436
437 // classifier extent
438 left = 0;
439 top = 0;
440 right = 0;
441 bottom = 0;
442 CVB_CALL_CAPI_CHECKED(GetSF2TrainingWindow(Handle(), left, top, right, bottom));
443 trainingWindow_ = Cvb::Rect<int>(left, top, right, bottom);
444
445 // classifier features
446 CExports::PIXELLIST fineFeatures = nullptr;
447 CExports::PIXELLIST coarseFeatures = nullptr;
448 CExports::cvbval_t coarseScale = coarseScale_;
449 CVB_CALL_CAPI_CHECKED(GetSF2Features(Handle(), fineFeatures, coarseFeatures, coarseScale));
450 fineFeatures_ = Internal::PixelList::FromHandle(HandleGuard<Internal::PixelList>(fineFeatures));
451 coarseFeatures_ = Internal::PixelList::FromHandle(HandleGuard<Internal::PixelList>(coarseFeatures));
452
453 // other classifier properties
454 CExports::TSymmetryParams tmp = {0};
455 CVB_CALL_CAPI_CHECKED(GetSF2Symmetries(Handle(), tmp));
456 rotation_ = Cvb::ValueRange<Angle>(Cvb::Angle::FromDegrees(tmp.A0), Cvb::Angle::FromDegrees(tmp.A1));
457 scale_ = Cvb::ValueRange<double>(tmp.R0, tmp.R1);
458 contrastMode_ = (Cvb::ShapeFinder2::ContrastMode)tmp.ContrastMode;
459 }
460
461 static std::vector<Cvb::ShapeFinder2::SearchResult> ResultListFromPixelList(PrecisionMode precision,
462 CExports::PIXELLIST pixelList)
463 {
464 auto pl = Internal::PixelList::FromHandle(HandleGuard<Internal::PixelList>(pixelList));
465 int plCount = pl->Count();
466 std::vector<Cvb::ShapeFinder2::SearchResult> res(static_cast<std::size_t>(plCount));
467 for (int i = 0; i < plCount; i++)
468 {
469 res[i] = Cvb::ShapeFinder2::SearchResult(precision, pl->ToValues(i));
470 }
471 return res;
472 }
473
474 static CExports::TSearchAllParams GetSearchAllParameters(PrecisionMode precision, double relativeThreshold,
475 int minimumThreshold, int coarseLocality)
476 {
477 CExports::TSearchAllParams p = {0};
478 p.Precision = (int)precision;
479 p.LocXY = coarseLocality;
480 p.LocA = 0x7FFFFFFF;
481 p.LocR = 0x7FFFFFFF;
482 p.RelativeThreshold = static_cast<int>(relativeThreshold * 100 + 0.5); // NOLINT(bugprone-incorrect-roundings)
483 p.MinimalThreshold = minimumThreshold;
484 p.MaxNumSolutions = SearchAllResultCountMax;
485 return p;
486 }
487
488 static CExports::TSymmetryParams GetSymmetryParameters(ValueRange<Angle> rotationRange,
489 ValueRange<double> scaleRange)
490 {
491 CExports::TSymmetryParams p = {0};
492 p.ContrastMode = (int)Cvb::ShapeFinder2::ContrastMode::Normal;
493 p.A0 = rotationRange.Min().Deg();
494 p.A1 = rotationRange.Max().Deg();
495 p.R0 = scaleRange.Min();
496 p.R1 = scaleRange.Max();
497 return p;
498 }
499
500 static inline std::unique_ptr<Classifier> Load(const String &fileName)
501 {
502 return Internal::DoBoolCallObjectOut<Classifier>(
503 [&](void *&handle) { return CVB_CALL_CAPI(LoadSFTyped(handle, fileName.c_str())); });
504 }
505
506 private:
507 static const int SearchAllResultCountMax = 10000;
508
509 HandleGuard<Classifier> handle_;
510
511 String fileName_;
512
513 int coarseScale_ = 0;
514 Cvb::Rect<int> featureWindow_;
515 Cvb::Rect<int> trainingWindow_;
516 std::unique_ptr<Internal::PixelList> fineFeatures_;
517 std::unique_ptr<Internal::PixelList> coarseFeatures_;
518 Cvb::ValueRange<Cvb::Angle> rotation_;
519 Cvb::ValueRange<double> scale_;
521 };
522
523 } // namespace ShapeFinder2
524
526
527 CVB_END_INLINE_NS
528
529} // namespace Cvb
Object for convenient and type - safe handling of angles.
Definition angle.hpp:16
static Angle FromRadians(double rad, bool trim=false) noexcept
Create an angle in radians.
Definition angle.hpp:39
double Rad() const noexcept
Get the value in radians.
Definition angle.hpp:68
void SetIsTrimmed(bool trim) noexcept
Set trimming of the value of the angle to the range -PI...PI.
Definition angle.hpp:120
static Angle FromDegrees(double deg, bool trim=false) noexcept
Create an angle in degrees.
Definition angle.hpp:25
Classifier(const String &fileName)
Loads a classifier with the given file name.
Definition classifier.hpp:71
static std::unique_ptr< Image > FromHandle(HandleGuard< Image > &&guard)
Creates an image from a classic API handle.
Definition decl_image.hpp:155
void * Handle() const noexcept
Classic API image handle.
Definition decl_image.hpp:232
Image plane information container.
Definition decl_image_plane.hpp:29
int Plane() const noexcept
Plane index in the image, to which this plane refers to.
Definition decl_image_plane.hpp:147
const Image & Parent() const noexcept
Image to which this plane descriptor refers to.
Definition detail_image_plane.hpp:87
Rectangle object.
Definition rect.hpp:24
ShapeFinder2 classifier object.
Definition classifier.hpp:36
static std::unique_ptr< Classifier > Create(const String &fileName)
Creates a classifier object loading a classifier file.
Definition classifier.hpp:61
double RotationStep()
Step size at which the rotations in the classifier have been generated.
Definition classifier.hpp:396
String Comment() const noexcept
Get the comment assigned to the classifier.
Definition classifier.hpp:157
ValueRange< Angle > Rotation()
Range of rotations for which this classifier has been generated.
Definition classifier.hpp:366
int ContrastThreshold() const noexcept
Get the threshold for the gradient slope.
Definition classifier.hpp:190
static std::unique_ptr< Classifier > FromHandle(HandleGuard< Classifier > &&guard)
Creates a classifier from a classic API handle.
Definition classifier.hpp:46
void SetContrastThreshold(int threshold)
Set the threshold for the gradient slope.
Definition classifier.hpp:200
ValueRange< double > Scale()
Range of scales for which this classifier has been generated.
Definition classifier.hpp:376
Cvb::ShapeFinder2::ContrastMode ContrastMode()
Contrast mode for which this classifier has been created.
Definition classifier.hpp:386
Cvb::ShapeFinder2::GradientType GradientType() const noexcept
Get the gradient type this classifier uses for feature extraction.
Definition classifier.hpp:169
double ScaleStep()
Step size at which the scales in the classifier have been generated.
Definition classifier.hpp:406
int NumLayers() const noexcept
Number of layers in the classifier.
Definition classifier.hpp:127
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:273
Rect< int > FeatureWindow() const noexcept
Get the feature window of this classifier.
Definition classifier.hpp:180
void SetAngularTolerance(Angle angularTolerance)
Set the acceptance parameter for feature gradient angles.
Definition classifier.hpp:224
void Save(const String &fileName) const
Writes the classifier to a file.
Definition classifier.hpp:101
int FeatureCount() const noexcept
Get the number of features this classifier contains.
Definition classifier.hpp:240
Classifier(const String &fileName)
Loads a classifier with the given file name.
Definition classifier.hpp:71
std::unique_ptr< Image > Visualization(int layer=-1) const
Creates and returns a color coded image representation of this ShapeFinder classifier.
Definition classifier.hpp:113
std::vector< Point2D< double > > CoarseFeatures() const noexcept
Features the classifier uses on the coarsely granular level.
Definition classifier.hpp:346
Angle AngularTolerance() const noexcept
Get the acceptance parameter for feature gradient angles.
Definition classifier.hpp:211
Rect< int > TrainingWindow() const noexcept
Training window of the classes in the classifier relative to the anchor point.
Definition classifier.hpp:326
bool UseCuda(CudaStatus status) const noexcept
Set the flag to use CUDA if possible or to force not using CUDA.
Definition classifier.hpp:252
std::vector< Point2D< double > > FineFeatures() const noexcept
The features the classifier uses on the finely granular level.
Definition classifier.hpp:336
String FileName() const
Gets the name of the file, from which this classifier was loaded.
Definition classifier.hpp:137
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:305
void * Handle() const noexcept
Classic API classifier handle.
Definition classifier.hpp:91
void SetComment(const String &comment) noexcept
Set the comment assigned to the classifier.
Definition classifier.hpp:147
int CoarseScale() const noexcept
Scale factor between the fine and the coarse feature level.
Definition classifier.hpp:356
Container for range definitions.
Definition value_range.hpp:17
cvbbool_t ReleaseObject(OBJ &Object)
T move(T... args)
Namespace for the ShapeFinder2 package.
Definition classifier.hpp:30
GradientType
Type of Gradient used for feature extraction.
Definition shapefinder2.hpp:56
CudaStatus
ShapeFinder2 CUDA status enum.
Definition shapefinder2.hpp:65
PrecisionMode
Controls precision over accuracy for ShapeFinder 1 type searches.
Definition shapefinder2.hpp:42
ContrastMode
Normal contrast features.
Definition shapefinder2.hpp:32
@ Normal
Normal contrast features.
Definition shapefinder2.hpp:34
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 round(T... args)