14#include <xtensor/xstrided_view.hpp>
23inline std::string get_namespace()
25 std::string ret =
"GooseEYE";
26#ifdef GOOSEEYE_USE_XTENSOR_PYTHON
38inline std::string shape_to_string(
const T& shape)
40 std::string ret =
"[";
41 for (
size_t i = 0; i < shape.size(); ++i) {
42 ret += std::to_string(shape[i]);
43 if (i < shape.size() - 1) {
67 std::vector<size_t> shape(ndim, 3);
72 xt::view(kern, xt::all()) = 1;
77 xt::view(kern, xt::keep(1), xt::all()) = 1;
78 xt::view(kern, xt::all(), xt::keep(1)) = 1;
82 xt::view(kern, xt::keep(1), xt::all(), xt::all()) = 1;
83 xt::view(kern, xt::all(), xt::keep(1), xt::all()) = 1;
84 xt::view(kern, xt::all(), xt::all(), xt::keep(1)) = 1;
121 const std::vector<size_t>& shape,
125 bool periodic =
true)
134 for (
size_t i = 0; i < row.size(); ++i) {
135 for (
int di = -r(i); di <= r(i); ++di) {
136 for (
int dj = -r(i); dj <= r(i); ++dj) {
137 int dr = (int)(ceil(pow((
double)(pow(di, 2) + pow(dj, 2)), 0.5)));
139 out.periodic(row(i) + di, col(i) + dj) = 1;
148 for (
size_t i = 0; i < row.size(); ++i) {
149 for (
int di = -r(i); di <= r(i); ++di) {
150 for (
int dj = -r(i); dj <= r(i); ++dj) {
151 if (out.in_bounds(row(i) + di, col(i) + dj)) {
152 int dr = (int)(ceil(pow((
double)(pow(di, 2) + pow(dj, 2)), 0.5)));
154 out(row(i) + di, col(i) + dj) = 1;
172dummy_circles(
const std::vector<size_t>& shape,
bool periodic =
true, uint64_t seed = 0)
175 prrng::pcg32 rng(seed);
178 size_t N = (size_t)(0.05 * (
double)shape[0]);
179 size_t M = (size_t)(0.05 * (
double)shape[1]);
180 size_t R = (size_t)(pow((0.3 * (
double)(shape[0] * shape[1])) / (M_PI * (double)(N * M)), 0.5));
187 for (
size_t i = 0; i < N; i++) {
188 for (
size_t j = 0; j < M; j++) {
189 row[i * M + j] = (int)((
double)i * (double)shape[0] / (
double)N);
190 col[i * M + j] = (int)((
double)j * (double)shape[1] / (
double)M);
191 r[i * M + j] = (int)R;
196 int dN = (int)(0.5 * (
double)shape[0] / (double)N);
197 int dM = (int)(0.5 * (
double)shape[1] / (double)M);
200 for (
size_t i = 0; i < N * M; i++) {
201 row(i) += rng.randint(2 * dN) - dN;
202 col(i) += rng.randint(2 * dM) - dM;
203 r(i) = (double)r(i) * 2.0 * rng.random();
212template <
class S,
class U>
213inline void periodic_copy_below_to_above(S&& F,
const U& Pad)
215 xt::xstrided_slice_vector sbelow(F.dimension());
216 xt::xstrided_slice_vector sabove(F.dimension());
218 for (
size_t ax = 0; ax < F.dimension(); ++ax) {
219 if (F.shape(ax) <= 1) {
223 for (
size_t i = 0; i < ax; ++i) {
224 sbelow[i] = xt::all();
225 sabove[i] = xt::all();
228 sbelow[ax] = xt::range(0, Pad[ax][0]);
229 sabove[ax] = xt::range(F.shape(ax) - Pad[ax][1] - Pad[ax][0], F.shape(ax) - Pad[ax][1]);
231 for (
size_t i = ax + 1; i < F.dimension(); ++i) {
232 sbelow[i] = xt::all();
233 sabove[i] = xt::all();
236 auto below = xt::strided_view(F, sbelow);
237 auto above = xt::strided_view(F, sabove);
239 above = xt::where(xt::not_equal(below, 0), below, above);
243template <
class S,
class U>
244inline void periodic_copy_above_to_below(S&& F,
const U& Pad)
246 xt::xstrided_slice_vector sbelow(F.dimension());
247 xt::xstrided_slice_vector sabove(F.dimension());
249 for (
size_t ax = 0; ax < F.dimension(); ++ax) {
250 if (F.shape(ax) <= 1) {
254 for (
size_t i = 0; i < ax; ++i) {
255 sbelow[i] = xt::all();
256 sabove[i] = xt::all();
259 sbelow[ax] = xt::range(Pad[ax][0], Pad[ax][0] + Pad[ax][1]);
260 sabove[ax] = xt::range(F.shape(ax) - Pad[ax][1], F.shape(ax));
262 for (
size_t i = ax + 1; i < F.dimension(); ++i) {
263 sbelow[i] = xt::all();
264 sabove[i] = xt::all();
267 auto below = xt::strided_view(F, sbelow);
268 auto above = xt::strided_view(F, sabove);
270 below = xt::where(xt::not_equal(above, 0), above, below);
274template <
class S,
class U>
275inline void periodic_copy(S&& F,
const U& Pad)
277 periodic_copy_above_to_below(F, Pad);
278 periodic_copy_below_to_above(F, Pad);
296 std::is_integral<typename T::value_type>::value &&
297 std::is_integral<typename S::value_type>::value,
303 bool periodic =
true)
305 using value_type =
typename T::value_type;
307 GOOSEEYE_ASSERT(f.dimension() == kernel.dimension(), std::out_of_range);
308 GOOSEEYE_ASSERT(xt::all(xt::equal(kernel, 0) || xt::equal(kernel, 1)), std::out_of_range);
309 GOOSEEYE_ASSERT(
static_cast<size_t>(xt::amax(f)()) <= iterations.size() + 1, std::out_of_range);
311 xt::pad_mode pad_mode = xt::pad_mode::constant;
315 pad_mode = xt::pad_mode::periodic;
319 auto Pad = detail::pad_width(K);
323 for (
size_t iter = 0; iter < xt::amax(iterations)(0); ++iter) {
325 for (
size_t h = Pad[0][0]; h < F.shape(0) - Pad[0][1]; ++h) {
326 for (
size_t i = Pad[1][0]; i < F.shape(1) - Pad[1][1]; ++i) {
327 for (
size_t j = Pad[2][0]; j < F.shape(2) - Pad[2][1]; ++j) {
330 value_type l = F(h, i, j);
338 if (iter >= iterations(l)) {
345 xt::range(h - Pad[0][0], h + Pad[0][1] + 1),
346 xt::range(i - Pad[1][0], i + Pad[1][1] + 1),
347 xt::range(j - Pad[2][0], j + Pad[2][1] + 1));
351 xt::range(h - Pad[0][0], h + Pad[0][1] + 1),
352 xt::range(i - Pad[1][0], i + Pad[1][1] + 1),
353 xt::range(j - Pad[2][0], j + Pad[2][1] + 1));
356 Gi = xt::where(xt::equal(Fi, 0) && xt::equal(K, 1), l, Gi);
363 detail::periodic_copy(G, Pad);
374 xt::range(Pad[0][0], F.shape(0) - Pad[0][1]),
375 xt::range(Pad[1][0], F.shape(1) - Pad[1][1]),
376 xt::range(Pad[2][0], F.shape(2) - Pad[2][1]));
379 std::copy(F.cbegin(), F.cend(), ret.begin());
387template <class T, std::enable_if_t<std::is_integral<typename T::value_type>::value,
int> = 0>
401 std::is_integral<typename T::value_type>::value &&
402 std::is_integral<typename S::value_type>::value,
404inline T
dilate(
const T& f,
const S& kernel,
size_t iterations = 1,
bool periodic =
true)
407 return dilate(f, kernel, iter, periodic);
414template <class T, std::enable_if_t<std::is_integral<typename T::value_type>::value,
int> = 0>
415inline T
dilate(
const T& f,
size_t iterations = 1,
bool periodic =
true)
430 using value_type =
typename T::value_type;
431 std::map<value_type, value_type> map;
433 for (
size_t i = 0; i < a.size(); ++i) {
434 map.try_emplace(a.flat(i), b.flat(i));
439 xt::empty<typename T::value_type>(std::array<size_t, 2>{map.size(), 2});
441 for (
auto const& [key, val] : map) {
456template <
class L,
class A>
461 using value_type =
typename A::value_type;
462 std::map<value_type, value_type> map;
463 for (
size_t i = 0; i < rename.shape(0); ++i) {
464 map.emplace(rename(i, 0), rename(i, 1));
467#ifdef GOOSEEYE_ENABLE_ASSERT
468 auto l = xt::unique(labels);
469 for (
size_t i = 0; i < l.size(); ++i) {
474 L ret = xt::empty_like(labels);
475 for (
size_t i = 0; i < labels.size(); ++i) {
476 ret.flat(i) = map[labels.flat(i)];
492 using value_type =
typename T::value_type;
493 auto unq = xt::unique(labels);
494 bool background = xt::any(xt::equal(unq, 0));
496 std::array<size_t, 2> shape = {unq.size(), 2};
503 for (
size_t i = 1; i < unq.size(); ++i) {
504 rename(i, 0) = unq(i);
510 for (
size_t i = 0; i < unq.size(); ++i) {
514 rename(row, 0) = unq(i);
515 rename(row, 1) = row;
521 for (
size_t i = 0; i < unq.size(); ++i) {
522 rename(i, 0) = unq(i);
523 rename(i, 1) = i + 1;
535template <
class L,
class A>
538#ifdef GOOSEEYE_ENABLE_ASSERT
539 auto a = xt::unique(labels);
540 auto b = xt::unique(order);
545 auto maxlab = *std::max_element(order.begin(), order.end());
546 std::vector<typename A::value_type> renum(maxlab + 1);
548 for (
size_t i = 0; i < order.size(); ++i) {
552 L ret = xt::empty_like(labels);
553 for (
size_t i = 0; i < labels.size(); ++i) {
554 ret.flat(i) = renum[labels.flat(i)];
563inline auto labels_sizes_impl(
const T& labels)
565 using value_type =
typename T::value_type;
566 std::map<value_type, value_type> map;
568 for (
size_t i = 0; i < labels.size(); ++i) {
569 if (map.count(labels.flat(i)) == 0) {
570 map.emplace(labels.flat(i), 1);
573 map[labels.flat(i)]++;
590 using value_type =
typename T::value_type;
591 auto map = detail::labels_sizes_impl(labels);
592 std::array<size_t, 2> shape = {map.size(), 2};
596 for (
auto const& [key, val] : map) {
611template <
class T,
class N>
614 using value_type =
typename T::value_type;
615 auto map = detail::labels_sizes_impl(labels);
617 for (
size_t i = 0; i < names.size(); ++i) {
618 ret(i) = map[names(i)];
630template <
size_t Dim,
class T>
633#ifdef GOOSEEYE_ENABLE_ASSERT
634 for (
size_t i = 0; i < Dim; ++i) {
639 std::array<size_t, Dim> mid;
640 for (
size_t i = 0; i < Dim; ++i) {
641 mid[i] = (kernel.shape(i) - 1) / 2;
644 for (
size_t i = 0; i < Dim; ++i) {
645 idx += mid[i] * kernel.strides()[i];
648 kernel.flat(idx) = 0;
650 if constexpr (Dim == 1) {
651 auto i = xt::flatten_indices(xt::argwhere(kernel)) - mid[0];
653 std::copy(i.begin(), i.end(), ret.begin());
657 auto ret = xt::from_indices(xt::argwhere(kernel));
658 for (
size_t i = 0; i < Dim; ++i) {
659 xt::view(ret, xt::all(), i) -= mid[i];
671template <
size_t Dimension,
bool Periodicity = true>
674 static constexpr size_t Dim = Dimension;
678 std::array<ptrdiff_t, Dim> m_shape;
681 ptrdiff_t m_new_label = 1;
683 std::array<ptrdiff_t, Dim> m_strides;
691 std::vector<ptrdiff_t> m_renum;
703 std::vector<ptrdiff_t> m_next;
704 std::vector<ptrdiff_t> m_connected;
716 if constexpr (
Dim == 1) {
720 else if constexpr (
Dim == 2) {
722 m_dx = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}};
724 else if constexpr (
Dim == 3) {
725 m_dx = {{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}, {0, 0, 1}, {0, 1, 0}, {1, 0, 0}};
728 throw std::runtime_error(
"Please specify the kernel in dimensions > 3.");
737 template <
class T,
class K>
740 m_dx = detail::kernel_to_dx<Dim>(kernel);
746 void init(
const T&
shape)
748 m_label = xt::empty<ptrdiff_t>(
shape);
749 m_renum.resize(m_label.size() + 1);
750 m_next.resize(m_label.size() + 1);
751 for (
size_t i = 0; i <
Dim; ++i) {
752 m_shape[i] =
static_cast<ptrdiff_t
>(
shape[i]);
753 if constexpr (
Dim >= 2) {
754 m_strides[i] =
static_cast<ptrdiff_t
>(m_label.strides()[i]);
758 m_connected.resize(m_dx.shape(0));
762 if constexpr (
Dim == 2) {
763 if (m_shape[0] == 1) {
764 get_compare = &ClusterLabeller<Dimension, Periodicity>::get_compare_2d_1n;
766 else if (m_shape[1] == 1) {
767 get_compare = &ClusterLabeller<Dimension, Periodicity>::get_compare_2d_n1;
778 std::fill(m_label.begin(), m_label.end(), 0);
779 std::iota(m_renum.begin(), m_renum.end(), 0);
790 ptrdiff_t n =
static_cast<ptrdiff_t
>(m_new_label);
793 for (ptrdiff_t i = 1; i < n; ++i) {
794 if (m_renum[i] == i) {
795 m_renum[i] = m_new_label;
799 this->private_renumber(m_renum);
800 std::iota(m_renum.begin(), m_renum.begin() + n, 0);
809 std::fill(m_next.begin(), m_next.end(), -1);
817 void private_renumber(
const T& renum)
819 for (
size_t i = 0; i < m_label.size(); ++i) {
820 m_label.flat(i) = renum[m_label.flat(i)];
832 void merge_detail(ptrdiff_t a, ptrdiff_t b)
835 ptrdiff_t i = m_renum[b];
836 ptrdiff_t target = m_renum[a];
846 while (m_next[a] != -1) {
858 size_t unique(ptrdiff_t*
labels,
size_t nlabels)
871 ptrdiff_t merge(ptrdiff_t*
labels,
size_t nlabels)
873 ptrdiff_t target =
labels[0];
874 for (
size_t i = 1; i < nlabels; ++i) {
875 this->merge_detail(target,
labels[i]);
886 this->private_renumber(m_renum);
895 ptrdiff_t get_compare_2d_1n(
size_t idx,
size_t j)
898 return (m_shape[1] + idx + m_dx(j, 1)) % m_shape[1];
901 ptrdiff_t compare = idx + m_dx(j, 1);
902 if (compare < 0 || compare >= m_shape[1]) {
913 ptrdiff_t get_compare_2d_n1(
size_t idx,
size_t j)
916 return (m_shape[0] + idx + m_dx(j, 0)) % m_shape[0];
919 ptrdiff_t compare = idx + m_dx(j, 0);
920 if (compare < 0 || compare >= m_shape[0]) {
935 ptrdiff_t get_compare_default(
size_t idx,
size_t j)
938 return (m_shape[0] + idx + m_dx.flat(j)) % m_shape[0];
941 ptrdiff_t compare = idx + m_dx.flat(j);
942 if (compare < 0 || compare >= m_shape[0]) {
945 return idx + m_dx.flat(j);
948 ptrdiff_t ii = (m_shape[0] + (idx / m_strides[0]) + m_dx(j, 0)) % m_shape[0];
949 ptrdiff_t jj = (m_shape[1] + (idx % m_strides[0]) + m_dx(j, 1)) % m_shape[1];
950 return ii * m_shape[1] + jj;
953 ptrdiff_t ii = (idx / m_strides[0]) + m_dx(j, 0);
954 ptrdiff_t jj = (idx % m_strides[0]) + m_dx(j, 1);
955 if (ii < 0 || ii >= m_shape[0] || jj < 0 || jj >= m_shape[1]) {
958 return ii * m_shape[1] + jj;
961 auto index = xt::unravel_from_strides(idx, m_strides, xt::layout_type::row_major);
962 for (
size_t d = 0; d <
Dim; ++d) {
963 index[d] += m_dx(j, d);
965 if (index[d] < 0 || index[d] >= m_shape[d]) {
971 index[d] = (n + (index[d] % n)) % n;
974 return xt::ravel_index(index, m_shape, xt::layout_type::row_major);
978 void label_impl(
size_t idx)
980 size_t nconnected = 0;
982 for (
size_t j = 0; j < m_dx.shape(0); ++j) {
983 ptrdiff_t compare = (this->*get_compare)(idx, j);
989 if (m_label.flat(compare) != 0) {
990 m_connected[nconnected] = m_renum[m_label.flat(compare)];
995 if (nconnected == 0) {
996 m_label.flat(idx) = m_new_label;
1001 if (nconnected == 1) {
1002 m_label.flat(idx) = m_connected[0];
1006 nconnected = this->unique(&m_connected[0], nconnected);
1007 if (nconnected == 1) {
1008 m_label.flat(idx) = m_connected[0];
1015 m_label.flat(idx) = this->merge(&m_connected[0], nconnected);
1027 GOOSEEYE_ASSERT(xt::has_shape(img, m_label.shape()), std::out_of_range);
1029 for (
size_t idx = 0; idx < img.size(); ++idx) {
1030 if (img.flat(idx) == 0) {
1033 if (m_label.flat(idx) != 0) {
1036 this->label_impl(idx);
1038 this->apply_merge();
1043 bool legal_points(
const T& begin,
const T& end)
1045 size_t n = m_label.size();
1046 if constexpr (std::is_signed_v<typename T::value_type>) {
1047 return !std::any_of(begin, end, [n](
size_t i) {
return i < 0 || i >= n; });
1050 return !std::any_of(begin, end, [n](
size_t i) {
return i >= n; });
1064 for (
auto it = begin; it != end; ++it) {
1065 if (m_label.flat(*it) != 0) {
1068 this->label_impl(*it);
1070 this->apply_merge();
1081 return this->
add_points(idx.begin(), idx.end());
1097 GOOSEEYE_ASSERT(this->legal_points(idx.begin(), idx.end()), std::out_of_range);
1098 std::vector<size_t> ret;
1101 auto nl = m_new_label;
1103 auto lab = m_label.flat(idx(i));
1105 for (; i < idx.size(); ++i) {
1106 auto l = m_label.flat(idx(i));
1107 if (l != lab && l != 0) {
1114 this->label_impl(idx(i));
1115 if (m_new_label != nl || m_nmerge != nm) {
1121 if (i == idx.size()) {
1126 this->apply_merge();
1127 ret.push_back(idx.size());
1137 return detail::get_namespace() +
"ClusterLabeller" + std::to_string(
Dim) +
" " +
1138 detail::shape_to_string(m_shape);
1147 return m_label.shape();
1156 return m_label.size();
1173template <
size_t Dimension,
bool Periodicity>
1174class ClusterLabellerOverload :
public ClusterLabeller<Dimension, Periodicity> {
1200 GOOSEEYE_ASSERT(f.layout() == xt::layout_type::row_major, std::runtime_error);
1202 auto n = f.dimension();
1203 if (n == 1 && periodic) {
1204 return detail::ClusterLabellerOverload<1, true>(f).get();
1206 if (n == 1 && !periodic) {
1207 return detail::ClusterLabellerOverload<1, false>(f).get();
1209 if (n == 2 && periodic) {
1210 return detail::ClusterLabellerOverload<2, true>(f).get();
1212 if (n == 2 && !periodic) {
1213 return detail::ClusterLabellerOverload<2, false>(f).get();
1215 if (n == 3 && periodic) {
1216 return detail::ClusterLabellerOverload<3, true>(f).get();
1218 if (n == 3 && !periodic) {
1219 return detail::ClusterLabellerOverload<3, false>(f).get();
1221 throw std::runtime_error(
"Please use ClusterLabeller directly for dimensions > 3.");
1249 bool periodic =
true)
1251 if (positions.size() == 0) {
1252 return xt::zeros<double>({shape.size()});
1256 return xt::mean(positions, 0);
1259 double pi = xt::numeric_constants<double>::PI;
1260 auto theta = 2.0 * pi * positions / shape;
1261 auto xi = xt::cos(theta);
1262 auto zeta = xt::sin(theta);
1263 auto xi_bar = xt::mean(xi, 0);
1264 auto zeta_bar = xt::mean(zeta, 0);
1265 auto theta_bar = xt::atan2(-zeta_bar, -xi_bar) + pi;
1266 return shape * theta_bar / (2.0 * pi);
1278 bool periodic =
true)
1280 if (positions.size() == 0) {
1281 return xt::zeros<double>({shape.size()});
1285 return xt::average(positions, weights, 0);
1288 double pi = xt::numeric_constants<double>::PI;
1289 auto theta = 2.0 * pi * positions / shape;
1290 auto xi = xt::cos(theta);
1291 auto zeta = xt::sin(theta);
1292 auto xi_bar = xt::average(xi, weights, 0);
1293 auto zeta_bar = xt::average(zeta, weights, 0);
1294 auto theta_bar = xt::atan2(-zeta_bar, -xi_bar) + pi;
1295 return shape * theta_bar / (2.0 * pi);
1306 PositionList() =
default;
1309 void set(
const T& condition)
1311 positions = xt::from_indices(xt::argwhere(condition));
1314 template <
class T,
class W>
1315 void set(
const T& condition,
const W& w)
1317 auto pos = xt::argwhere(condition);
1318 weights = xt::empty<double>({pos.size()});
1319 for (
size_t i = 0; i < pos.size(); ++i) {
1320 weights(i) = w[pos[i]];
1322 positions = xt::from_indices(pos);
1338template <
class T,
class N>
1342 static_assert(std::is_integral<typename T::value_type>::value,
"Integral labels required.");
1346 size_t rank = labels.dimension();
1349 detail::PositionList plist;
1351 for (
size_t l = 0; l < names.size(); ++l) {
1352 plist.set(xt::equal(labels, names(l)));
1353 if (plist.positions.size() == 0) {
1356 xt::view(ret, l, xt::all()) =
center(shape, plist.positions, periodic);
1366template <
class T,
class W,
class N>
1370 static_assert(std::is_integral<typename T::value_type>::value,
"Integral labels required.");
1371 GOOSEEYE_ASSERT(xt::has_shape(labels, weights.shape()), std::out_of_range);
1375 size_t rank = labels.dimension();
1378 detail::PositionList plist;
1380 for (
size_t l = 0; l < names.size(); ++l) {
1381 plist.set(xt::equal(labels, names(l)), weights);
1382 if (plist.positions.size() == 0) {
1385 xt::view(ret, l, xt::all()) =
1415 Ensemble(
const std::vector<size_t>& roi,
bool periodic =
true,
bool variance =
true);
1484 void mean(
const T& f);
1491 template <
class T,
class M>
1492 void mean(
const T& f,
const M& fmask);
1500 void S2(
const T& f,
const T& g);
1509 template <
class T,
class M>
1510 void S2(
const T& f,
const T& g,
const M& fmask,
const M& gmask);
1518 void C2(
const T& f,
const T& g);
1527 template <
class T,
class M>
1528 void C2(
const T& f,
const T& g,
const M& fmask,
const M& gmask);
1536 void W2(
const T& w,
const T& f);
1544 template <
class T,
class M>
1545 void W2(
const T& w,
const T& f,
const M& fmask);
1554 template <
class C,
class T>
1566 template <
class C,
class T,
class M>
1588 template <
class T,
class M>
1604 Type m_stat = Type::Unset;
1607 static const size_t MAX_DIM = 3;
1624 std::vector<size_t> m_shape_orig;
1627 std::vector<size_t> m_shape;
1630 std::vector<std::vector<size_t>> m_pad;
1642inline auto distance(
const std::vector<size_t>& roi);
1650inline auto distance(
const std::vector<size_t>& roi,
size_t axis);
1658inline auto distance(
const std::vector<size_t>& roi,
const std::vector<double>& h);
1667inline auto distance(
const std::vector<size_t>& roi,
const std::vector<double>& h,
size_t axis);
1677inline auto S2(
const std::vector<size_t>& roi,
const T& f,
const T& g,
bool periodic =
true);
1688template <
class T,
class M>
1690S2(
const std::vector<size_t>& roi,
1695 bool periodic =
true);
1705inline auto C2(
const std::vector<size_t>& roi,
const T& f,
const T& g,
bool periodic =
true);
1716template <
class T,
class M>
1718C2(
const std::vector<size_t>& roi,
1723 bool periodic =
true);
1733inline auto W2(
const std::vector<size_t>& roi,
const T& w,
const T& f,
bool periodic =
true);
1743template <
class T,
class M>
1745W2(
const std::vector<size_t>& roi,
const T& w,
const T& f,
const M& fmask,
bool periodic =
true);
1756template <
class C,
class T>
1758W2c(
const std::vector<size_t>& roi,
1763 bool periodic =
true);
1775template <
class C,
class T,
class M>
1777W2c(
const std::vector<size_t>& roi,
1783 bool periodic =
true);
1792inline auto heightheight(
const std::vector<size_t>& roi,
const T& f,
bool periodic =
true);
1801template <
class T,
class M>
1803heightheight(
const std::vector<size_t>& roi,
const T& f,
const M& fmask,
bool periodic =
true);
1814L(
const std::vector<size_t>& roi,
1816 bool periodic =
true,
(Incrementally) Label clusters (0 as background, 1..n as labels).
void prune()
Prune: renumber labels to lowest possible label, see also AvalancheSegmenter::nlabels.
void add_image(const T &img)
Add image.
auto size() const
Size of ClusterLabeller::s and ClusterLabeller::labels (== prod(shape)).
ClusterLabeller(const T &shape)
ClusterLabeller(const T &shape, const K &kernel)
std::string repr() const
Basic class info.
const auto & shape() const
Shape of ClusterLabeller::s and ClusterLabeller::labels.
static constexpr bool Periodic
Periodicity of the system.
void add_points(const T &begin, const T &end)
Add sequence of points.
const auto & labels() const
Per block, the label (0 for background).
std::vector< size_t > add_sequence(const T &idx)
Add a sequence of points.
void add_points(const T &idx)
Add sequence of points.
void reset()
Reset labels to zero.
static constexpr size_t Dim
Dimensionality of the system.
Compute ensemble averaged statistics, by repetitively calling the member-function of a certain statis...
void mean(const T &f)
Add realization to arithmetic mean.
void L(const T &f, path_mode mode=path_mode::Bresenham)
Add realization to lineal-path function.
void S2(const T &f, const T &g)
Add realization to 2-point correlation: P(f(i) * g(i + di)).
array_type::array< double > data_second() const
Get raw-data: ensemble sum of the second moment: x_1^2 + x_2^2 + ...
Ensemble()=default
Constructor.
array_type::array< double > variance() const
Get ensemble variance.
void heightheight(const T &f)
Add realization to height-height correlation.
void W2c(const C &clusters, const C ¢ers, const T &f, path_mode mode=path_mode::Bresenham)
Add realization to collapsed weighted 2-point correlation.
array_type::array< double > data_first() const
Get raw-data: ensemble sum of the first moment: x_1 + x_2 + ...
void W2(const T &w, const T &f)
Add realization to weighted 2-point correlation.
array_type::array< double > distance() const
Get the relative distance of each pixel in the 'region-of-interest' to its center.
array_type::array< double > result() const
Get ensemble average.
array_type::array< double > norm() const
Get raw-data: normalisation (number of measurements per pixel).
void C2(const T &f, const T &g)
Add realization to 2-point cluster function: P(f(i) == g(i + di)).
#define GOOSEEYE_ASSERT(expr, assertion)
All assertions are implemented as:
xt::xtensor< T, N > tensor
Fixed (static) rank array.
array_type::array< int > nearest(size_t ndim)
Return kernel with nearest neighbours.
Toolbox to compute statistics.
path_mode
Different methods to compute a pixel-path.
@ Bresenham
Bresenham algorithm.
@ full
Similar to actual selecting every voxel that is crossed.
array_type::tensor< double, 2 > labels_centers_of_mass(const T &labels, const W &weights, const N &names, bool periodic=true)
Get the position of the center of each label.
array_type::tensor< double, 1 > center_of_mass(const array_type::tensor< double, 1 > &shape, const array_type::tensor< double, 2 > &positions, const array_type::tensor< double, 1 > &weights, bool periodic=true)
Return the geometric center of a list of positions.
array_type::tensor< double, 1 > center(const array_type::tensor< double, 1 > &shape, const array_type::tensor< double, 2 > &positions, bool periodic=true)
Return the geometric center of a list of positions.
auto L(const std::vector< size_t > &roi, const T &f, bool periodic=true, path_mode mode=path_mode::Bresenham)
Lineal-path function.
T dilate(const T &f, const S &kernel, const array_type::tensor< size_t, 1 > &iterations, bool periodic=true)
Dilate image.
T labels_prune(const T &labels)
Prune labels: renumber labels to lowest possible label starting from 1.
auto W2c(const std::vector< size_t > &roi, const C &clusters, const C ¢ers, const T &f, path_mode mode=path_mode::Bresenham, bool periodic=true)
Collapsed weighted 2-point correlation.
array_type::tensor< typename T::value_type, 2 > labels_sizes(const T &labels)
Size per label.
array_type::tensor< typename T::value_type, 2 > labels_map(const T &a, const T &b)
Get a map to relabel from a to b.
auto C2(const std::vector< size_t > &roi, const T &f, const T &g, bool periodic=true)
2-point cluster function: P(f(i) == g(i + di)).
array_type::array< int > clusters(const T &f, bool periodic=true)
Compute clusters.
array_type::tensor< double, 2 > labels_centers(const T &labels, const N &names, bool periodic=true)
Get the position of the center of each label.
L labels_rename(const L &labels, const A &rename)
Rename labels.
auto W2(const std::vector< size_t > &roi, const T &w, const T &f, bool periodic=true)
Weighted 2-point correlation.
array_type::array< int > dummy_circles(const std::vector< size_t > &shape, const array_type::tensor< int, 1 > &row, const array_type::tensor< int, 1 > &col, const array_type::tensor< int, 1 > &r, bool periodic=true)
Dummy image with circles.
array_type::tensor< int, 2 > path(const array_type::tensor< int, 1 > &x0, const array_type::tensor< int, 1 > &x1, path_mode mode=path_mode::Bresenham)
Compute a path between two pixels.
auto distance(const std::vector< size_t > &roi)
Get the relative distance of each pixel in the 'region-of-interest' to its center.
auto S2(const std::vector< size_t > &roi, const T &f, const T &g, bool periodic=true)
2-point correlation: P(f(i) * g(i + di)).
auto heightheight(const std::vector< size_t > &roi, const T &f, bool periodic=true)
Height-height correlation.
L labels_reorder(const L &labels, const A &order)
Reorder labels.