19#include <unordered_map>
25struct RasterStatsOptions
27 static constexpr float min_coverage_fraction_default =
28 std::numeric_limits<float>::min();
30 float min_coverage_fraction = min_coverage_fraction_default;
31 bool calc_variance =
false;
32 bool store_histogram =
false;
33 bool store_values =
false;
34 bool store_weights =
false;
35 bool store_coverage_fraction =
false;
36 bool store_xy =
false;
37 bool include_nodata =
false;
38 double default_weight = std::numeric_limits<double>::quiet_NaN();
40 bool operator==(
const RasterStatsOptions &other)
const
42 return min_coverage_fraction == other.min_coverage_fraction &&
43 calc_variance == other.calc_variance &&
44 store_histogram == other.store_histogram &&
45 store_values == other.store_values &&
46 store_weights == other.store_weights &&
47 store_coverage_fraction == other.store_coverage_fraction &&
48 store_xy == other.store_xy &&
49 include_nodata == other.include_nodata &&
50 (default_weight == other.default_weight ||
51 (std::isnan(default_weight) &&
52 std::isnan(other.default_weight)));
55 bool operator!=(
const RasterStatsOptions &other)
const
57 return !(*
this == other);
80 void process(
double x,
double w)
87 double mean_old = mean;
90 mean += (w / sum_w) * (x - mean_old);
91 t += w * (x - mean_old) * (x - mean);
96 constexpr double variance()
const
105 return std::sqrt(variance());
110 double coefficent_of_variation()
const
112 return stdev() / mean;
116template <
typename ValueType>
class RasterStats
124 explicit RasterStats(
const RasterStatsOptions &options)
125 : m_min{std::numeric_limits<ValueType>::max()},
126 m_max{std::numeric_limits<ValueType>::lowest()}, m_sum_ciwi{0},
127 m_sum_ci{0}, m_sum_xici{0}, m_sum_xiciwi{0}, m_options{options}
132 void process(
const ValueType *pValues,
const GByte *pabyMask,
133 const double *padfWeights,
const GByte *pabyWeightsMask,
134 const double *padfX,
const double *padfY,
size_t nX,
size_t nY)
136 for (
size_t i = 0; i < nX * nY; i++)
138 if (pabyMask[i] == 255)
142 process_location(padfX[i % nX], padfY[i / nX]);
144 const double dfWeight =
146 ? (pabyWeightsMask[i] == 255
148 : std::numeric_limits<double>::quiet_NaN())
150 process_value(pValues[i], 1.0, dfWeight);
156 void process(
const ValueType *pValues,
const GByte *pabyMask,
157 const double *padfWeights,
const GByte *pabyWeightsMask,
158 const GByte *pabyCov,
const double *pdfX,
const double *pdfY,
159 size_t nX,
size_t nY)
161 for (
size_t i = 0; i < nX * nY; i++)
163 if (pabyMask[i] == 255 && pabyCov[i])
167 process_location(pdfX[i % nX], pdfY[i / nX]);
169 const double dfWeight =
171 ? (pabyWeightsMask[i] == 255
173 : std::numeric_limits<double>::quiet_NaN())
175 process_value(pValues[i], 1.0, dfWeight);
181 void process(
const ValueType *pValues,
const GByte *pabyMask,
182 const double *padfWeights,
const GByte *pabyWeightsMask,
183 const float *pfCov,
const double *pdfX,
const double *pdfY,
184 size_t nX,
size_t nY)
186 for (
size_t i = 0; i < nX * nY; i++)
188 if (pabyMask[i] == 255 &&
189 pfCov[i] >= m_options.min_coverage_fraction)
193 process_location(pdfX[i % nX], pdfY[i / nX]);
195 const double dfWeight =
197 ? (pabyWeightsMask[i] == 255
199 : std::numeric_limits<double>::quiet_NaN())
201 process_value(pValues[i], pfCov[i], dfWeight);
206 void process_location(
double x,
double y)
208 if (m_options.store_xy)
210 m_cell_x.push_back(x);
211 m_cell_y.push_back(y);
215 void process_value(
const ValueType &val,
float coverage,
double weight)
217 if (m_options.store_coverage_fraction)
219 m_cell_cov.push_back(coverage);
222 m_sum_ci +=
static_cast<double>(coverage);
223 m_sum_xici +=
static_cast<double>(val) *
static_cast<double>(coverage);
225 double ciwi =
static_cast<double>(coverage) * weight;
227 m_sum_xiciwi +=
static_cast<double>(val) * ciwi;
229 if (m_options.calc_variance)
231 m_variance.process(
static_cast<double>(val),
232 static_cast<double>(coverage));
233 m_weighted_variance.process(
static_cast<double>(val), ciwi);
239 if (m_options.store_xy)
241 m_min_xy = {m_cell_x.back(), m_cell_y.back()};
248 if (m_options.store_xy)
250 m_max_xy = {m_cell_x.back(), m_cell_y.back()};
254 if (m_options.store_histogram)
256 auto &entry = m_freq[val];
257 entry.m_sum_ci +=
static_cast<double>(coverage);
258 entry.m_sum_ciwi += ciwi;
261 if (m_options.store_values)
263 m_cell_values.push_back(val);
266 if (m_options.store_weights)
268 m_cell_weights.push_back(weight);
280 return sum() / count();
284 return std::numeric_limits<double>::quiet_NaN();
297 double weighted_mean()
const
299 if (weighted_count() > 0)
301 return weighted_sum() / weighted_count();
305 return std::numeric_limits<double>::quiet_NaN();
313 double weighted_fraction()
const
315 return weighted_sum() / sum();
324 std::optional<ValueType> mode()
const
326 auto it = std::max_element(
327 m_freq.cbegin(), m_freq.cend(),
328 [](
const auto &a,
const auto &b)
330 return a.second.m_sum_ci < b.second.m_sum_ci ||
331 (a.second.m_sum_ci == b.second.m_sum_ci &&
334 if (it == m_freq.end())
345 std::optional<ValueType> min()
const
356 std::optional<std::pair<double, double>> min_xy()
const
369 std::optional<ValueType> max()
const
380 std::optional<std::pair<double, double>> max_xy()
const
406 double weighted_sum()
const
426 std::optional<double> count(
const ValueType &value)
const
428 const auto &entry = m_freq.find(value);
430 if (entry == m_freq.end())
435 return entry->second.m_sum_ci;
443 std::optional<double> frac(
const ValueType &value)
const
445 auto count_for_value = count(value);
447 if (!count_for_value.has_value())
449 return count_for_value;
452 return count_for_value.value() / count();
459 std::optional<double> weighted_frac(
const ValueType &value)
const
461 auto count_for_value = weighted_count(value);
463 if (!count_for_value.has_value())
465 return count_for_value;
468 return count_for_value.value() / weighted_count();
476 double variance()
const
478 return m_variance.variance();
486 double weighted_variance()
const
488 return m_weighted_variance.variance();
499 return m_variance.stdev();
507 double weighted_stdev()
const
509 return m_weighted_variance.stdev();
521 double weighted_count()
const
535 std::optional<double> weighted_count(
const ValueType &value)
const
537 const auto &entry = m_freq.find(value);
539 if (entry == m_freq.end())
544 return entry->second.m_sum_ciwi;
555 std::optional<ValueType> minority()
const
557 auto it = std::min_element(
558 m_freq.cbegin(), m_freq.cend(),
559 [](
const auto &a,
const auto &b)
561 return a.second.m_sum_ci < b.second.m_sum_ci ||
562 (a.second.m_sum_ci == b.second.m_sum_ci &&
565 if (it == m_freq.end())
576 std::uint64_t variety()
const
578 return m_freq.size();
581 const std::vector<ValueType> &values()
const
583 return m_cell_values;
586 const std::vector<bool> &values_defined()
const
588 return m_cell_values_defined;
591 const std::vector<float> &coverage_fractions()
const
596 const std::vector<double> &weights()
const
598 return m_cell_weights;
601 const std::vector<bool> &weights_defined()
const
603 return m_cell_weights_defined;
606 const std::vector<double> ¢er_x()
const
611 const std::vector<double> ¢er_y()
const
616 const auto &freq()
const
624 std::pair<double, double> m_min_xy{
625 std::numeric_limits<double>::quiet_NaN(),
626 std::numeric_limits<double>::quiet_NaN()};
627 std::pair<double, double> m_max_xy{
628 std::numeric_limits<double>::quiet_NaN(),
629 std::numeric_limits<double>::quiet_NaN()};
634 double m_sum_ciwi{0};
636 double m_sum_xici{0};
637 double m_sum_xiciwi{0};
639 WestVariance m_variance{};
640 WestVariance m_weighted_variance{};
642 struct ValueFreqEntry
645 double m_sum_ciwi = 0;
648 std::unordered_map<ValueType, ValueFreqEntry> m_freq{};
650 std::vector<float> m_cell_cov{};
651 std::vector<ValueType> m_cell_values{};
652 std::vector<double> m_cell_weights{};
653 std::vector<double> m_cell_x{};
654 std::vector<double> m_cell_y{};
655 std::vector<bool> m_cell_values_defined{};
656 std::vector<bool> m_cell_weights_defined{};
658 RasterStatsOptions m_options;
662std::ostream &operator<<(std::ostream &os,
const RasterStats<T> &stats)
664 os <<
"{" << std::endl;
665 os <<
" \"count\" : " << stats.count() <<
"," << std::endl;
668 if (stats.min().has_value())
670 os << stats.min().value();
676 os <<
"," << std::endl;
679 if (stats.max().has_value())
681 os << stats.max().value();
687 os <<
"," << std::endl;
689 os <<
" \"mean\" : " << stats.mean() <<
"," << std::endl;
690 os <<
" \"sum\" : " << stats.sum() <<
"," << std::endl;
691 os <<
" \"weighted_mean\" : " << stats.weighted_mean() <<
"," << std::endl;
692 os <<
" \"weighted_sum\" : " << stats.weighted_sum();
693 if (stats.stores_values())
695 os <<
"," << std::endl;
696 os <<
" \"mode\" : ";
697 if (stats.mode().has_value())
699 os << stats.mode().value();
705 os <<
"," << std::endl;
707 os <<
" \"minority\" : ";
708 if (stats.minority().has_value())
710 os << stats.minority().value();
716 os <<
"," << std::endl;
718 os <<
" \"variety\" : " << stats.variety() << std::endl;
724 os <<
"}" << std::endl;
unsigned char GByte
Unsigned byte type.
Definition cpl_port.h:175