Commit 4bcc7c32 authored by Baptiste Esteban's avatar Baptiste Esteban
Browse files

Avoiding copy when adding border + doc corrections

parent f61d9c41
Pipeline #30608 passed with stage
in 19 minutes and 35 seconds
......@@ -119,7 +119,7 @@ This file provides functions to pad a rectangular buffer or an image either:
:param input: The input ndimage (or ndimensional buffer).
:param output: The input ndimage (or ndimensional buffer).
:param mode: The padding policy
:param value: The value used to fill the array (used if mode is `PAD_CONSTANT`
:param value: The value used to fill the array (used if mode is `PAD_CONSTANT`)
**Second version**
......@@ -127,7 +127,7 @@ This file provides functions to pad a rectangular buffer or an image either:
:param out: The output ndimensional buffer.
:param roi: The roi of the output buffer
:param mode: The padding policy
:param value: The value used to fill the array (used if mode is `PAD_CONSTANT`
:param value: The value used to fill the array (used if mode is `PAD_CONSTANT`)
......@@ -143,7 +143,7 @@ This file provides functions to pad a rectangular buffer or an image either:
mln::image2d<uint8_t> input(iroi);
mln::image2d<uint8_t> out(oroi);
mln::copy_and_pad(input, out, mln::PAD_CONSTANT, 69);
mln::copy_pad(input, out, mln::PAD_CONSTANT, 69);
......@@ -33,6 +33,7 @@ This example computes a grain filter, which removes all the node having an area
::
#include <mln/accu/accumulators/count.hpp>
#include <mln/core/extension/padding.hpp>
#include <mln/core/image/ndimage.hpp>
#include <mln/morpho/mtos.hpp>
#include <mln/io/imread.hpp>
......@@ -40,11 +41,8 @@ This example computes a grain filter, which removes all the node having an area
// Function to reduce the nodemap to the original image domain
mln::image2d<int> reduce_nodemap(mln::image2d<int> n);
// Function to add a border
mln::image2d<mln::rgb8> add_border(mln::image2d<mln::rgb8> ima);
// Function to remove the border
mln::image2d<int> remove_border(mln::image2d<int> n);
// Function to get the median of the border values
mln::rgb8 get_median_on_border(mln::image2d<mln::rgb8> ima);
// Accumulator to compute the mean of the pixel values of each node, without taking into account the values of the holes
struct mean_node_accu : mln::Accumulator<mean_node_accu>
......@@ -71,17 +69,21 @@ This example computes a grain filter, which removes all the node having an area
mln::image2d<mln::rgb8> ima;
mln::io::imread("lena.ppm", ima);
// Add a border
auto to_process = add_border(ima);
// Adding a border
const auto median = get_median_on_border(ima);
ima.inflate_domain(1);
constexpr int borders[2][2] = {{1, 1}, {1, 1}};
mln::pad(ima, mln::PAD_CONSTANT, borders, median);
// Compute the MToS
auto [t, nm] = mln::morpho::mtos(to_process, {0, 0});
auto [t, nm] = mln::morpho::mtos(to_process, {-1, -1}); // The rooting point is in the added border
// Reduce the nodemap
nm = reduce_nodemap(nm);
// Remove the border in the nodemap
nm = remove_border(nm);
// Remove the border
ima.inflate_domain(-1);
nm.inflate_domain(-1);
// Compute the area of each node of the tree
auto area = t.compute_attribute_on_points(nm, mln::accu::accumulators::count<int>());
......
#include <mln/accu/accumulators/count.hpp>
#include <mln/accu/accumulators/max.hpp>
#include <mln/core/algorithm/accumulate.hpp>
#include <mln/core/colors.hpp>
#include <mln/core/extension/padding.hpp>
#include <mln/core/image/ndimage.hpp>
#include <mln/core/image/view/channel.hpp>
#include <mln/core/image/view/transform.hpp>
......@@ -20,6 +23,7 @@ namespace
struct mean_node_accu : mln::Accumulator<mean_node_accu>
{
using result_type = decltype(std::declval<mln::rgb8>() + std::declval<mln::rgb8>());
public:
void take(const mln::rgb8& v)
{
......@@ -32,21 +36,15 @@ namespace
result_type to_result() const { return m_count > 1 ? static_cast<result_type>(m_sum / m_count) : m_sum; }
private:
result_type m_sum = {0, 0, 0};
int m_count = 0;
result_type m_sum = {0, 0, 0};
int m_count = 0;
};
/// \brief Add a border to the image with values set at the median value
mln::image2d<mln::rgb8> add_border(mln::image2d<mln::rgb8> ima)
mln::rgb8 get_median_on_border(mln::image2d<mln::rgb8> ima)
{
mln::image2d<mln::rgb8> res(ima.width() + 2, ima.height() + 2);
std::vector<mln::rgb8> border;
border.reserve(2 * ima.width() + 2 * ima.height() - 4);
mln_foreach (auto p, ima.domain())
res(mln::point2d{1, 1} + p) = ima(p);
for (int i = 0; i < ima.width(); i++)
{
border.push_back(ima(mln::point2d{i, 0}));
......@@ -65,45 +63,18 @@ namespace
i++;
return i < 3 && a[i] < b[i];
});
mln::rgb8 med = border[border.size() / 2];
for (int i = 0; i < res.width(); i++)
{
res(mln::point2d{i, 0}) = med;
res(mln::point2d{i, res.height() - 1}) = med;
}
for (int i = 1; i < res.height() - 1; i++)
{
res(mln::point2d{0, i}) = med;
res(mln::point2d{res.width() - 1, i}) = med;
}
return res;
}
mln::image2d<int> remove_border(mln::image2d<int> n)
{
mln::image2d<int> res(n.width() - 2, n.height() - 2);
mln_foreach(auto p, res.domain())
res(p) = n(p + mln::point2d{1, 1});
return res;
}
/// \brief Compute the maximum value of an image
std::uint16_t max(mln::image2d<std::uint16_t> ima)
{
std::uint16_t res = 0;
mln_foreach (auto p, ima.domain())
res = std::max(res, ima(p));
return res;
return border[border.size() / 2];
}
/// \brief Reduce the size of a nodemap by a factor 2
mln::image2d<int> reduce_nodemap(mln::image2d<int> n)
{
mln::image2d<int> res((n.width() + 3) / 4, (n.height() + 3) / 4);
// mln::image2d<int> res((n.width() + 3) / 4, (n.height() + 3) / 4);
const mln::point2d pmin(n.domain().tl());
const mln::point2d pmax(n.domain().br());
mln::image2d<int> res(mln::box2d{{(pmin[0] - 3) / 4, (pmin[1] - 3) / 4}, {(pmax[0] + 3) / 4, (pmax[1] + 3) / 4}});
mln_foreach(auto p, n.domain())
mln_foreach (auto p, n.domain())
{
if (p[0] % 4 == 0 && p[1] % 4 == 0)
{
......@@ -119,13 +90,18 @@ int main(int argc, char* argv[])
{
if (argc < 4)
{
std::cerr << "Invalid number of arguments\nUsage: " << argv[0] << " input_filename depth_map_filename rec_filename\n";
std::cerr << "Invalid number of arguments\nUsage: " << argv[0]
<< " input_filename depth_map_filename rec_filename\n";
return 1;
}
mln::image2d<mln::rgb8> ima;
mln::io::imread(argv[1], ima);
auto to_process = add_border(ima);
const auto med = get_median_on_border(ima);
ima.inflate_domain(1);
constexpr int borders[2][2] = {{1, 1}, {1, 1}};
mln::pad(ima, mln::PAD_CONSTANT, borders, med);
mln::morpho::component_tree<> trees[3];
mln::image2d<int> nodemaps[3];
......@@ -133,28 +109,29 @@ int main(int argc, char* argv[])
for (int c = 0; c < 3; c++)
{
std::tie(trees[c], nodemaps[c]) = mln::morpho::tos(mln::view::channel(to_process, c), {0, 0});
std::tie(trees[c], nodemaps[c]) = mln::morpho::tos(mln::view::channel(ima, c), {-1, -1});
depths[c] = trees[c].compute_depth();
}
const auto [gos, tree_to_graph] = mln::morpho::details::compute_inclusion_graph(trees, nodemaps, depths, 3);
auto depth_map = mln::morpho::details::compute_depth_map(gos, tree_to_graph, nodemaps);
{
std::uint16_t max_depth = max(depth_map);
std::uint16_t max_depth = mln::accumulate(depth_map, mln::accu::accumulators::max<std::uint16_t>());
auto normalized_depth =
mln::view::transform(depth_map, [&max_depth](std::uint16_t a) -> float { return (float)a / (float)max_depth; });
auto heat_depth = mln::view::transform(normalized_depth, heat_lut);
mln::io::imsave(heat_depth, argv[2]);
}
auto [t, nm] = mln::morpho::details::satmaxtree(depth_map, {0, 0});
nm = reduce_nodemap(nm);
nm = remove_border(nm);
auto [t, nm] = mln::morpho::details::satmaxtree(depth_map, {-1, -1});
nm = reduce_nodemap(nm);
ima.inflate_domain(-1);
nm.inflate_domain(-1);
auto area = t.compute_attribute_on_points(nm, mln::accu::accumulators::count<int>());
t.filter(mln::morpho::CT_FILTER_DIRECT, nm, [&area](int n) { return area[n] >= 100; });
auto mean = t.compute_attribute_on_values(nm, ima, mean_node_accu());
auto rec = t.reconstruct_from(nm, ranges::make_span(mean.data(), mean.size()));
auto rec = t.reconstruct_from(nm, ranges::make_span(mean.data(), mean.size()));
mln::io::imsave(mln::view::cast<mln::rgb8>(rec), argv[3]);
return 0;
......
Markdown is supported
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