CVB++ 15.0
blob.hpp
1#pragma once
2
3#if defined _WIN32
4
5# include <map>
6
7# include "../_cexports/c_foundation.h"
8
9# include "../global.hpp"
10# include "../image.hpp"
11# include "../value_range.hpp"
12# include "../exception.hpp"
13# include "../point_2d.hpp"
14# include "../rect.hpp"
15# include "../size_2d.hpp"
16# include "../angle.hpp"
17
18# include <vector>
19# include <memory>
20
21namespace Cvb
22{
23
24 CVB_BEGIN_INLINE_NS
25
26 namespace Foundation
27 {
28
30
49 namespace Blob
50 {
51
53 enum class BlobRangeFilter
54 {
61 };
62
64
68 {
70 None = 0,
72 Right = 1,
74 Top = 2,
76 Left = 4,
78 Bottom = 8,
80 All = 15
81 };
82
84 {
85 return static_cast<BlobBorderFilter>(static_cast<std::uint32_t>(a) | static_cast<std::uint32_t>(b));
86 }
87
88 class BlobResult;
89 class BlobFilter;
90
92 ValueRange<int> binarizationThreshold);
94 ValueRange<int> binarizationThreshold, Rect<int> aoi);
96 BinarizeAndSearchBlobs(const ImagePlane &plane, ValueRange<int> binarizationThreshold, const BlobFilter &filter);
98 ValueRange<int> binarizationThreshold, Rect<int> aoi,
99 const BlobFilter &filter);
100 inline std::vector<BlobResult> SearchBlobs(const Image &binarizedImage);
101 inline std::vector<BlobResult> SearchBlobs(const Image &binarizedImage, Rect<int> aoi);
102 inline std::vector<BlobResult> SearchBlobs(const Image &binarizedImage, const BlobFilter &filter);
103 inline std::vector<BlobResult> SearchBlobs(const Image &binarizedImage, Rect<int> aoi, const BlobFilter &filter);
104
105 namespace Internal
106 {
107
108 class BlobAnalyzer final
109 {
110 friend class BlobResult;
111 friend class BlobFilter;
112
114 ValueRange<int> binarizationThreshold);
116 Blob::BinarizeAndSearchBlobs(const ImagePlane &plane, ValueRange<int> binarizationThreshold, Rect<int> aoi);
118 ValueRange<int> binarizationThreshold,
119 const BlobFilter &filter);
121 ValueRange<int> binarizationThreshold,
122 Rect<int> aoi, const BlobFilter &filter);
123 friend std::vector<BlobResult> Blob::SearchBlobs(const Image &binarizedImage);
124 friend std::vector<BlobResult> Blob::SearchBlobs(const Image &binarizedImage, Rect<int> aoi);
125 friend std::vector<BlobResult> Blob::SearchBlobs(const Image &binarizedImage, const BlobFilter &filter);
126 friend std::vector<BlobResult> Blob::SearchBlobs(const Image &binarizedImage, Rect<int> aoi,
127 const BlobFilter &filter);
128
129 private:
130 explicit BlobAnalyzer(const ImagePlane &plane)
131 : handle_(
132 CExports::FBlobCreate(plane_.Parent().Handle(), static_cast<CExports::cvbdim_t>(plane_.Plane())))
133 , plane_(plane)
134 {
135 if (!handle_.Handle())
136 Utilities::SystemInfo::ThrowLastError();
137 }
138
139 void *Handle() const noexcept
140 {
141 return handle_.Handle();
142 }
143
144 void SetAOI(Rect<int> aoi)
145 {
146 auto result = CVB_CALL_CAPI(FBlobSetArea(
147 Handle(), static_cast<CExports::cvbdim_t>(plane_.Plane()), static_cast<CExports::cvbdim_t>(aoi.Left()),
148 static_cast<CExports::cvbdim_t>(aoi.Top()), static_cast<CExports::cvbdim_t>(aoi.Right()),
149 static_cast<CExports::cvbdim_t>(aoi.Bottom())));
150 if (result < 0)
151 Utilities::SystemInfo::ThrowLastError(result);
152 }
153
154 void SetSkipBinarzation(bool skip)
155 {
156 auto result = CVB_CALL_CAPI(FBlobSetSkipBinarization(Handle(), skip ? 1 : 0));
157 if (result < 0)
158 Utilities::SystemInfo::ThrowLastError(result);
159 }
160
161 void SetBorderFilter(BlobBorderFilter borderFilter)
162 {
163 auto result =
164 CVB_CALL_CAPI(FBlobSetObjectTouchBorder(Handle(), static_cast<CExports::cvbval_t>(borderFilter)));
165 if (result < 0)
166 Utilities::SystemInfo::ThrowLastError(result);
167 }
168
169 void SetSizeFilter(ValueRange<int> sizeFilter)
170 {
171 auto result = CVB_CALL_CAPI(FBlobSetLimitArea(Handle(), static_cast<CExports::cvbval_t>(sizeFilter.Min()),
172 static_cast<CExports::cvbval_t>(sizeFilter.Max())));
173 if (result < 0)
174 Utilities::SystemInfo::ThrowLastError(result);
175 }
176
177 void SetWidthFilter(ValueRange<int> widthFilter)
178 {
179 auto result = CVB_CALL_CAPI(FBlobSetLimitWidth(Handle(), static_cast<CExports::cvbval_t>(widthFilter.Min()),
180 static_cast<CExports::cvbval_t>(widthFilter.Max())));
181 if (result < 0)
182 Utilities::SystemInfo::ThrowLastError(result);
183 }
184
185 void SetHeightFilter(ValueRange<int> heightFilter)
186 {
187 auto result =
188 CVB_CALL_CAPI(FBlobSetLimitHeight(Handle(), static_cast<CExports::cvbval_t>(heightFilter.Min()),
189 static_cast<CExports::cvbval_t>(heightFilter.Max())));
190 if (result < 0)
191 Utilities::SystemInfo::ThrowLastError(result);
192 }
193
194 void SetBinarizationRange(ValueRange<int> binarizationRange)
195 {
196 auto result = CVB_CALL_CAPI(
197 FBlobSetObjectFeatureRange(Handle(), static_cast<CExports::cvbval_t>(binarizationRange.Min()),
198 static_cast<CExports::cvbval_t>(binarizationRange.Max())));
199 if (result < 0)
200 Utilities::SystemInfo::ThrowLastError(result);
201 }
202
203 std::vector<BlobResult> Run();
204
205 const ImagePlane &plane_;
206
207 ReleaseObjectGuard handle_;
208 };
209
210 } // namespace Internal
211
213
215 class BlobResult final
216 {
217 friend class Internal::BlobAnalyzer;
218
219 public:
220 BlobResult() noexcept
221 : boundingBox_(Rect<int>())
222 {
223 }
224
226
230 double X() const noexcept
231 {
232 return center_.X();
233 }
234
236
240 double Y() const noexcept
241 {
242 return center_.Y();
243 }
244
246
250 Point2D<double> Center() const noexcept
251 {
252 return center_;
253 }
254
256
260 double Size() const noexcept
261 {
262 return size_;
263 }
264
266
270 Rect<int> BoundingBox() const noexcept
271 {
272 return boundingBox_;
273 }
274
277
281 double MinimumMoment() const noexcept
282 {
283 return minimumMoment_;
284 }
285
288
292 double MaximumMoment() const noexcept
293 {
294 return maximumMoment_;
295 }
296
298
302 double MomentRatio() const noexcept
303 {
304 return momentRatio_;
305 }
306
308
312 Angle MomentAngle() const noexcept
313 {
314 return momentAngle_;
315 }
316
318
323 {
324 return minimummomentPoints_;
325 }
326
327 private:
328 BlobResult(const Internal::BlobAnalyzer &analyzer, int index) noexcept
329 {
330 // for speed reasons (this ctor will be called potentially very
331 // often...) there will be no consistency checks here...
332 double x = 0.0;
333 double y = 0.0;
334 CVB_CALL_CAPI(FBlobGetCenterEx(analyzer.Handle(), index, x, y));
335 center_ = Point2D<double>(x, y);
336
337 CExports::cvbval_t size = 0;
338 CVB_CALL_CAPI(FBlobGetSize(analyzer.Handle(), index, size));
339 size_ = static_cast<double>(size);
340
341 CExports::cvbdim_t left = 0;
342 CExports::cvbdim_t top = 0;
343 CExports::cvbdim_t width = 0;
344 CExports::cvbdim_t height = 0;
345 CVB_CALL_CAPI(FBlobGetBoundingBoxEx(analyzer.Handle(), index, left, top, width, height));
346 boundingBox_ = Rect<int>(Point2D<int>(static_cast<int>(left), static_cast<int>(top)),
347 Size2D<int>(static_cast<int>(width), static_cast<int>(height)));
348
349 double angleRad = 0.0;
350 CVB_CALL_CAPI(
351 FBlobGetMoments(analyzer.Handle(), index, minimumMoment_, maximumMoment_, momentRatio_, angleRad));
352 momentAngle_ = Angle::FromRadians(angleRad);
353
354 CExports::cvbval_t x0 = 0;
355 CExports::cvbval_t y0 = 0;
356 CExports::cvbval_t x1 = 0;
357 CExports::cvbval_t y1 = 0;
358 CVB_CALL_CAPI(FBlobGetMinMomentPointsEx(analyzer.Handle(), index, x0, y0, x1, y1));
359 minimummomentPoints_ = {Point2D<int>(static_cast<int>(x0), static_cast<int>(y0)),
360 Point2D<int>(static_cast<int>(x1), static_cast<int>(y1))};
361 }
362
363 Point2D<double> center_;
364 double size_ = 0.0;
365 Rect<int> boundingBox_;
366 double minimumMoment_ = 0.0;
367 double maximumMoment_ = 0.0;
368 double momentRatio_ = 0.0;
369 Angle momentAngle_;
370 std::vector<Point2D<int>> minimummomentPoints_;
371 };
372
373 inline std::vector<BlobResult> Internal::BlobAnalyzer::Run()
374 {
375 auto resutlExec = CExports::FBlobExec(Handle());
376 if (resutlExec < 0)
377 Utilities::SystemInfo::ThrowLastError(resutlExec);
378
379 CExports::cvbval_t numBlobs = 0;
380 auto resultNumBlobs = CExports::FBlobGetNumBlobs(Handle(), numBlobs);
381 if (resutlExec < 0)
382 Utilities::SystemInfo::ThrowLastError(resultNumBlobs);
383
384 std::vector<BlobResult> results(static_cast<std::size_t>(numBlobs));
385 for (int i = 0; i < static_cast<int>(numBlobs); ++i)
386 results[i] = BlobResult(*this, i);
387
388 return results;
389 }
390
392
394 class BlobFilter final
395 {
397 ValueRange<int> binarizationThreshold,
398 const BlobFilter &filter);
400 ValueRange<int> binarizationThreshold, Rect<int> aoi,
401 const BlobFilter &filter);
402 friend std::vector<BlobResult> SearchBlobs(const Image &binarizedImage, const BlobFilter &filter);
403 friend std::vector<BlobResult> SearchBlobs(const Image &binarizedImage, Rect<int> aoi,
404 const BlobFilter &filter);
405
406 public:
408
411 BlobFilter() = default;
412
414
419 {
420 return borderFilter_;
421 }
422
424
429 {
430 borderFilter_ = borderFilter;
431 }
432
434
439 bool ContainsRangeFilter(BlobRangeFilter rangeFilter) const noexcept
440 {
441 return rangeFilters_.find(rangeFilter) != rangeFilters_.end();
442 }
443
445
454 {
455 return rangeFilters_[rangeFilter];
456 }
457
458 private:
459 void Apply(Internal::BlobAnalyzer &analyzer) const
460 {
462 analyzer.SetBorderFilter(borderFilter_);
463 if (ContainsRangeFilter(BlobRangeFilter::Size))
464 analyzer.SetSizeFilter(rangeFilters_[BlobRangeFilter::Size]);
465 if (ContainsRangeFilter(BlobRangeFilter::Width))
466 analyzer.SetWidthFilter(rangeFilters_[BlobRangeFilter::Width]);
467 if (ContainsRangeFilter(BlobRangeFilter::Height))
468 analyzer.SetHeightFilter(rangeFilters_[BlobRangeFilter::Height]);
469 }
470
472 mutable std::map<BlobRangeFilter, ValueRange<int>> rangeFilters_;
473 };
474
476
483 ValueRange<int> binarizationThreshold)
484 {
485 Internal::BlobAnalyzer analyzer(plane);
486 analyzer.SetBinarizationRange(binarizationThreshold);
487 return analyzer.Run();
488 }
489
491
499 ValueRange<int> binarizationThreshold, Rect<int> aoi)
500 {
501 Internal::BlobAnalyzer analyzer(plane);
502 analyzer.SetBinarizationRange(binarizationThreshold);
503 analyzer.SetAOI(aoi);
504 return analyzer.Run();
505 }
506
508
516 BinarizeAndSearchBlobs(const ImagePlane &plane, ValueRange<int> binarizationThreshold, const BlobFilter &filter)
517 {
518 Internal::BlobAnalyzer analyzer(plane);
519 analyzer.SetBinarizationRange(binarizationThreshold);
520 filter.Apply(analyzer);
521 return analyzer.Run();
522 }
523
525
534 ValueRange<int> binarizationThreshold, Rect<int> aoi,
535 const BlobFilter &filter)
536 {
537 Internal::BlobAnalyzer analyzer(plane);
538 analyzer.SetBinarizationRange(binarizationThreshold);
539 analyzer.SetAOI(aoi);
540 filter.Apply(analyzer);
541 return analyzer.Run();
542 }
543
545
552 inline std::vector<BlobResult> SearchBlobs(const Image &binarizedImage)
553 {
554 Internal::BlobAnalyzer analyzer(binarizedImage.Plane(0));
555 analyzer.SetSkipBinarzation(true);
556 return analyzer.Run();
557 }
558
560
568 inline std::vector<BlobResult> SearchBlobs(const Image &binarizedImage, Rect<int> aoi)
569 {
570 Internal::BlobAnalyzer analyzer(binarizedImage.Plane(0));
571 analyzer.SetSkipBinarzation(true);
572 analyzer.SetAOI(aoi);
573 return analyzer.Run();
574 }
575
577
585 inline std::vector<BlobResult> SearchBlobs(const Image &binarizedImage, const BlobFilter &filter)
586 {
587 Internal::BlobAnalyzer analyzer(binarizedImage.Plane(0));
588 analyzer.SetSkipBinarzation(true);
589 filter.Apply(analyzer);
590 return analyzer.Run();
591 }
592
594
603 inline std::vector<BlobResult> SearchBlobs(const Image &binarizedImage, Rect<int> aoi, const BlobFilter &filter)
604 {
605 Internal::BlobAnalyzer analyzer(binarizedImage.Plane(0));
606 analyzer.SetSkipBinarzation(true);
607 analyzer.SetAOI(aoi);
608 filter.Apply(analyzer);
609 return analyzer.Run();
610 }
611
612 } // namespace Blob
613
616 using Blob::BlobFilter;
618 using Blob::BlobResult;
619 using Blob::SearchBlobs;
620
621 } // namespace Foundation
622
623 CVB_END_INLINE_NS
624
625} // namespace Cvb
626
627#endif
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
Class to build a filter for the blob search.
Definition blob.hpp:395
BlobFilter()=default
Default filter without any filter set.
friend std::vector< BlobResult > BinarizeAndSearchBlobs(const ImagePlane &plane, ValueRange< int > binarizationThreshold, const BlobFilter &filter)
Searches for all blobs in the given image plane.
Definition blob.hpp:516
ValueRange< int > & operator[](BlobRangeFilter rangeFilter)
Sets the range filters via an attribute.
Definition blob.hpp:453
Cvb::Foundation::Blob::BlobBorderFilter BorderFilter() const noexcept
Gets whether to filter blobs that touch the borders of the image.
Definition blob.hpp:418
bool ContainsRangeFilter(BlobRangeFilter rangeFilter) const noexcept
Check if a range filter exists.
Definition blob.hpp:439
void SetBorderFilter(Cvb::Foundation::Blob::BlobBorderFilter borderFilter) noexcept
Sets whether to filter blobs that touch the borders of the image.
Definition blob.hpp:428
friend std::vector< BlobResult > SearchBlobs(const Image &binarizedImage, const BlobFilter &filter)
Searches for all blobs in the given binarized image.
Definition blob.hpp:585
Container for a blob analysis result.
Definition blob.hpp:216
std::vector< Point2D< int > > MinimumMomentPoints() const
Points where the major axis of the blob intersects with the blob's bounding box.
Definition blob.hpp:322
Angle MomentAngle() const noexcept
Angle between Major moment axis and the x-axis.
Definition blob.hpp:312
Point2D< double > Center() const noexcept
Position of the blob's center.
Definition blob.hpp:250
double Size() const noexcept
Size (area) of the blob in pixels.
Definition blob.hpp:260
Rect< int > BoundingBox() const noexcept
Bounding box of the blob.
Definition blob.hpp:270
double Y() const noexcept
Get Y component of the blob center.
Definition blob.hpp:240
double MinimumMoment() const noexcept
Minimum inertial moment (smaller 2nd order moment translated into the blob's major/minor axis coordin...
Definition blob.hpp:281
double X() const noexcept
Get X component of the blob center.
Definition blob.hpp:230
double MomentRatio() const noexcept
Ratio of the minimum moment and the maximum moment of this blob.
Definition blob.hpp:302
double MaximumMoment() const noexcept
Maximum inertial moment (larger 2nd order moments translated into the blob's major/minor axis coordin...
Definition blob.hpp:292
Class to build a filter for the blob search.
Definition blob.hpp:395
Container for a blob analysis result.
Definition blob.hpp:216
The Common Vision Blox image.
Definition decl_image.hpp:50
ImagePlane Plane(int plane) const
Indexed access to the individual plane information.
Definition detail_image.hpp:58
Image plane information container.
Definition decl_image_plane.hpp:29
Plane information container.
Definition decl_plane.hpp:25
Multi-purpose 2D vector class.
Definition point_2d.hpp:20
Rectangle object.
Definition rect.hpp:24
Stores a pair of numbers that represents the width and the height of a subject, typically a rectangle...
Definition size_2d.hpp:20
Container for range definitions.
Definition value_range.hpp:17
cvbres_t FBlobSetLimitWidth(FBLOB Handle, long Min, long Max)
cvbres_t FBlobSetArea(FBLOB Handle, long Index, long left, long top, long right, long bottom)
cvbres_t FBlobGetCenterEx(FBLOB Handle, long BlobNum, double &CenterX, double &CenterY)
FBLOB FBlobCreate(IMG Image, long Index)
cvbres_t FBlobSetLimitArea(FBLOB Handle, long AreaMin, long AreaMax)
cvbres_t FBlobSetLimitHeight(FBLOB Handle, long Min, long Max)
cvbres_t FBlobGetBoundingBoxEx(FBLOB Handle, long BlobNum, long &x, long &y, long &dx, long &dy)
cvbres_t FBlobSetObjectTouchBorder(FBLOB Handle, long Mask)
cvbres_t FBlobGetSize(FBLOB Handle, long BlobNum, long &Size)
cvbres_t FBlobGetMoments(FBLOB Handle, long BlobNum, double &Min, double &Max, double &Ratio, double &Angle)
cvbres_t FBlobGetMinMomentPointsEx(FBLOB Handle, long BlobNum, long &x0, long &y0, long &x1, long &y1)
cvbres_t FBlobSetSkipBinarization(FBLOB Handle, cvbbool_t Skip)
cvbres_t FBlobSetObjectFeatureRange(FBLOB Handle, long FeatureMin, long FeatureMax)
Blob search methods.
Definition blob.hpp:50
std::vector< BlobResult > BinarizeAndSearchBlobs(const ImagePlane &plane, ValueRange< int > binarizationThreshold)
Searches for all blobs in the given image plane.
Definition blob.hpp:482
BlobBorderFilter
Enumeration for filtering blobs that touch the boundaries of the AOI specified for blob extraction.
Definition blob.hpp:68
@ Bottom
Filter out those blobs that touch the bottom border.
Definition blob.hpp:78
@ None
Do not filter out those blobs that touch a border.
Definition blob.hpp:70
@ Right
Filter out those blobs that touch the right border.
Definition blob.hpp:72
@ Left
Filter out those blobs that touch the left border.
Definition blob.hpp:76
@ Top
Filter out those blobs that touch the top border.
Definition blob.hpp:74
@ All
Filter out those blobs that touch any border.
Definition blob.hpp:80
BlobRangeFilter
Defines the attribute for a blob filter range.
Definition blob.hpp:54
@ Width
Width of the blob in pixels.
Definition blob.hpp:58
@ Size
Area of the blob in pixels.
Definition blob.hpp:56
@ Height
Height of the blob in pixels.
Definition blob.hpp:60
std::vector< BlobResult > SearchBlobs(const Image &binarizedImage)
Searches for all blobs in the given binarized image.
Definition blob.hpp:552
Namespace for the Foundation package.
Definition decl_metric_aqs12_calibration_piece.hpp:11
Root namespace for the Image Manager interface.
Definition c_bayer_to_rgb.h:17