OpenEV
Extending OpenCV to event-based vision
Loading...
Searching...
No Matches
stats.hpp
Go to the documentation of this file.
1
6#ifndef OPENEV_CORE_STATS_HPP
7#define OPENEV_CORE_STATS_HPP
8
10#include <algorithm>
11#include <climits>
12#include <cmath>
13#include <cstddef>
14#include <cstdint>
15#include <opencv2/core/matx.hpp>
16#include <opencv2/core/types.hpp>
17#include <type_traits>
18#include <utility>
19#include <vector>
20
21namespace ev {
22[[maybe_unused]] constexpr bool USING_STATS_HPP = true;
23
25#define OPENEV_HAS_GETTER_(name) \
26 template <typename C, typename = void> \
27 struct has_##name##_ : std::false_type {}; \
28 template <typename C> \
29 struct has_##name##_<C, std::void_t<decltype(std::declval<const C &>().name())>> : std::true_type {};
30
31OPENEV_HAS_GETTER_(count)
32OPENEV_HAS_GETTER_(firstTimestamp)
33OPENEV_HAS_GETTER_(lastTimestamp)
34OPENEV_HAS_GETTER_(sum)
35OPENEV_HAS_GETTER_(sumT)
36OPENEV_HAS_GETTER_(sumP)
37OPENEV_HAS_GETTER_(squares)
38OPENEV_HAS_GETTER_(bounds)
39OPENEV_HAS_GETTER_(activeCount)
40OPENEV_HAS_GETTER_(peakCount)
41OPENEV_HAS_GETTER_(sumCLogC)
42#undef OPENEV_HAS_GETTER_
44
50template <typename Derived>
51class Stats_ {
52public:
53 using ResultType = TimeType;
54
59 [[nodiscard]] inline ResultType duration() const {
60 if constexpr(has_firstTimestamp_<Derived>::value && has_lastTimestamp_<Derived>::value) {
61 return self_().lastTimestamp() - self_().firstTimestamp();
62 } else {
63 return self_().back().t - self_().front().t;
64 }
65 }
66
71 [[nodiscard]] inline ResultType rate() const {
72 const ResultType span = duration();
73 return static_cast<ResultType>(count_()) / span;
74 }
75
81 [[nodiscard]] inline ResultType density(const cv::Size size) const {
82 return static_cast<ResultType>(count_()) / (static_cast<ResultType>(size.width) * static_cast<ResultType>(size.height));
83 }
84
89 [[nodiscard]] inline std::size_t activePixels() const {
90 if constexpr(has_activeCount_<Derived>::value) {
91 return self_().activeCount();
92 } else {
93 std::size_t active = 0;
94 forEachPixelCount_([&active](const uint32_t) { active++; });
95 return active;
96 }
97 }
98
104 [[nodiscard]] inline ResultType fillRatio(const cv::Size size) const {
105 return static_cast<ResultType>(activePixels()) / (static_cast<ResultType>(size.width) * static_cast<ResultType>(size.height));
106 }
107
113 [[nodiscard]] inline ResultType polarityRatio(const PolarityType p) const {
114 if constexpr(has_sumP_<Derived>::value) {
115 const ResultType positive = self_().sumP() / static_cast<ResultType>(count_());
116 return p ? positive : 1 - positive;
117 } else {
118 std::size_t matching = 0;
119 for(const auto &e : self_()) {
120 matching += e.p == p ? 1 : 0;
121 }
122 return static_cast<ResultType>(matching) / static_cast<ResultType>(count_());
123 }
124 }
125
130 [[nodiscard]] inline Event_<ResultType> mean() const {
131 if constexpr(has_sum_<Derived>::value && has_sumT_<Derived>::value && has_sumP_<Derived>::value) {
132 const auto n = static_cast<ResultType>(count_());
133 return {self_().sum().x / n, self_().sum().y / n, self_().sumT() / n, self_().sumP() / n > 0.5};
134 } else {
135 ResultType x{0};
136 ResultType y{0};
137 ResultType t{0};
138 ResultType p{0};
139 for(const auto &e : self_()) {
140 x += e.x;
141 y += e.y;
142 t += e.t;
143 p += e.p;
144 }
145 const auto n = static_cast<ResultType>(count_());
146 return {x / n, y / n, t / n, p / n > 0.5};
147 }
148 }
149
154 [[nodiscard]] inline cv::Point_<ResultType> meanPoint() const {
155 if constexpr(has_sum_<Derived>::value) {
156 return self_().sum() / static_cast<ResultType>(count_());
157 } else {
158 ResultType x{0};
159 ResultType y{0};
160 for(const auto &e : self_()) {
161 x += e.x;
162 y += e.y;
163 }
164 const auto n = static_cast<ResultType>(count_());
165 return {x / n, y / n};
166 }
167 }
168
173 [[nodiscard]] inline cv::Matx<ResultType, 2, 2> covariance() const {
174 if constexpr(has_sum_<Derived>::value && has_squares_<Derived>::value) {
175 const auto n = static_cast<ResultType>(count_());
176 const cv::Point_<ResultType> mean = self_().sum() / n;
177 const cv::Vec<ResultType, 3> squares = self_().squares() / n;
178 const ResultType xy = squares[2] - mean.x * mean.y;
179 return {squares[0] - mean.x * mean.x, xy, xy, squares[1] - mean.y * mean.y};
180 } else {
181 const cv::Point_<ResultType> mean = meanPoint();
182 ResultType xx{0};
183 ResultType yy{0};
184 ResultType xy{0};
185 for(const auto &e : self_()) {
186 const ResultType dx = e.x - mean.x;
187 const ResultType dy = e.y - mean.y;
188 xx += dx * dx;
189 yy += dy * dy;
190 xy += dx * dy;
191 }
192 const auto n = static_cast<ResultType>(count_());
193 return {xx / n, xy / n, xy / n, yy / n};
194 }
195 }
196
201 [[nodiscard]] inline cv::Rect boundingBox() const {
202 if constexpr(has_bounds_<Derived>::value) {
203 return self_().bounds();
204 } else {
205 return bounds_();
206 }
207 }
208
213 [[nodiscard]] inline ResultType meanTime() const {
214 if constexpr(has_sumT_<Derived>::value) {
215 return self_().sumT() / static_cast<ResultType>(count_());
216 } else {
217 ResultType t{0};
218 for(const auto &e : self_()) {
219 t += e.t;
220 }
221 return t / static_cast<ResultType>(count_());
222 }
223 }
224
229 [[nodiscard]] inline ResultType midTime() const {
230 if constexpr(has_firstTimestamp_<Derived>::value && has_lastTimestamp_<Derived>::value) {
231 return 0.5 * (self_().firstTimestamp() + self_().lastTimestamp());
232 } else {
233 return 0.5 * (self_().front().t + self_().back().t);
234 }
235 }
236
241 [[nodiscard]] inline std::size_t peak() const {
242 if constexpr(has_peakCount_<Derived>::value) {
243 return self_().peakCount();
244 } else {
245 uint32_t peak = 0;
246 forEachPixelCount_([&peak](const uint32_t count) { peak = std::max(peak, count); });
247 return peak;
248 }
249 }
250
256 [[nodiscard]] inline ResultType entropy() const {
257 const auto n = static_cast<ResultType>(count_());
258 if constexpr(has_sumCLogC_<Derived>::value) {
259 const ResultType h = std::log2(n) - self_().sumCLogC() / n;
260 return h < 0 ? 0 : h;
261 } else {
262 ResultType h{0};
263 forEachPixelCount_([&h, n](const uint32_t count) {
264 const ResultType p = static_cast<ResultType>(count) / n;
265 h -= p * std::log2(p);
266 });
267 return h;
268 }
269 }
270
271protected:
273 [[nodiscard]] inline const Derived &self_() const {
274 return static_cast<const Derived &>(*this);
275 }
276
277 [[nodiscard]] inline std::size_t count_() const {
278 if constexpr(has_count_<Derived>::value) {
279 return static_cast<std::size_t>(self_().count());
280 } else {
281 return self_().size();
282 }
283 }
284
285 template <typename E>
286 [[nodiscard]] inline static cv::Point pixel_(const E &e) {
287 if constexpr(std::is_floating_point_v<decltype(e.x)>) {
288 return {round_(e.x), round_(e.y)};
289 } else {
290 return {static_cast<int>(e.x), static_cast<int>(e.y)};
291 }
292 }
293
294 [[nodiscard]] inline cv::Rect bounds_() const {
295 int left = INT_MAX;
296 int right = INT_MIN;
297 int top = INT_MAX;
298 int bottom = INT_MIN;
299 for(const auto &e : self_()) {
300 const cv::Point pixel = pixel_(e);
301 left = std::min(left, pixel.x);
302 right = std::max(right, pixel.x);
303 top = std::min(top, pixel.y);
304 bottom = std::max(bottom, pixel.y);
305 }
306 return {left, top, right - left + 1, bottom - top + 1};
307 }
308
309 template <typename Fn>
310 inline void forEachPixelCount_(Fn fn) const {
311 constexpr uint64_t MAX_AREA_PER_EVENT = 32;
312 const cv::Rect bounds = boundingBox();
313 const auto width = static_cast<uint64_t>(bounds.width);
314 const auto height = static_cast<uint64_t>(bounds.height);
315
316 if(width <= (MAX_AREA_PER_EVENT * count_()) / height) {
317 std::vector<uint32_t> counts(width * height, 0);
318 for(const auto &e : self_()) {
319 const cv::Point pixel = pixel_(e);
320 counts[(static_cast<uint64_t>(pixel.y - bounds.y) * width) + static_cast<uint64_t>(pixel.x - bounds.x)]++;
321 }
322 for(const uint32_t count : counts) {
323 if(count > 0) {
324 fn(count);
325 }
326 }
327 } else {
328 std::vector<uint64_t> keys;
329 keys.reserve(count_());
330 for(const auto &e : self_()) {
331 const cv::Point pixel = pixel_(e);
332 keys.push_back((static_cast<uint64_t>(static_cast<uint32_t>(pixel.y)) << 32U) | static_cast<uint32_t>(pixel.x));
333 }
334 std::sort(keys.begin(), keys.end());
335 uint32_t run = 1;
336 for(std::size_t i = 1; i <= keys.size(); i++) {
337 if(i == keys.size() || keys[i] != keys[i - 1]) {
338 fn(run);
339 run = 1;
340 } else {
341 run++;
342 }
343 }
344 }
345 }
347};
348} // namespace ev
349
350#endif // OPENEV_CORE_STATS_HPP
This class extends cv::Point_<T> for event data. For more information, please refer here.
Definition types.hpp:86
This is an auxiliary class. This class cannot be instanced.
Definition stats.hpp:51
ResultType midTime() const
Calculate the midpoint time between the oldest and the newest event.
Definition stats.hpp:229
ResultType fillRatio(const cv::Size size) const
Compute fill ratio as the fraction of pixels with at least one event.
Definition stats.hpp:104
ResultType duration() const
Time difference between the last and the first event.
Definition stats.hpp:59
cv::Point_< ResultType > meanPoint() const
Compute the mean x,y point of the events.
Definition stats.hpp:154
Event_< ResultType > mean() const
Compute the mean of the events.
Definition stats.hpp:130
std::size_t peak() const
Find the largest number of events on a single pixel.
Definition stats.hpp:241
ResultType density(const cv::Size size) const
Compute event density as the ratio between the number of events and the number of pixels.
Definition stats.hpp:81
ResultType entropy() const
Compute the Shannon entropy of the spatial distribution of the events.
Definition stats.hpp:256
ResultType rate() const
Compute event rate as the ratio between the number of events and the time difference between the last...
Definition stats.hpp:71
std::size_t activePixels() const
Count the pixels with at least one event.
Definition stats.hpp:89
ResultType polarityRatio(const PolarityType p) const
Compute polarity ratio as the fraction of events with the given polarity.
Definition stats.hpp:113
ResultType meanTime() const
Compute the mean time of the events.
Definition stats.hpp:213
cv::Rect boundingBox() const
Compute the smallest rectangle of pixels containing the events.
Definition stats.hpp:201
cv::Matx< ResultType, 2, 2 > covariance() const
Compute the covariance of the x,y coordinates of the events around meanPoint().
Definition stats.hpp:173
Basic event-based vision structures based on OpenCV components.