Commit 2248eea0 authored by Victor Simonin's avatar Victor Simonin
Browse files

Create new branch from development/watershed-hierarchy for future request,...

Create new branch from development/watershed-hierarchy for future request, import saliency map on component tree
parent 1d332ac2
Pipeline #28545 passed with stages
in 15 minutes and 15 seconds
......@@ -3,7 +3,10 @@
#include <mln/accu/accumulator.hpp>
#include <mln/core/algorithm/clone.hpp>
#include <mln/core/algorithm/fill.hpp>
#include <mln/core/image/ndimage.hpp>
#include <mln/core/image/view/zip.hpp>
#include <mln/core/neighborhood/c4.hpp>
#include <mln/core/range/foreach.hpp>
#include <mln/core/trace.hpp>
......@@ -122,6 +125,19 @@ namespace mln::morpho
template <class I, class V>
image_ch_value_t<I, V> reconstruct_from(I node_map, ::ranges::span<V> values) const;
using Edge = std::tuple<int, int, double>;
/// Generate a saliency map of the given Component Tree
///
/// @return A list of edges that associates each edges to a saliency weight
template <class I, class J>
std::vector<Edge> saliency_map(I node_map, J values);
/// Produce a visualization of the given Component Tree using the Khalimsky grid of the saliency map
template <class I, class J>
mln::image2d<double> saliency_khalimsky_grid(I node_map, J values);
using node_t = int;
std::vector<node_t> parent;
......@@ -411,5 +427,105 @@ namespace mln::morpho
return out;
}
using Edge = std::tuple<int, int, double>;
template <class I, class J>
std::vector<Edge> component_tree<void>::saliency_map(I node_map, J values)
{
std::vector<Edge> res;
auto width = node_map.width();
mln_foreach (auto p, node_map.domain())
{
for (auto q : mln::c4(p))
{
if ((q[0] == p[0] + 1 || q[1] == p[1] + 1) && q[0] < node_map.width() && q[1] < node_map.height())
{
auto id_p = 0;
auto id_q = 0;
for (size_t i = 1; i < this->parent.size(); i++)
{
if (id_p == 0 && values[i] == node_map(p))
id_p = i;
if (id_q == 0 && values[i] == node_map(q))
id_q = i;
if (id_p != 0 && id_q != 0)
break;
}
auto edge = std::make_tuple(p[0] + width * p[1], q[0] + width * q[1], 0);
std::get<2>(edge) = std::abs(node_map(p) - node_map(q));
res.emplace_back(edge);
}
}
}
return res;
}
template <class I, class J>
mln::image2d<double> component_tree<void>::saliency_khalimsky_grid(I node_map, J values)
{
int height = node_map.height();
int width = node_map.width();
int res_height = 2 * height + 1;
int res_width = 2 * width + 1;
image2d<double> res(res_width, res_height);
fill(res, 0);
const std::vector<Edge>& s_map = this->saliency_map(node_map, values);
for (const auto& edge : s_map)
{
int u = std::get<0>(edge);
  • To get all the values of a tuple, you can use structured bindings

    int u = std::get<0>(edges);
    int v = std::get<1>(edges);
    float w = std::get<2>(edges);

    becomes

    const auto [u, v, w] = edges;

    So when you traverse the s_map vector, you can do in your for loop

    for (const auto [u, v, w] : s_map)
Please register or sign in to reply
int v = std::get<1>(edge);
double w = std::get<2>(edge);
int u_pos[2] = {u % width, u / width};
int v_pos[2] = {v % width, v / width};
int res_offset[2] = {u_pos[0] - v_pos[0], u_pos[1] - v_pos[1]};
int res_edge_pos[2] = {2 * v_pos[0] + 1 + res_offset[0], 2 * v_pos[1] + 1 + res_offset[1]};
res({res_edge_pos[0], res_edge_pos[1]}) = w;
}
for (int y = 0; y < res_height; y += 2)
{
for (int x = 0; x < res_width; x += 2)
{
double max = std::numeric_limits<double>::min();
if (y + 1 < height)
max = std::max(max, res({x, y + 1}));
if (x + 1 < width)
max = std::max(max, res({x + 1, y}));
if (y - 1 >= 0)
max = std::max(max, res({x, y - 1}));
if (x - 1 >= 0)
max = std::max(max, res({x - 1, y}));
res({x, y}) = max;
}
}
for (int y = 0; y < res_height; y++)
{
for (int x = 0; x < res_width; x++)
{
res({x, y}) = 255 - res({x, y});
}
}
return res;
}
} // namespace mln::morpho
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