Commit e7e462e7 authored by Baptiste Esteban's avatar Baptiste Esteban
Browse files

Merge branch 'development/alphatree-tests' of...

Merge branch 'development/alphatree-tests' of https://gitlab.lrde.epita.fr/olena/pylene into development/alphatree
parents b8294c11 d182e920
......@@ -213,14 +213,18 @@ namespace mln::morpho
// Do we need to create a new node
int rp_root = links[rp];
int rq_root = links[rq];
int max_root = std::max(rp_root, rq_root);
int min_root = std::min(rp_root, rq_root);
int new_root_id;
if (levels[rq_root] == w)
if (levels[max_root] == w)
{
new_root_id = rq_root;
new_root_id = max_root;
}
else if (levels[rp_root] == w)
else if (levels[min_root] == w)
{
new_root_id = rp_root;
new_root_id = min_root;
}
else
{
......@@ -289,4 +293,4 @@ namespace mln::morpho
return {std::move(t), std::move(node_map)};
}
} // namespace mln::morpho
} // namespace mln::morpho
\ No newline at end of file
......@@ -14,8 +14,9 @@ namespace mln::morpho
* Implementation *
******************/
template <typename V, typename Nodemap, typename Th, typename L> requires(std::is_convertible_v<Th, V>)
auto horizontal_cut_labelization_from(const component_tree<V>& t, Nodemap nm, Th th, ::ranges::span<L> vals)
template <typename V, typename Nodemap, typename Th, typename L>
requires(std::is_convertible_v<Th, V>) auto horizontal_cut_labelization_from(const component_tree<V>& t, Nodemap nm,
Th th, ::ranges::span<L> vals)
{
static_assert(mln::is_a_v<Nodemap, mln::details::Image>);
static_assert(std::is_same_v<image_value_t<Nodemap>, int>);
......@@ -23,24 +24,28 @@ namespace mln::morpho
assert(static_cast<std::size_t>(vals.size()) == t.parent.size());
image_ch_value_t<Nodemap, ValueType> lbl = imchvalue<ValueType>(nm);
image_concrete_t<Nodemap> cut_nm = imconcretize(nm);
image_ch_value_t<Nodemap, ValueType> lbl = imchvalue<ValueType>(nm);
std::size_t n = t.parent.size();
mln_foreach (auto p, nm.domain())
// Root of cut connected component
std::vector<std::size_t> root_cut_cc(n);
for (std::size_t node = 0; node < n; ++node)
{
cut_nm(p) = nm(p);
while (t.parent[cut_nm(p)] != cut_nm(p) && t.values[t.parent[cut_nm(p)]] <= th)
cut_nm(p) = t.parent[cut_nm(p)];
std::size_t parent_node = t.parent[node];
root_cut_cc[node] = t.values[parent_node] > th ? node : root_cut_cc[parent_node];
}
mln_foreach (auto px, cut_nm.pixels())
lbl(px.point()) = vals[px.val()];
// Reconstruction of image
mln_foreach (auto px, nm.pixels())
lbl(px.point()) = vals[root_cut_cc[px.val()]];
return lbl;
}
template <typename V, typename Nodemap, typename Th, typename L> requires(std::is_convertible_v<Th, V>)
auto horizontal_cut_labelization_from(const component_tree<V>& t, Nodemap nm, Th th, const std::vector<L>& vals)
template <typename V, typename Nodemap, typename Th, typename L>
requires(std::is_convertible_v<Th, V>) auto horizontal_cut_labelization_from(const component_tree<V>& t, Nodemap nm,
Th th, const std::vector<L>& vals)
{
return horizontal_cut_labelization_from(t, nm, th, ::ranges::make_span(vals.data(), vals.size()));
}
......
#include <mln/core/colors.hpp>
#include <mln/core/image/ndimage.hpp>
#include <mln/core/neighborhood/c26.hpp>
#include <mln/core/neighborhood/c4.hpp>
#include <mln/core/neighborhood/c8.hpp>
#include <mln/morpho/alphatree.hpp>
#include <mln/morpho/cut.hpp>
......@@ -8,9 +10,8 @@
#include <gtest/gtest.h>
template <typename V>
mln::image2d<int> //
cut(const mln::morpho::component_tree<V>& t, mln::image2d<int>& node_map, int alpha)
template <typename V, typename I, typename T>
I cut(const mln::morpho::component_tree<V>& t, I& node_map, T alpha)
{
std::size_t n = t.parent.size();
......@@ -33,7 +34,7 @@ cut(const mln::morpho::component_tree<V>& t, mln::image2d<int>& node_map, int al
if (t.values[t.parent[i]] <= alpha) // progate to parent
labels[i] = labels[t.parent[i]];
mln::image2d<int> imlabel;
I imlabel;
imlabel.resize(node_map.domain());
mln_foreach (auto px, imlabel.pixels())
......@@ -52,9 +53,10 @@ TEST(Morpho, AlphaTree)
{107, 87, 118, 109, 167}, //
{107, 73, 125, 157, 117}, //
};
auto [t, node_map] = mln::morpho::alphatree(ima, mln::c4, [](const auto& a, const auto& b) -> std::uint8_t { return mln::functional::l2dist_t<>()(a, b);});
auto [t, node_map] = mln::morpho::alphatree(
ima, mln::c4, [](const auto& a, const auto& b) -> std::uint8_t { return mln::functional::l2dist_t<>()(a, b); });
mln::image2d<int> ref0 = {
mln::image2d<int> ref_0 = {
{0, 1, 2, 3, 4}, //
{5, 6, 7, 8, 9}, //
{10, 11, 12, 13, 14}, //
......@@ -62,7 +64,7 @@ TEST(Morpho, AlphaTree)
{15, 20, 21, 22, 23}, //
};
mln::image2d<int> ref1 = {
mln::image2d<int> ref_1 = {
{0, 1, 2, 3, 4}, //
{5, 6, 7, 8, 9}, //
{5, 11, 12, 13, 14}, //
......@@ -70,7 +72,7 @@ TEST(Morpho, AlphaTree)
{15, 20, 21, 22, 23}, //
};
mln::image2d<int> ref10 = {
mln::image2d<int> ref_10 = {
{0, 0, 2, 3, 4}, //
{5, 0, 2, 8, 9}, //
{5, 11, 12, 13, 14}, //
......@@ -79,7 +81,7 @@ TEST(Morpho, AlphaTree)
};
mln::image2d<int> ref11 = {
mln::image2d<int> ref_11 = {
{0, 0, 2, 3, 4}, //
{5, 0, 2, 8, 4}, //
{5, 11, 12, 13, 14}, //
......@@ -88,13 +90,29 @@ TEST(Morpho, AlphaTree)
};
ASSERT_IMAGES_EQ_EXP(cut(t, node_map, 0), ref0);
ASSERT_IMAGES_EQ_EXP(cut(t, node_map, 1), ref1);
ASSERT_IMAGES_EQ_EXP(cut(t, node_map, 10), ref10);
ASSERT_IMAGES_EQ_EXP(cut(t, node_map, 11), ref11);
ASSERT_IMAGES_EQ_EXP(cut(t, node_map, 0u), ref_0);
ASSERT_IMAGES_EQ_EXP(cut(t, node_map, 1u), ref_1);
ASSERT_IMAGES_EQ_EXP(cut(t, node_map, 10u), ref_10);
ASSERT_IMAGES_EQ_EXP(cut(t, node_map, 11u), ref_11);
}
TEST(Morpho, AlphaTreeRGB8)
TEST(Morpho, AlphaTreeParentRelation)
{
mln::image2d<int> ima = {
{4, 0, 0, 1}, //
{5, 0, 8, 1}, //
{6, 0, 9, 1}, //
{7, 0, 10, 1}, //
{2, 3, 4, 5}, //
};
auto [t, _] = mln::morpho::alphatree(ima, mln::c4);
for (std::size_t i = 0; i < t.parent.size(); ++i)
ASSERT_TRUE(static_cast<int>(i) >= t.parent[i]);
}
TEST(Morpho, AlphaTreeRGB8Uint16Distance)
{
const mln::image2d<mln::rgb8> ima = {
{{10, 0, 0}, {10, 0, 0}, {12, 20, 38}}, //
......@@ -102,58 +120,182 @@ TEST(Morpho, AlphaTreeRGB8)
{{11, 18, 0}, {25, 17, 11}, {9, 0, 5}} //
};
auto [t, nm] = mln::morpho::alphatree(
ima, mln::c4, [](const auto& a, const auto& b) -> std::uint16_t { return mln::functional::l2dist_t<>()(a, b); });
const mln::image2d<int> ref_0 = {
{0, 0, 1}, //
{2, 3, 4}, //
{5, 6, 7} //
};
const mln::image2d<int> ref_8 = {
{6, 6, 13}, //
{12, 6, 10}, //
{9, 8, 7} //
{0, 0, 1}, //
{2, 0, 4}, //
{5, 6, 7} //
};
const mln::image2d<int> ref_16 = {
{6, 6, 13}, //
{5, 6, 10}, //
{5, 8, 7} //
{0, 0, 1}, //
{2, 0, 4}, //
{2, 6, 7} //
};
const mln::image2d<int> ref_17 = {
{6, 6, 13}, //
{4, 6, 10}, //
{4, 4, 7} //
ASSERT_IMAGES_EQ_EXP(cut(t, nm, 0u), ref_0);
ASSERT_IMAGES_EQ_EXP(cut(t, nm, 8u), ref_8);
ASSERT_IMAGES_EQ_EXP(cut(t, nm, 16u), ref_16);
}
TEST(Morpho, AlphaTreeRGB8FloatDistance)
{
const mln::image2d<mln::rgb8> ima = {
{{10, 0, 0}, {10, 0, 0}, {12, 20, 38}}, //
{{13, 22, 16}, {15, 2, 6}, {37, 25, 12}}, //
{{11, 18, 0}, {25, 17, 11}, {9, 0, 5}} //
};
const mln::image2d<int> ref_18 = {
{3, 3, 13}, //
{3, 3, 10}, //
{3, 3, 7} //
auto [t, nm] = mln::morpho::alphatree(
ima, mln::c4, [](const auto& a, const auto& b) -> std::float_t { return mln::functional::l2dist_t<>()(a, b); });
const mln::image2d<int> ref_0 = {
{0, 0, 1}, //
{2, 3, 4}, //
{5, 6, 7} //
};
const mln::image2d<int> ref_24 = {
{2, 2, 13}, //
{2, 2, 10}, //
{2, 2, 2} //
const mln::image2d<int> ref_16 = {
{0, 0, 1}, //
{2, 0, 4}, //
{5, 6, 7} //
};
const mln::image2d<int> ref_32 = {
{1, 1, 13}, //
{1, 1, 1}, //
{1, 1, 1} //
{0, 0, 1}, //
{2, 0, 4}, //
{2, 6, 7} //
};
const mln::image2d<int> ref_36 = {
{0, 0, 0}, //
{0, 0, 0}, //
{0, 0, 0} //
ASSERT_IMAGES_EQ_EXP(cut(t, nm, 0.f), ref_0);
ASSERT_IMAGES_EQ_EXP(cut(t, nm, 16.f), ref_16);
ASSERT_IMAGES_EQ_EXP(cut(t, nm, 32.f), ref_32);
}
TEST(Morpho, AlphaTree8C)
{
mln::image2d<std::uint32_t> ima = {
{128, 124, 150, 137, 106}, //
{116, 128, 156, 165, 117}, //
{117, 90, 131, 108, 151}, //
{107, 87, 118, 109, 167}, //
{107, 73, 125, 157, 117}, //
};
auto [t, nm] = mln::morpho::alphatree(
ima, mln::c4, [](const auto& a, const auto& b) -> std::uint16_t { return mln::functional::l2dist_t<>()(a, b); });
auto rng = std::vector<int>(t.parent.size());
std::iota(rng.begin(), rng.end(), 0);
ASSERT_IMAGES_EQ_EXP(mln::morpho::horizontal_cut_labelization_from(t, nm, 0u, rng), nm);
ASSERT_IMAGES_EQ_EXP(mln::morpho::horizontal_cut_labelization_from(t, nm, 8u, rng), ref_8);
ASSERT_IMAGES_EQ_EXP(mln::morpho::horizontal_cut_labelization_from(t, nm, 16u, rng), ref_16);
ASSERT_IMAGES_EQ_EXP(mln::morpho::horizontal_cut_labelization_from(t, nm, 17u, rng), ref_17);
ASSERT_IMAGES_EQ_EXP(mln::morpho::horizontal_cut_labelization_from(t, nm, 18u, rng), ref_18);
ASSERT_IMAGES_EQ_EXP(mln::morpho::horizontal_cut_labelization_from(t, nm, 24u, rng), ref_24);
ASSERT_IMAGES_EQ_EXP(mln::morpho::horizontal_cut_labelization_from(t, nm, 32u, rng), ref_32);
ASSERT_IMAGES_EQ_EXP(mln::morpho::horizontal_cut_labelization_from(t, nm, 36u, rng), ref_36);
ima, mln::c8, [](const auto& a, const auto& b) -> std::uint32_t { return mln::functional::l2dist_t<>()(a, b); });
mln::image2d<int> ref_0 = {
{0, 1, 2, 3, 4}, //
{5, 0, 6, 7, 8}, //
{9, 10, 11, 12, 13}, //
{14, 15, 16, 17, 18}, //
{14, 19, 20, 21, 22}, //
};
mln::image2d<int> ref_16 = {
{0, 0, 2, 2, 4}, //
{5, 0, 6, 7, 8}, //
{9, 10, 11, 8, 7}, //
{9, 10, 16, 16, 18}, //
{9, 19, 20, 18, 22}, //
};
ASSERT_IMAGES_EQ_EXP(cut(t, nm, 0.f), ref_0);
ASSERT_IMAGES_EQ_EXP(cut(t, nm, 16.f), ref_16);
}
TEST(Morpho, AlphaTree8CHQUEUE)
{
mln::image2d<std::uint8_t> ima = {
{128, 124, 150, 137, 106}, //
{116, 128, 156, 165, 117}, //
{117, 90, 131, 108, 151}, //
{107, 87, 118, 109, 167}, //
{107, 73, 125, 157, 117}, //
};
auto [t, nm] = mln::morpho::alphatree(
ima, mln::c8, [](const auto& a, const auto& b) -> std::uint8_t { return mln::functional::l2dist_t<>()(a, b); });
mln::image2d<int> ref_0 = {
{0, 1, 2, 3, 4}, //
{5, 0, 6, 7, 8}, //
{9, 10, 11, 12, 13}, //
{14, 15, 16, 17, 18}, //
{14, 19, 20, 21, 22}, //
};
mln::image2d<int> ref_16 = {
{0, 1, 2, 3, 4}, //
{5, 0, 2, 7, 8}, //
{5, 10, 0, 12, 13}, //
{14, 10, 16, 12, 18}, //
{14, 19, 16, 18, 22}, //
};
ASSERT_IMAGES_EQ_EXP(cut(t, nm, 0.f), ref_0);
ASSERT_IMAGES_EQ_EXP(cut(t, nm, 16.f), ref_16);
}
TEST(Morpho, AlphaTree3DImage)
{
const mln::image3d<uint32_t> ima = {
{{10, 0, 0}, {10, 0, 0}, {12, 20, 38}}, //
{{13, 22, 16}, {15, 2, 6}, {37, 25, 12}}, //
{{11, 18, 0}, {25, 17, 11}, {9, 0, 5}} //
};
auto [t, nm] = mln::morpho::alphatree(
ima, mln::c26, [](const auto& a, const auto& b) -> std::uint32_t { return mln::functional::l2dist_t<>()(a, b); });
const mln::image3d<int> ref_0 = {
{{0, 1, 1}, {0, 1, 1}, {2, 3, 4}}, //
{{5, 6, 7}, {8, 9, 10}, {11, 12, 13}}, //
{{14, 15, 16}, {12, 17, 18}, {19, 20, 21}} //
};
const mln::image3d<int> ref_16 = {
{{0, 1, 1}, {0, 1, 1}, {1, 3, 4}}, //
{{5, 6, 7}, {8, 9, 10}, {11, 0, 13}}, //
{{5, 15, 9}, {0, 15, 13}, {19, 9, 10}} //
};
ASSERT_IMAGES_EQ_EXP(cut(t, nm, 0u), ref_0);
ASSERT_IMAGES_EQ_EXP(cut(t, nm, 16u), ref_16);
}
TEST(Morpho, AlphaTree3DImageHQUEUE)
{
const mln::image3d<uint8_t> ima = {
{{10, 0, 0}, {10, 0, 0}, {12, 20, 38}}, //
{{13, 22, 16}, {15, 2, 6}, {37, 25, 12}}, //
{{11, 18, 0}, {25, 17, 11}, {9, 0, 5}} //
};
auto [t, nm] = mln::morpho::alphatree(
ima, mln::c26, [](const auto& a, const auto& b) -> std::uint8_t { return mln::functional::l2dist_t<>()(a, b); });
const mln::image3d<int> ref_0 = {
{{0, 1, 1}, {0, 1, 1}, {2, 3, 4}}, //
{{5, 6, 7}, {8, 9, 10}, {11, 12, 13}}, //
{{14, 15, 16}, {12, 17, 18}, {19, 20, 21}} //
};
const mln::image3d<int> ref_16 = {
{{0, 1, 1}, {0, 1, 1}, {0, 3, 4}}, //
{{5, 6, 7}, {5, 1, 10}, {11, 6, 13}}, //
{{5, 7, 1}, {6, 7, 13}, {19, 1, 10}} //
};
ASSERT_IMAGES_EQ_EXP(cut(t, nm, 0u), ref_0);
ASSERT_IMAGES_EQ_EXP(cut(t, nm, 16u), ref_16);
}
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment