+
+
+
+
+
+
+
+
+
+
+
+
+
22inline std::string get_namespace()
+
+
24 std::string ret =
"GooseEYE";
+
25#ifdef GOOSEEYE_USE_XTENSOR_PYTHON
+
+
+
+
+
+
+
+
37inline std::string shape_to_string(
const T& shape)
+
+
39 std::string ret =
"[";
+
40 for (
size_t i = 0; i < shape.size(); ++i) {
+
41 ret += std::to_string(shape[i]);
+
42 if (i < shape.size() - 1) {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
97 const std::vector<size_t>& shape,
+
+
+
+
101 bool periodic =
true)
+
+
+
+
+
+
+
+
+
110 for (
size_t i = 0; i < row.size(); ++i) {
+
111 for (
int di = -r(i); di <= r(i); ++di) {
+
112 for (
int dj = -r(i); dj <= r(i); ++dj) {
+
113 int dr = (int)(ceil(pow((
double)(pow(di, 2) + pow(dj, 2)), 0.5)));
+
+
115 out.periodic(row(i) + di, col(i) + dj) = 1;
+
+
+
+
+
+
+
+
+
124 for (
size_t i = 0; i < row.size(); ++i) {
+
125 for (
int di = -r(i); di <= r(i); ++di) {
+
126 for (
int dj = -r(i); dj <= r(i); ++dj) {
+
127 if (out.in_bounds(row(i) + di, col(i) + dj)) {
+
128 int dr = (int)(ceil(pow((
double)(pow(di, 2) + pow(dj, 2)), 0.5)));
+
+
130 out(row(i) + di, col(i) + dj) = 1;
+
+
+
+
+
+
+
+
+
+
+
+
+
148dummy_circles(
const std::vector<size_t>& shape,
bool periodic =
true, uint64_t seed = 0)
+
+
+
151 prrng::pcg32 rng(seed);
+
+
+
154 size_t N = (size_t)(0.05 * (
double)shape[0]);
+
155 size_t M = (size_t)(0.05 * (
double)shape[1]);
+
156 size_t R = (size_t)(pow((0.3 * (
double)(shape[0] * shape[1])) / (M_PI * (double)(N * M)), 0.5));
+
+
+
+
+
+
+
163 for (
size_t i = 0; i < N; i++) {
+
164 for (
size_t j = 0; j < M; j++) {
+
165 row[i * M + j] = (int)((
double)i * (double)shape[0] / (
double)N);
+
166 col[i * M + j] = (int)((
double)j * (double)shape[1] / (
double)M);
+
167 r[i * M + j] = (int)R;
+
+
+
+
+
172 int dN = (int)(0.5 * (
double)shape[0] / (double)N);
+
173 int dM = (int)(0.5 * (
double)shape[1] / (double)M);
+
+
+
176 for (
size_t i = 0; i < N * M; i++) {
+
177 row(i) += rng.randint(2 * dN) - dN;
+
178 col(i) += rng.randint(2 * dM) - dM;
+
179 r(i) = (double)r(i) * 2.0 * rng.random();
+
+
+
+
+
+
+
+
+
+
+
+
199 std::is_integral<typename T::value_type>::value &&
+
200 std::is_integral<typename S::value_type>::value,
+
+
+
+
+
+
206 bool periodic =
true);
+
+
212template <class T, std::enable_if_t<std::is_integral<typename T::value_type>::value,
int> = 0>
+
+
+
+
+
+
+
223 std::is_integral<typename T::value_type>::value &&
+
224 std::is_integral<typename S::value_type>::value,
+
+
226inline T
dilate(
const T& f,
const S& kernel,
size_t iterations = 1,
bool periodic =
true);
+
+
232template <class T, std::enable_if_t<std::is_integral<typename T::value_type>::value,
int> = 0>
+
233inline T
dilate(
const T& f,
size_t iterations = 1,
bool periodic =
true);
+
+
241template <
class T,
class S>
+
+
+
+
+
+
+
+
+
249 for (
size_t i = 0; i < a.size(); ++i) {
+
250 ret(a.flat(i)) = b.flat(i);
+
+
+
+
+
+
+
+
+
+
+
265 using value_type =
typename T::value_type;
+
266 std::map<value_type, value_type> map;
+
+
268 for (
size_t i = 0; i < a.size(); ++i) {
+
269 map.try_emplace(a.flat(i), b.flat(i));
+
+
+
+
+
274 xt::empty<typename T::value_type>(std::array<size_t, 2>{map.size(), 2});
+
+
276 for (
auto const& [key, val] : map) {
+
+
+
+
+
+
+
+
+
+
291template <
class L,
class A>
+
+
+
+
+
+
296 using value_type =
typename A::value_type;
+
297 std::map<value_type, value_type> map;
+
298 for (
size_t i = 0; i < rename.shape(0); ++i) {
+
299 map.emplace(rename(i, 0), rename(i, 1));
+
+
+
302#ifdef GOOSEEYE_ENABLE_ASSERT
+
303 auto l = xt::unique(labels);
+
304 for (
size_t i = 0; i < l.size(); ++i) {
+
+
+
+
+
309 L ret = xt::empty_like(labels);
+
310 for (
size_t i = 0; i < labels.size(); ++i) {
+
311 ret.flat(i) = map[labels.flat(i)];
+
+
+
+
+
+
+
323template <
class L,
class A>
+
+
+
+
326#ifdef GOOSEEYE_ENABLE_ASSERT
+
327 auto a = xt::unique(labels);
+
328 auto b = xt::unique(order);
+
+
+
+
+
333 auto maxlab = *std::max_element(order.begin(), order.end());
+
334 std::vector<typename A::value_type> renum(maxlab + 1);
+
+
336 for (
size_t i = 0; i < order.size(); ++i) {
+
+
+
+
340 L ret = xt::empty_like(labels);
+
341 for (
size_t i = 0; i < labels.size(); ++i) {
+
342 ret.flat(i) = renum[labels.flat(i)];
+
+
+
+
+
+
+
+
+
+
+
356 using value_type =
typename T::value_type;
+
357 std::map<value_type, value_type> map;
+
+
359 for (
size_t i = 0; i < labels.size(); ++i) {
+
360 if (map.count(labels.flat(i)) == 0) {
+
361 map.emplace(labels.flat(i), 1);
+
+
+
364 map[labels.flat(i)]++;
+
+
+
+
+
+
370 xt::empty<value_type>(std::array<size_t, 2>{map.size(), 2});
+
+
372 for (
auto const& [key, val] : map) {
+
+
+
+
+
+
+
+
+
+
+
+
389inline void unravel_index(
+
+
391 const std::array<ptrdiff_t, 2>& strides,
+
392 std::array<ptrdiff_t, 2>& indices)
+
+
394 indices[0] = idx / strides[0];
+
395 indices[1] = idx % strides[0];
+
+
+
403template <
size_t Dim,
class T>
+
+
+
406#ifdef GOOSEEYE_ENABLE_ASSERT
+
407 for (
size_t i = 0; i < Dim; ++i) {
+
+
+
+
+
412 std::array<size_t, Dim> mid;
+
413 for (
size_t i = 0; i < Dim; ++i) {
+
414 mid[i] = (kernel.shape(i) - 1) / 2;
+
+
+
417 for (
size_t i = 0; i < Dim; ++i) {
+
418 idx += mid[i] * kernel.strides()[i];
+
+
+
421 kernel.flat(idx) = 0;
+
+
423 if constexpr (Dim == 1) {
+
424 return xt::flatten_indices(xt::argwhere(kernel)) - mid[0];
+
+
+
427 auto ret = xt::from_indices(xt::argwhere(kernel));
+
428 for (
size_t i = 0; i < Dim; ++i) {
+
429 xt::view(ret, xt::all(), i) -= mid[i];
+
+
+
+
+
+
+
441template <
size_t Dimension,
bool Periodicity = true>
+
+
+
+
444 static constexpr size_t Dim = Dimension;
+
+
+
+
448 std::array<size_t, Dim> m_shape;
+
+
+
451 ptrdiff_t m_new_label = 1;
+
+
453 std::array<ptrdiff_t, Dim> m_index;
+
454 std::array<ptrdiff_t, Dim> m_strides;
+
+
462 std::vector<ptrdiff_t> m_renum;
+
+
474 std::vector<ptrdiff_t> m_next;
+
475 std::vector<ptrdiff_t> m_connected;
+
+
+
+
+
+
+
484 if constexpr (
Dim == 1) {
+
+
+
+
488 else if constexpr (
Dim == 2) {
+
+
490 m_dx = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}};
+
+
+
+
+
+
499 template <
class T,
class K>
+
+
+
+
502 m_dx = detail::kernel_to_dx<Dim>(kernel);
+
+
+
+
+
+
+
508 void init(
const T&
shape)
+
+
510 static_assert(
Dim == 1 ||
Dim == 2,
"WIP: 1d and 2d supported.");
+
511 m_label = xt::empty<ptrdiff_t>(
shape);
+
512 m_renum.resize(m_label.size() + 1);
+
513 m_next.resize(m_label.size() + 1);
+
514 for (
size_t i = 0; i <
Dim; ++i) {
+
515 m_shape[i] =
static_cast<ptrdiff_t
>(
shape[i]);
+
516 m_strides[i] =
static_cast<ptrdiff_t
>(m_label.strides()[i]);
+
+
+
+
520 m_connected.resize(m_dx.shape(0));
+
+
+
+
+
+
+
529 std::fill(m_label.begin(), m_label.end(), 0);
+
530 std::iota(m_renum.begin(), m_renum.end(), 0);
+
+
+
+
+
+
+
+
+
541 ptrdiff_t n =
static_cast<ptrdiff_t
>(m_new_label);
+
+
+
544 for (ptrdiff_t i = 1; i < n; ++i) {
+
545 if (m_renum[i] == i) {
+
546 m_renum[i] = m_new_label;
+
+
+
+
550 this->private_renumber(m_renum);
+
551 std::iota(m_renum.begin(), m_renum.begin() + n, 0);
+
+
+
+
+
+
+
560 std::fill(m_next.begin(), m_next.end(), -1);
+
+
+
+
568 void private_renumber(
const T& renum)
+
+
570 for (
size_t i = 0; i < m_label.size(); ++i) {
+
571 m_label.flat(i) = renum[m_label.flat(i)];
+
+
+
+
583 void merge_detail(ptrdiff_t a, ptrdiff_t b)
+
+
+
586 ptrdiff_t i = m_renum[b];
+
587 ptrdiff_t target = m_renum[a];
+
+
+
+
+
+
+
+
+
+
597 while (m_next[a] != -1) {
+
+
+
+
+
+
610 ptrdiff_t merge(ptrdiff_t*
labels,
size_t nlabels)
+
+
+
+
614 ptrdiff_t target =
labels[0];
+
615 for (
size_t i = 1; i < nlabels; ++i) {
+
616 this->merge_detail(target,
labels[i]);
+
+
+
+
+
+
+
+
+
+
+
627 this->private_renumber(m_renum);
+
+
+
+
+
632 void label_impl(
size_t idx)
+
+
634 static_assert(
Dim == 1 ||
Dim == 2,
"WIP: 1d and 2d supported.");
+
+
+
637 size_t nconnected = 0;
+
+
639 for (
size_t j = 0; j < m_dx.shape(0); ++j) {
+
+
641 ptrdiff_t nn = m_shape[0];
+
642 ptrdiff_t ii = (nn + idx + m_dx(j)) % nn;
+
+
+
+
646 ptrdiff_t nn = m_shape[0];
+
647 ptrdiff_t ii = idx + m_dx(j);
+
648 if (ii < 0 || ii >= nn) {
+
+
+
+
+
+
654 detail::unravel_index(idx, m_strides, m_index);
+
655 ptrdiff_t nn = m_shape[0];
+
656 ptrdiff_t mm = m_shape[1];
+
657 ptrdiff_t ii = (nn + m_index[0] + m_dx(j, 0)) % nn;
+
658 ptrdiff_t jj = (mm + m_index[1] + m_dx(j, 1)) % mm;
+
659 compare = ii * mm + jj;
+
+
+
662 detail::unravel_index(idx, m_strides, m_index);
+
663 ptrdiff_t nn = m_shape[0];
+
664 ptrdiff_t mm = m_shape[1];
+
665 ptrdiff_t ii = m_index[0] + m_dx(j, 0);
+
666 ptrdiff_t jj = m_index[1] + m_dx(j, 1);
+
667 if (ii < 0 || ii >= nn || jj < 0 || jj >= mm) {
+
+
+
670 compare = ii * mm + jj;
+
+
+
673 if (m_label.flat(compare) != 0) {
+
674 m_connected[nconnected] = m_renum[m_label.flat(compare)];
+
+
+
+
+
679 if (nconnected == 0) {
+
680 m_label.flat(idx) = m_new_label;
+
+
+
+
+
685 if (nconnected == 1) {
+
686 m_label.flat(idx) = m_connected[0];
+
+
+
+
+
+
+
693 m_label.flat(idx) = this->merge(&m_connected[0], nconnected);
+
+
+
+
+
698 if (m_nmerge > 100) {
+
+
+
+
+
+
+
+
+
+
711 GOOSEEYE_ASSERT(xt::has_shape(img, m_label.shape()), std::out_of_range);
+
+
713 for (
size_t idx = 0; idx < img.size(); ++idx) {
+
714 if (img.flat(idx) == 0) {
+
+
+
717 if (m_label.flat(idx) != 0) {
+
+
+
720 this->label_impl(idx);
+
+
+
+
+
+
+
+
+
+
733#ifdef GOOSEEYE_ENABLE_ASSERT
+
734 size_t n = m_label.size();
+
+
736 !std::any_of(begin, end, [n](
size_t i) {
return i < 0 || i >= n; }), std::out_of_range);
+
+
+
739 for (
auto it = begin; it != end; ++it) {
+
740 if (m_label.flat(*it) != 0) {
+
+
+
743 this->label_impl(*it);
+
+
+
+
+
+
+
+
+
+
+
756 return this->
add_points(idx.begin(), idx.end());
+
+
+
+
+
+
+
765 return detail::get_namespace() +
"ClusterLabeller" + std::to_string(
Dim) +
" " +
+
766 detail::shape_to_string(m_shape);
+
+
+
+
+
+
+
775 return m_label.shape();
+
+
+
+
+
+
+
784 return m_label.size();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
814 :
Clusters(f, kernel::nearest(f.dimension()), periodic)
+
+
+
+
+
825 template <
class T,
class S>
+
+
826 Clusters(
const T& f,
const S& kernel,
bool periodic =
true) : m_periodic(periodic)
+
+
+
829 "(please open a PR for missing functions)");
+
+
831 static_assert(std::is_integral<typename T::value_type>::value,
"Integral labels required.");
+
832 static_assert(std::is_integral<typename S::value_type>::value,
"Integral kernel required.");
+
+
834 GOOSEEYE_ASSERT(xt::all(xt::equal(f, 0) || xt::equal(f, 1)), std::out_of_range);
+
835 GOOSEEYE_ASSERT(xt::all(xt::equal(kernel, 0) || xt::equal(kernel, 1)), std::out_of_range);
+
836 GOOSEEYE_ASSERT(f.dimension() == kernel.dimension(), std::out_of_range);
+
+
838 m_shape = detail::shape(f);
+
839 m_kernel = xt::atleast_3d(kernel);
+
840 m_pad = detail::pad_width(m_kernel);
+
841 m_l = xt::atleast_3d(f);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
856 xt::view(renum, xt::keep(labels)) = xt::arange<int>(
static_cast<int>(labels.size()));
+
857 for (
auto& i : m_l) {
+
+
+
+
+
+
+
+
+
868 return xt::adapt(m_l.data(), m_shape);
+
+
+
+
+
+
+
+
+
+
880 for (
int l = 1; l < static_cast<int>(x.shape(0)); ++l) {
+
881 c(x(l, 0), x(l, 1), x(l, 2)) = l;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
897 x = this->average_position_periodic();
+
+
+
900 x = this->average_position(m_l);
+
+
+
+
+
+
+
+
908 return xt::view(x, xt::all(), xt::keep(axes));
+
+
+
+
+
+
+
+
+
+
920 for (
size_t h = 0; h < m_l.shape(0); ++h) {
+
921 for (
size_t i = 0; i < m_l.shape(1); ++i) {
+
922 for (
size_t j = 0; j < m_l.shape(2); ++j) {
+
+
+
+
+
+
+
+
+
+
+
+
+
934 xt::pad_mode pad_mode = xt::pad_mode::constant;
+
+
+
+
938 pad_mode = xt::pad_mode::periodic;
+
+
+
941 m_l = xt::pad(m_l, m_pad, pad_mode, pad_value);
+
+
+
+
+
+
+
+
+
950 array_type::tensor<int, 1> renum = xt::arange<int>(
static_cast<int>(m_l.size()));
+
+
952 for (
size_t h = m_pad[0][0]; h < m_l.shape(0) - m_pad[0][1]; ++h) {
+
953 for (
size_t i = m_pad[1][0]; i < m_l.shape(1) - m_pad[1][1]; ++i) {
+
954 for (
size_t j = m_pad[2][0]; j < m_l.shape(2) - m_pad[2][1]; ++j) {
+
+
+
+
+
+
+
+
962 xt::range(h - m_pad[0][0], h + m_pad[0][1] + 1),
+
963 xt::range(i - m_pad[1][0], i + m_pad[1][1] + 1),
+
964 xt::range(j - m_pad[2][0], j + m_pad[2][1] + 1));
+
+
966 auto Ni = Li * m_kernel;
+
+
968 int l = xt::amax(Ni)();
+
+
+
+
+
+
+
975 Li = xt::where(xt::equal(Ni, 1), l, Li);
+
+
977 if (xt::all(xt::equal(Li, l) || xt::equal(Li, 0) || xt::equal(Li, 1))) {
+
+
+
+
+
982 array_type::array<int> merge = xt::where(xt::less_equal(Li, 1), l, Li);
+
983 merge = xt::unique(merge);
+
+
985 int linkto = xt::amin(xt::view(renum, xt::keep(merge)))[0];
+
986 for (
auto& a : merge) {
+
987 renum = xt::where(xt::equal(renum, renum(a)), linkto, renum);
+
+
+
+
+
+
+
+
+
996 xt::range(m_pad[0][0], m_l.shape(0) - m_pad[0][1]),
+
997 xt::range(m_pad[1][0], m_l.shape(1) - m_pad[1][1]),
+
998 xt::range(m_pad[2][0], m_l.shape(2) - m_pad[2][1]));
+
+
+
1001 for (
auto& i : m_l) {
+
+
+
+
+
+
1007 array_type::tensor<double, 2> average_position(
const T& lab)
const
+
+
+
1010 size_t N = xt::amax(lab)() + 1;
+
+
+
1013 array_type::tensor<double, 2> x = xt::zeros<double>({N, size_t(3)});
+
1014 array_type::tensor<double, 1> n = xt::zeros<double>({N});
+
+
1016 for (
size_t h = 0; h < lab.shape(0); ++h) {
+
1017 for (
size_t i = 0; i < lab.shape(1); ++i) {
+
1018 for (
size_t j = 0; j < lab.shape(2); ++j) {
+
+
1020 int l = lab(h, i, j);
+
+
+
1023 x(l, 0) += (double)h;
+
1024 x(l, 1) += (double)i;
+
1025 x(l, 2) += (double)j;
+
+
+
+
+
+
+
+
1033 n = xt::where(xt::equal(n, 0), 1, n);
+
+
+
1036 for (
size_t i = 0; i < x.shape(1); ++i) {
+
1037 auto xi = xt::view(x, xt::all(), i);
+
+
+
+
+
+
+
1044 array_type::tensor<double, 2> average_position_periodic()
const
+
+
+
+
+
+
1050 auto x_np = this->average_position(m_l_np);
+
+
+
1053 auto mid = detail::half_shape(m_shape);
+
+
+
1056 array_type::tensor<double, 2> shift = xt::zeros<double>({x_np.shape(0),
size_t(3)});
+
+
+
1059 for (
size_t i = 0; i < shift.shape(0); ++i) {
+
1060 for (
size_t j = 0; j < shift.shape(1); ++j) {
+
1061 if (x_np(i, j) > mid[j]) {
+
1062 shift(i, j) = -(double)m_shape[j];
+
+
+
+
+
+
1068 size_t N = xt::amax(m_l)() + 1;
+
+
+
1071 array_type::tensor<double, 2> x = xt::zeros<double>({N, size_t(3)});
+
1072 array_type::tensor<double, 1> n = xt::zeros<double>({N});
+
+
1074 for (
size_t h = 0; h < m_l.shape(0); ++h) {
+
1075 for (
size_t i = 0; i < m_l.shape(1); ++i) {
+
1076 for (
size_t j = 0; j < m_l.shape(2); ++j) {
+
+
1078 int l = m_l_np(h, i, j);
+
+
+
1081 x(relabel(l), 0) += (double)h + shift(l, 0);
+
1082 x(relabel(l), 1) += (double)i + shift(l, 1);
+
1083 x(relabel(l), 2) += (double)j + shift(l, 2);
+
1084 n(relabel(l)) += 1.0;
+
+
+
+
+
+
+
1091 n = xt::where(xt::equal(n, 0), 1, n);
+
+
+
1094 for (
size_t i = 0; i < x.shape(1); ++i) {
+
1095 auto xi = xt::view(x, xt::all(), i);
+
+
1097 xi = xt::where(xi < 0, xi + m_shape[i], xi);
+
+
+
+
+
+
1103 static const size_t MAX_DIM = 3;
+
1104 std::vector<size_t> m_shape;
+
1105 std::vector<std::vector<size_t>> m_pad;
+
1106 array_type::tensor<int, 3> m_kernel;
+
+
1108 array_type::tensor<int, 3> m_l;
+
1109 array_type::tensor<int, 3> m_l_np;
+
+
+
+
+
+
1114template <
size_t Dimension,
bool Periodicity>
+
1115class ClusterLabellerOverload :
public ClusterLabeller<Dimension, Periodicity> {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
1141 auto n = f.dimension();
+
1142 if (n == 1 && periodic) {
+
1143 return detail::ClusterLabellerOverload<1, true>(f).get();
+
+
1145 if (n == 1 && !periodic) {
+
1146 return detail::ClusterLabellerOverload<1, false>(f).get();
+
+
1148 if (n == 2 && periodic) {
+
1149 return detail::ClusterLabellerOverload<2, true>(f).get();
+
+
1151 if (n == 2 && !periodic) {
+
1152 return detail::ClusterLabellerOverload<2, false>(f).get();
+
+
+
1155 GOOSEEYE_WARNING(
"WIP: updated 3d implementation needs to be completed. Please file a PR.");
+
+
+
+
+
1166template <
typename T,
typename U,
typename V>
+
+
1167inline T
pos2img(
const T& img,
const U& positions,
const V& labels)
+
+
+
+
1171 GOOSEEYE_ASSERT(img.dimension() == positions.shape(1), std::out_of_range);
+
1172 GOOSEEYE_ASSERT(positions.shape(0) == labels.size(), std::out_of_range);
+
+
+
1175 using value_type =
typename T::value_type;
+
+
+
1178 if (res.dimension() == 1) {
+
1179 xt::view(res, xt::keep(positions)) = labels;
+
+
1181 else if (res.dimension() == 2) {
+
1182 for (
size_t i = 0; i < positions.shape(0); ++i) {
+
1183 res(positions(i, 0), positions(i, 1)) =
static_cast<value_type
>(labels(i));
+
+
+
+
1187 for (
size_t i = 0; i < positions.shape(0); ++i) {
+
1188 res(positions(i, 0), positions(i, 1), positions(i, 2)) =
+
1189 static_cast<value_type
>(labels(i));
+
+
+
+
+
+
+
+
+
+
+
+
1210 static_assert(std::is_integral<typename T::value_type>::value,
"Integral labels required.");
+
+
+
+
+
1215 double pi = xt::numeric_constants<double>::PI;
+
1216 size_t N =
static_cast<size_t>(xt::amax(labels)(0)) + 1ul;
+
1217 size_t rank = labels.dimension();
+
1218 auto axes = detail::atleast_3d_axes(rank);
+
+
+
+
1222 for (
size_t l = 0; l < N; ++l) {
+
+
1224 xt::from_indices(xt::argwhere(xt::equal(labels, l)));
+
1225 if (positions.size() == 0) {
+
+
+
+
1229 xt::view(ret, l, xt::all()) = xt::mean(positions, 0);
+
+
+
1232 if (xt::all(xt::equal(positions, 0.0))) {
+
+
+
1235 auto theta = 2.0 * pi * positions / shape;
+
1236 auto xi = xt::cos(theta);
+
1237 auto zeta = xt::sin(theta);
+
1238 auto xi_bar = xt::mean(xi, 0);
+
1239 auto zeta_bar = xt::mean(zeta, 0);
+
1240 auto theta_bar = xt::atan2(-zeta_bar, -xi_bar) + pi;
+
1241 auto positions_bar = shape * theta_bar / (2.0 * pi);
+
1242 xt::view(ret, l, xt::all()) = positions_bar;
+
+
+
+
1246 return xt::view(ret, xt::all(), xt::keep(axes));
+
+
+
+
+
+
+
+
+
1272 Ensemble(
const std::vector<size_t>& roi,
bool periodic =
true,
bool variance =
true);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
1341 void mean(
const T& f);
+
+
1348 template <
class T,
class M>
+
1349 void mean(
const T& f,
const M& fmask);
+
+
+
1357 void S2(
const T& f,
const T& g);
+
+
1366 template <
class T,
class M>
+
1367 void S2(
const T& f,
const T& g,
const M& fmask,
const M& gmask);
+
+
+
1375 void C2(
const T& f,
const T& g);
+
+
1384 template <
class T,
class M>
+
1385 void C2(
const T& f,
const T& g,
const M& fmask,
const M& gmask);
+
+
+
1393 void W2(
const T& w,
const T& f);
+
+
1401 template <
class T,
class M>
+
1402 void W2(
const T& w,
const T& f,
const M& fmask);
+
+
1411 template <
class C,
class T>
+
+
+
+
1423 template <
class C,
class T,
class M>
+
+
+
+
+
+
+
+
+
+
+
1445 template <
class T,
class M>
+
+
+
+
+
+
+
+
+
+
+
1461 Type m_stat = Type::Unset;
+
+
+
1464 static const size_t MAX_DIM = 3;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
1481 std::vector<size_t> m_shape_orig;
+
+
+
1484 std::vector<size_t> m_shape;
+
+
+
1487 std::vector<std::vector<size_t>> m_pad;
+
+
+
+
+
+
+
+
1499inline auto distance(
const std::vector<size_t>& roi);
+
+
1507inline auto distance(
const std::vector<size_t>& roi,
size_t axis);
+
+
1515inline auto distance(
const std::vector<size_t>& roi,
const std::vector<double>& h);
+
+
1524inline auto distance(
const std::vector<size_t>& roi,
const std::vector<double>& h,
size_t axis);
+
+
+
1534inline auto S2(
const std::vector<size_t>& roi,
const T& f,
const T& g,
bool periodic =
true);
+
+
1545template <
class T,
class M>
+
+
1547S2(
const std::vector<size_t>& roi,
+
+
+
+
+
1552 bool periodic =
true);
+
+
+
1562inline auto C2(
const std::vector<size_t>& roi,
const T& f,
const T& g,
bool periodic =
true);
+
+
1573template <
class T,
class M>
+
+
1575C2(
const std::vector<size_t>& roi,
+
+
+
+
+
1580 bool periodic =
true);
+
+
+
1590inline auto W2(
const std::vector<size_t>& roi,
const T& w,
const T& f,
bool periodic =
true);
+
+
1600template <
class T,
class M>
+
+
1602W2(
const std::vector<size_t>& roi,
const T& w,
const T& f,
const M& fmask,
bool periodic =
true);
+
+
1613template <
class C,
class T>
+
+
1615W2c(
const std::vector<size_t>& roi,
+
+
+
+
+
1620 bool periodic =
true);
+
+
1632template <
class C,
class T,
class M>
+
+
1634W2c(
const std::vector<size_t>& roi,
+
+
+
+
+
+
1640 bool periodic =
true);
+
+
+
1649inline auto heightheight(
const std::vector<size_t>& roi,
const T& f,
bool periodic =
true);
+
+
1658template <
class T,
class M>
+
+
1660heightheight(
const std::vector<size_t>& roi,
const T& f,
const M& fmask,
bool periodic =
true);
+
+
+
+
1671L(
const std::vector<size_t>& roi,
+
+
1673 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).
+
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 clusters and obtain certain characteristic about them.
+
array_type::array< int > centers() const
Return label only in the center of gravity (1..n).
+
array_type::tensor< size_t, 1 > sizes() const
Return size per cluster.
+
Clusters(const T &f, const S &kernel, bool periodic=true)
Constructor.
+
Clusters(const T &f, bool periodic=true)
Constructor.
+
array_type::array< int > labels() const
Return labels (1..n).
+
array_type::tensor< double, 2 > center_positions(bool as3d=false) const
Return positions of the centers of gravity (in the original rank, or as 3-d).
+
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_WARNING(message)
Warnings are implemented as:
+
#define GOOSEEYE_ASSERT(expr, assertion)
All assertions are implemented as:
+
#define GOOSEEYE_WARNING_PYTHON(message)
Warnings specific to the Python API 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.
+
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)
Dilate image.
+
array_type::tensor< double, 2 > center_of_mass(const T &labels, bool periodic=true)
Get the position of the center of each label.
+
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.
+
L labels_rename(const L &labels, const A &rename)
Rename labels.
+
T pos2img(const T &img, const U &positions, const V &labels)
Convert positions to an image.
+
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.
+
array_type::tensor< size_t, 1 > relabel_map(const T &a, const S &b)
Find map to relabel from a to b.
+
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.
+
+