NumCpp  2.11.0
A Templatized Header Only C++ Implementation of the Python NumPy Library
Centroid.hpp
Go to the documentation of this file.
1 #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"
41 #include "NumCpp/Utils/num2str.hpp"
42 
43 namespace nc::imageProcessing
44 {
45  //================================================================================
46  // Class Description:
48  template<typename dtype>
49  class Centroid
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
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
friend std::ostream & operator<<(std::ostream &inStream, const Centroid< dtype > &inCentriod)
Definition: Centroid.hpp:247
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:48
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