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 
20 namespace Cvb
21 {
22 CVB_BEGIN_INLINE_NS
23 
24 template <>
25 inline HandleGuard<ShapeFinder2::Classifier>::HandleGuard(void * handle) noexcept
26  : HandleGuard<ShapeFinder2::Classifier>(handle, [](void* handle) { CVB_CALL_CAPI(ReleaseObject(handle)); })
27 {
28 }
29 
30 namespace ShapeFinder2
31 {
32 
33 
35 
37 class Classifier final
38 {
39 public:
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::unique_ptr<Classifier>(new Classifier(fileName));
67  }
68 
70 
74  explicit Classifier(const String & fileName)
75  : Classifier(std::move(*Load(fileName)))
76  {
77  fileName_ = fileName;
78  Init();
79  }
80 
81  virtual ~Classifier() = default;
82 
84 
90  void * Handle() const noexcept
91  {
92  return handle_.Handle();
93  }
94 
96 
100  void Save(const String & fileName) const
101  {
102  if (!CVB_CALL_CAPI(StoreSFTyped(Handle(), fileName.c_str())))
103  Utilities::SystemInfo::ThrowLastError();
104  }
105 
107 
112  std::unique_ptr<Image> Visualization(int layer = -1) const
113  {
114  if (layer < -1 || layer >= NumLayers())
115  throw std::out_of_range("layer value must be in [-1.0, <NumLayers]");
116 
117  HandleGuard<Image> guard(CExports::GetSFImage(static_cast<CExports::cvbdim_t>(layer), Handle()));
118  return Image::FromHandle<Image>(std::move(guard));
119  }
120 
122 
126  int NumLayers() const noexcept
127  {
128  return CExports::GetSFClassNumber(Handle());
129  }
130 
132 
136  String FileName() const noexcept
137  {
138  return fileName_;
139  }
140 
142 
146  void SetComment(const String & comment) noexcept
147  {
148  CVB_CALL_CAPI(SetSFCommentTyped(Handle(), comment.c_str()));
149  }
150 
152 
156  String Comment() const noexcept
157  {
158  Char *strComment = nullptr;
159  CVB_CALL_CAPI(GetSFCommentTyped(Handle(), strComment));
160  return ((strComment != nullptr) ? String(strComment) : String());
161  }
162 
164 
169  {
170  int val = CExports::GetSFGradienttype(Handle()) & 0xFF;
171  return static_cast<ShapeFinder2::GradientType>(val);
172  }
173 
175 
179  Rect<int> FeatureWindow() const noexcept
180  {
181  return featureWindow_;
182  }
183 
185 
189  int ContrastThreshold() const noexcept
190  {
191  return CExports::GetSFThreshold(Handle());
192  }
193 
195 
199  void SetContrastThreshold(int threshold)
200  {
201  if (!CExports::SetSFThreshold(Handle(), threshold))
202  Utilities::SystemInfo::ThrowLastError();
203  }
204 
206 
210  Angle AngularTolerance() const noexcept
211  {
212  auto byteValue = CExports::GetSFAngularTolerance(Handle());
213  auto rad = byteValue < 128 ? static_cast<double>(byteValue) * CVB_M_PI / 127.0 : (static_cast<double>(byteValue) - 255.0) * CVB_M_PI / 127.0;
214  return Cvb::Angle::FromRadians(rad);
215  }
216 
218 
222  void SetAngularTolerance(Angle angularTolerance)
223  {
224  angularTolerance.SetIsTrimmed(true); // limit to +/- M_PI
225  auto rad = angularTolerance.Rad();
226  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)));
227 
228  if (!CExports::SetSFAngularTolerance(Handle(), byteValue))
229  Utilities::SystemInfo::ThrowLastError();
230  }
231 
233 
237  int FeatureCount() const noexcept
238  {
239  return CExports::GetSFFeatureNumber(Handle());
240  }
241 
243 
249  bool UseCuda(CudaStatus status) const noexcept
250  {
251  return CExports::SF2UseCuda(Handle(), static_cast<CExports::SF2CudaStatus>(status));
252  }
253 
255 
267  std::vector<SearchResult> SearchAll(const ImagePlane & plane, Rect<int> aoi, PrecisionMode precision, double relativeThreshold, int minimumThreshold, int coarseLocality, ValueRange<Angle> rotationRange, ValueRange<double> scaleRange)
268  {
269  CExports::TSearchAllParams searchParams = GetSearchAllParameters(precision, relativeThreshold, minimumThreshold, coarseLocality);
270  if (!CExports::SetSF2SearchAllPars(Handle(), searchParams))
271  Utilities::SystemInfo::ThrowLastError();
272  CExports::TSymmetryParams symmetryLimits = GetSymmetryParameters(rotationRange, scaleRange);
273 
274  CExports::PIXELLIST lst = nullptr;
275  if (!CExports::SF2SearchEx(Handle(), plane.Parent().Handle(), plane.Plane(), aoi.Left(), aoi.Top(), aoi.Right(), aoi.Bottom(), symmetryLimits, lst))
276  Utilities::SystemInfo::ThrowLastError();
277 
278  return ResultListFromPixelList(precision, lst);
279  }
280 
282 
292  std::vector<SearchResult> SearchAll(const ImagePlane & plane, Rect<int> aoi, PrecisionMode precision, double relativeThreshold, int minimumThreshold, int coarseLocality)
293  {
294  CExports::TSearchAllParams searchParams = GetSearchAllParameters(precision, relativeThreshold, minimumThreshold, coarseLocality);
295  if (!CExports::SetSF2SearchAllPars(Handle(), searchParams))
296  Utilities::SystemInfo::ThrowLastError();
297 
298  CExports::PIXELLIST lst = nullptr;
299  if (!CExports::SF2Search(Handle(), plane.Parent().Handle(), plane.Plane(), aoi.Left(), aoi.Top(), aoi.Right(), aoi.Bottom(), lst))
300  Utilities::SystemInfo::ThrowLastError();
301 
302  return ResultListFromPixelList(precision, lst);
303  }
304 
306 
310  Rect<int> TrainingWindow() const noexcept
311  {
312  return trainingWindow_;
313  }
314 
316 
321  {
322  return fineFeatures_->ToPoints();
323  }
324 
326 
331  {
332  return coarseFeatures_->ToPoints();
333  }
334 
336 
340  int CoarseScale() const noexcept
341  {
342  return coarseScale_;
343  }
344 
346 
351  {
352  return rotation_;
353  }
354 
356 
361  {
362  return scale_;
363  }
364 
366 
371  {
372  return contrastMode_;
373  }
374 
376 
380  double RotationStep()
381  {
382  return CExports::GetSF2ASteps(Handle());
383  }
384 
386 
390  double ScaleStep()
391  {
392  return CExports::GetSF2RSteps(Handle());
393  }
394 
395 
396 private:
397 
398  Classifier(HandleGuard<Classifier>&& guard) noexcept
399  : handle_(std::move(guard))
400  {
401  }
402 
403  Classifier(Classifier && other) noexcept
404  : handle_(std::move(other.handle_))
405  {
406  }
407 
408  Classifier & operator=(Classifier && other) = default;
409 
410  static ValueRange<Angle> RotationRangeDefault() noexcept
411  {
412  return ValueRange<Angle>(Angle::FromDegrees(-0.0), Angle::FromDegrees(0.0));
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;
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();
458  std::vector<Cvb::ShapeFinder2::SearchResult> res(static_cast<std::size_t>(plCount));
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;
469  p.Precision = (int)precision;
470  p.LocXY = coarseLocality;
471  p.LocA = 0x7FFFFFFF;
472  p.LocR = 0x7FFFFFFF;
473  p.RelativeThreshold = (int)(relativeThreshold * 100 + 0.5);
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;
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 
499 private:
500 
501  static const int SearchAllResultCountMax = 10000;
502 
503  HandleGuard<Classifier> handle_;
504 
505  String fileName_;
506 
507  int coarseScale_;
508  Cvb::Rect<int> featureWindow_;
509  Cvb::Rect<int> trainingWindow_;
511  std::unique_ptr<Internal::PixelList> coarseFeatures_;
512  Cvb::ValueRange<Cvb::Angle> rotation_;
514  Cvb::ShapeFinder2::ContrastMode contrastMode_;
515 
516 };
517 
518 }
519 
520 using ShapeFinder2::Classifier;
521 
522 CVB_END_INLINE_NS
523 
524 }
525 
526 
void SetComment(const String &comment) noexcept
Set the comment assigned to the classifier.
Definition: classifier.hpp:146
Rect< int > FeatureWindow() const noexcept
Get the feature window of this classifier.
Definition: classifier.hpp:179
static std::unique_ptr< Classifier > FromHandle(HandleGuard< Classifier > &&guard)
Creates a classifier from a classic API handle.
Definition: classifier.hpp:49
double Rad() const noexcept
Get the value in radians.
Definition: angle.hpp:66
Image plane information container.
Definition: decl_image_plane.hpp:31
T Top() const noexcept
Gets first row of the rectangle.
Definition: rect.hpp:111
Search result as returned by the classifier.
Definition: search_result.hpp:23
bool UseCuda(CudaStatus status) const noexcept
Set the flag to use CUDA if possible or to force not using CUDA.
Definition: classifier.hpp:249
String FileName() const noexcept
Gets the name of the file, from which this classifier was loaded.
Definition: classifier.hpp:136
void Save(const String &fileName) const
Writes the classifier to a file.
Definition: classifier.hpp:100
Cvb::ShapeFinder2::ContrastMode ContrastMode()
Contrast mode for which this classifier has been created.
Definition: classifier.hpp:370
void SetContrastThreshold(int threshold)
Set the threshold for the gradient slope.
Definition: classifier.hpp:199
std::string String
String for wide characters or unicode characters.
Definition: string.hpp:45
int FeatureCount() const noexcept
Get the number of features this classifier contains.
Definition: classifier.hpp:237
GradientType
Type of Gradient used for feature extraction.
Definition: shapefinder2.hpp:58
Classifier(const String &fileName)
Loads a classifier with the given file name.
Definition: classifier.hpp:74
const Image & Parent() const noexcept
Image to which this plane descriptor refers to.
Definition: detail_image_plane.hpp:87
T left(T... args)
T Bottom() const noexcept
Gets bottom row of the rectangle (still inside the rectangle).
Definition: rect.hpp:151
CudaStatus
ShapeFinder2 CUDA status enum.
Definition: shapefinder2.hpp:67
static Angle FromRadians(double rad, bool trim=false) noexcept
Create an angle in radians.
Definition: angle.hpp:44
int ContrastThreshold() const noexcept
Get the threshold for the gradient slope.
Definition: classifier.hpp:189
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:267
T Left() const noexcept
Gets first column of the rectangle.
Definition: rect.hpp:91
int Plane() const noexcept
Plane index in the image, to which this plane refers to.
Definition: decl_image_plane.hpp:169
void SetAngularTolerance(Angle angularTolerance)
Set the acceptance parameter for feature gradient angles.
Definition: classifier.hpp:222
static std::unique_ptr< Classifier > Create(const String &fileName)
Creates a classifier object loading a classifier file.
Definition: classifier.hpp:64
double ScaleStep()
Step size at which the scales in the classifier have been generated.
Definition: classifier.hpp:390
Angle AngularTolerance() const noexcept
Get the acceptance parameter for feature gradient angles.
Definition: classifier.hpp:210
ValueRange< double > Scale()
Range of scales for which this classifier has been generated.
Definition: classifier.hpp:360
STL class.
String Comment() const noexcept
Get the comment assigned to the classifier.
Definition: classifier.hpp:156
Root namespace for the Image Manager interface.
Definition: version.hpp:11
static Angle FromDegrees(double deg, bool trim=false) noexcept
Create an angle in degrees.
Definition: angle.hpp:30
ValueRange< Angle > Rotation()
Range of rotations for which this classifier has been generated.
Definition: classifier.hpp:350
std::vector< Point2D< double > > FineFeatures() const noexcept
The features the classifier uses on the finely granular level.
Definition: classifier.hpp:320
Rect< int > TrainingWindow() const noexcept
Training window of the classes in the classifier relative to the anchor point.
Definition: classifier.hpp:310
char Char
Character type for wide characters or unicode characters.
Definition: string.hpp:59
T Right() const noexcept
Gets rightmost column of the rectangle (still inside the rectangle).
Definition: rect.hpp:131
std::unique_ptr< Image > Visualization(int layer=-1) const
Creates and returns a color coded image representation of this ShapeFinder classifier.
Definition: classifier.hpp:112
ContrastMode
Normal contrast features.
Definition: shapefinder2.hpp:36
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:292
int CoarseScale() const noexcept
Scale factor between the fine and the coarse feature level.
Definition: classifier.hpp:340
void * Handle() const noexcept
Classic API image handle.
Definition: decl_image.hpp:223
STL class.
PrecisionMode
Controls precision over accuracy for ShapeFinder 1 type searches.
Definition: shapefinder2.hpp:46
STL class.
int NumLayers() const noexcept
Number of layers in the classifier.
Definition: classifier.hpp:126
void SetIsTrimmed(bool trim) noexcept
Set trimming of the value of the angle to the range -PI...PI.
Definition: angle.hpp:119
void * Handle() const noexcept
Classic API classifier handle.
Definition: classifier.hpp:90
ShapeFinder2 classifier object.
Definition: classifier.hpp:37
double RotationStep()
Step size at which the rotations in the classifier have been generated.
Definition: classifier.hpp:380
Container for range definitions.
Definition: value_range.hpp:16
std::vector< Point2D< double > > CoarseFeatures() const noexcept
Features the classifier uses on the coarsely granular level.
Definition: classifier.hpp:330
Cvb::ShapeFinder2::GradientType GradientType() const noexcept
Get the gradient type this classifier uses for feature extraction.
Definition: classifier.hpp:168
Object for convenient and type - safe handling of angles.
Definition: angle.hpp:18