NumCpp  2.12.1
A Templatized Header Only C++ Implementation of the Python NumPy Library
Centroid.hpp
Go to the documentation of this file.
1
28#pragma once
29
30#include <cmath>
31#include <iostream>
32#include <string>
33#include <type_traits>
34
36#include "NumCpp/Core/Types.hpp"
39#include "NumCpp/NdArray.hpp"
42
43namespace nc::imageProcessing
44{
45 //================================================================================
46 // Class Description:
48 template<typename dtype>
50 {
51 private:
52 STATIC_ASSERT_ARITHMETIC(dtype);
53
54 public:
55 using accumulator_t = typename std::conditional<std::is_integral<dtype>::value, int64, double>::type;
56
57 //=============================================================================
58 // Description:
61 Centroid() = default;
62
63 //=============================================================================
64 // Description:
69 explicit Centroid(const Cluster<dtype>& inCluster) :
70 intensity_(inCluster.intensity()),
71 eod_(inCluster.eod())
72 {
73 centerOfMass(inCluster);
74 setEllipseProperties(inCluster);
75 }
76
77 //=============================================================================
78 // Description:
83 [[nodiscard]] double row() const noexcept
84 {
85 return row_;
86 }
87
88 //=============================================================================
89 // Description:
94 [[nodiscard]] double col() const noexcept
95 {
96 return col_;
97 }
98
99 //=============================================================================
100 // Description:
105 [[nodiscard]] accumulator_t intensity() const noexcept
106 {
107 return intensity_;
108 }
109
110 //=============================================================================
111 // Description:
116 [[nodiscard]] double eod() const noexcept
117 {
118 return eod_;
119 }
120
121 //=============================================================================
122 // Description:
127 [[nodiscard]] double a() const noexcept
128 {
129 return a_;
130 }
131
132 //=============================================================================
133
134 // Description:
139 [[nodiscard]] double b() const noexcept
140 {
141 return b_;
142 }
143
144 //=============================================================================
145 // Description:
150 [[nodiscard]] double eccentricity() const noexcept
151 {
152 return eccentricity_;
153 }
154
155 //=============================================================================
156
157 // Description:
162 [[nodiscard]] double orientation() const noexcept
163 {
164 return orientation_;
165 }
166
167 //=============================================================================
168 // Description:
173 [[nodiscard]] std::string str() const
174 {
175 std::string out = "row = " + utils::num2str(row_) + " col = " + utils::num2str(col_) +
176 " intensity = " + utils::num2str(intensity_) + " eod = " + utils::num2str(eod_) +
177 " a = " + utils::num2str(a_) + " b = " + utils::num2str(b_) +
178 " eccentricity = " + utils::num2str(eccentricity_) +
179 " orientation = " + utils::num2str(orientation_) + '\n';
180
181 return out;
182 }
183
184 //============================================================================
188 void print() const
189 {
190 std::cout << *this;
191 }
192
193 //=============================================================================
194 // Description:
201 bool operator==(const Centroid<dtype>& rhs) const noexcept
202 {
203 return (utils::essentiallyEqual(row_, rhs.row_) && utils::essentiallyEqual(col_, rhs.col_) &&
204 utils::essentiallyEqual(intensity_, rhs.intensity_) && utils::essentiallyEqual(eod_, rhs.eod_) &&
205 utils::essentiallyEqual(a_, rhs.a_) && utils::essentiallyEqual(b_, rhs.b_) &&
206 utils::essentiallyEqual(eccentricity_, rhs.eccentricity_) &&
207 utils::essentiallyEqual(orientation_, rhs.orientation_));
208 }
209
210 //=============================================================================
211 // Description:
218 bool operator!=(const Centroid<dtype>& rhs) const noexcept
219 {
220 return !(*this == rhs);
221 }
222
223 //=============================================================================
224 // Description:
234 bool operator<(const Centroid<dtype>& rhs) const noexcept
235 {
236 return intensity_ < rhs.intensity_ ? false : true;
237 }
238
239 //=============================================================================
240 // Description:
247 friend std::ostream& operator<<(std::ostream& inStream, const Centroid<dtype>& inCentriod)
248 {
249 inStream << inCentriod.str();
250 return inStream;
251 }
252
253 private:
254 //==================================Attributes================================///
255 double row_{ 0. };
256 double col_{ 0. };
257 accumulator_t intensity_{ 0 };
258 double eod_{ 0. };
260 double a_{};
262 double b_{};
264 double eccentricity_{};
266 double orientation_{};
267
268 //=============================================================================
269 // Description:
276 void centerOfMass(const Cluster<dtype>& inCluster)
277 {
278 const Shape clusterShape(inCluster.height(), inCluster.width());
279 NdArray<dtype> clusterArray(clusterShape);
280 clusterArray.zeros();
281
282 const uint32 rowMin = inCluster.rowMin();
283 const uint32 colMin = inCluster.colMin();
284
285 for (auto& pixel : inCluster)
286 {
287 clusterArray(pixel.row - rowMin, pixel.col - colMin) = pixel.intensity;
288 }
289
290 const auto rowCol = nc::centerOfMass(clusterArray);
291 row_ = rowCol.front() + rowMin;
292 col_ = rowCol.back() + colMin;
293 }
294
295 //=============================================================================
296 // Description:
301 void setEllipseProperties(const Cluster<dtype>& inCluster) noexcept
302 {
303 constexpr auto two = static_cast<double>(2.);
304
305 auto m20 = static_cast<double>(0.);
306 auto m02 = static_cast<double>(0.);
307 auto m11 = static_cast<double>(0.);
308
309 for (typename Cluster<dtype>::const_iterator iter = inCluster.begin(); iter != inCluster.end(); ++iter)
310 {
311 const auto& pixel = *iter;
312 const double deltaX = pixel.col - col_;
313 const double deltaY = pixel.row - row_;
314
315 m11 += deltaX * deltaY;
316 m20 += utils::sqr(deltaX);
317 m02 += utils::sqr(deltaY);
318 }
319
320 const auto numPixels = static_cast<double>(inCluster.size());
321 m11 /= numPixels;
322 m20 /= numPixels;
323 m02 /= numPixels;
324
325 double piece1 = m20 + m02;
326 piece1 /= two;
327
328 double piece2 = std::sqrt(static_cast<double>(4.) * utils::sqr(m11) + utils::sqr(m20 - m02));
329 piece2 /= two;
330
331 const double lambda1 = piece1 - piece2;
332 const double lambda2 = piece1 + piece2;
333
334 eccentricity_ = std::sqrt(static_cast<double>(1.) - lambda1 / lambda2);
335 orientation_ = static_cast<double>(-0.5) * std::atan2(two * m11, m20 - m02);
336 a_ = two * std::sqrt(lambda2);
337 b_ = two * std::sqrt(lambda1);
338 }
339 };
340} // namespace nc::imageProcessing
holds the information for a centroid
Definition: Centroid.hpp:50
bool operator<(const Centroid< dtype > &rhs) const noexcept
Definition: Centroid.hpp:234
double eod() const noexcept
Definition: Centroid.hpp:116
friend std::ostream & operator<<(std::ostream &inStream, const Centroid< dtype > &inCentriod)
Definition: Centroid.hpp:247
double b() const noexcept
Definition: Centroid.hpp:139
void print() const
Definition: Centroid.hpp:188
accumulator_t intensity() const noexcept
Definition: Centroid.hpp:105
double col() const noexcept
Definition: Centroid.hpp:94
bool operator==(const Centroid< dtype > &rhs) const noexcept
Definition: Centroid.hpp:201
Centroid(const Cluster< dtype > &inCluster)
Definition: Centroid.hpp:69
double eccentricity() const noexcept
Definition: Centroid.hpp:150
bool operator!=(const Centroid< dtype > &rhs) const noexcept
Definition: Centroid.hpp:218
double row() const noexcept
Definition: Centroid.hpp:83
std::string str() const
Definition: Centroid.hpp:173
typename std::conditional< std::is_integral< dtype >::value, int64, double >::type accumulator_t
Definition: Centroid.hpp:55
double a() const noexcept
Definition: Centroid.hpp:127
double orientation() const noexcept
Definition: Centroid.hpp:162
Holds the information for a cluster of pixels.
Definition: Cluster.hpp:53
typename std::vector< Pixel< dtype > >::const_iterator const_iterator
Definition: Cluster.hpp:59
Definition: applyThreshold.hpp:34
std::string num2str(dtype inNumber)
Definition: num2str.hpp:44
bool essentiallyEqual(dtype inValue1, dtype inValue2) noexcept
Definition: essentiallyEqual.hpp:49
constexpr dtype sqr(dtype inValue) noexcept
Definition: sqr.hpp:42
std::int64_t int64
Definition: Types.hpp:35
NdArray< double > centerOfMass(const NdArray< dtype > &inArray, Axis inAxis=Axis::NONE)
Definition: centerOfMass.hpp:47
auto sqrt(dtype inValue) noexcept
Definition: sqrt.hpp:48
std::uint32_t uint32
Definition: Types.hpp:40