Commit a5c9d9b5 authored by Quentin Kaci's avatar Quentin Kaci
Browse files

Merge branch 'development/watershed-hierarchy-saliency-integration' of...

Merge branch 'development/watershed-hierarchy-saliency-integration' of https://gitlab.lrde.epita.fr/olena/pylene into development/watershed-hierarchy-saliency-integration

 Conflicts:
	pylene/include/mln/morpho/watershed_hierarchy.hpp
parents ce609a55 6c714d35
......@@ -306,6 +306,17 @@ It is also possible to compute the saliency map to obtain another visualization.
:return: The saliency map as an image
.. list-table::
* - .. image:: /images/watershed_hierarchy_area_gray.png
:width: 100%
- .. image:: /images/saliency_watershed.png
:width: 100%
* - Watershed hierarchy by area with a cut at a threshold of 25
- The corresponding saliency map
A complete example
------------------
......
......@@ -62,6 +62,8 @@ add_image("alphatree_example" "${PYLENE_IMAGE_DIR}/lena.pgm" alphatree_cut_gray.
add_image("watershed_hierarchy_example" "${PYLENE_IMAGE_DIR}/lena.ppm" watershed_hierarchy_area_color.png)
add_image("watershed_hierarchy_example" "${PYLENE_IMAGE_DIR}/lena.pgm" watershed_hierarchy_area_gray.png)
add_image("saliency_example" "${PYLENE_IMAGE_DIR}/lena.pgm" saliency_watershed.png)
add_custom_target(build-images
DEPENDS "${DOCUMENTATION_IMAGES}")
......@@ -74,6 +76,7 @@ link_libraries(doc-lib)
add_executable(alphatree_example alphatree_example.cpp)
add_executable(watershed_hierarchy_example watershed_hierarchy_example.cpp)
add_executable(saliency_example saliency_example.cpp)
add_executable(erosion-cli erosion-cli.cpp)
add_executable(staff_lines staff_lines.cpp)
add_executable(component_tree_1 component_tree_1.cpp)
......
#include <mln/accu/accumulators/mean.hpp>
#include <mln/core/colors.hpp>
#include <mln/core/image/ndimage.hpp>
#include <mln/core/image/view/cast.hpp>
#include <mln/core/neighborhood/c4.hpp>
#include <mln/io/imread.hpp>
#include <mln/io/imsave.hpp>
#include <mln/morpho/tos.hpp>
#include <mln/morpho/watershed_hierarchy.hpp>
#include <iostream>
void process_example(const mln::image2d<uint8_t>& img, const std::string& output_filename, const double threshold)
{
// 2. Build the watershed hierarchy
auto area_attribute_func = [](auto tree, auto nm) -> std::vector<size_t> {
return tree.compute_attribute_on_points(nm, mln::accu::features::count<>());
};
auto [t, nm] = mln::morpho::watershed_hierarchy(img, area_attribute_func, mln::c4);
// 3. Compute the mean attribute
auto mean = t.compute_attribute_on_values(nm, img, mln::accu::accumulators::mean<uint8_t>());
// 4. Compute a cut of the watershed hierarchy
auto cut_nm = t.horizontal_cut(threshold, nm);
// 5. Label the cut
auto cut = t.reconstruct_from(cut_nm, ::ranges::make_span(mean));
mln::io::imsave(mln::view::cast<uint8_t>(cut), output_filename);
mln::image2d<uint8_t> in;
mln::io::imread(output_filename, in);
auto [t2, node_map] = mln::morpho::tos(in, {0, 0});
auto saliency = t2.saliency(in);
// 5. Save the output
mln::io::imsave(mln::view::cast<uint8_t>(saliency), output_filename);
}
int main(int argc, char* argv[])
{
if (argc < 3)
{
std::cerr << "Invalid number of argument\nUsage: " << argv[0] << " input_filename output_filename\n";
return 1;
}
auto in_filename = std::string(argv[1]);
auto out_filename = std::string(argv[2]);
// 1. Read the input image
mln::ndbuffer_image in;
in = mln::io::imread(in_filename);
if (in.sample_type() == mln::sample_type_id::UINT8)
{
const auto* img = in.cast_to<std::uint8_t, 2>();
process_example(*img, out_filename, 25);
}
else
{
std::cerr << "Unhandled sample type format\n";
return 1;
}
return 0;
}
\ No newline at end of file
......@@ -56,6 +56,14 @@ namespace mln::morpho
details::directional_hqueue<P, N, W> m_cont;
};
template <typename P, typename W>
struct edge_t
{
P p;
P q;
W w;
};
template <typename P, typename N, typename W, bool HQ>
class alphatree_edges
{
......
......@@ -10,8 +10,6 @@
#include <mln/core/range/foreach.hpp>
#include <mln/core/trace.hpp>
#include <iostream>
#include <vector>
#include <range/v3/view/span.hpp>
......
......@@ -3,6 +3,17 @@
namespace mln::morpho
{
namespace internal
{
template <typename P, typename W>
struct edge_t
{
P p;
P q;
W w;
};
} // namespace internal
void component_tree<void>::filter_direct(const std::vector<bool>& pred)
{
this->filter_direct_T([&pred](int x) { return pred[x]; });
......@@ -22,9 +33,9 @@ namespace mln::morpho
return depth;
}
static std::vector<mln::morpho::edge_t<int, double>> saliency_map(mln::image2d<uint8_t> node_map)
static std::vector<internal::edge_t<int, double>> saliency_map(mln::image2d<uint8_t> node_map)
{
std::vector<mln::morpho::edge_t<int, double>> res;
std::vector<internal::edge_t<int, double>> res;
auto width = node_map.width();
......@@ -35,11 +46,10 @@ namespace mln::morpho
{
if (dom.has(q))
{
mln::morpho::edge_t<int, double> edge = {p[0] + width * p[1], q[0] + width * q[1], 0};
auto offset_p = p[0] + width * p[1];
auto offset_q = q[0] + width * q[1];
// std::cout << p[0] + width * p[1] << ' ' << node_map.index_of_point(p) << '\n';
// std::cout << q[0] + width * q[1] << ' ' << node_map.index_of_point(q) << '\n';
// std::cout << "\n\n";
internal::edge_t<int, double> edge = {offset_p, offset_q, 0};
edge.w = std::abs(node_map(p) - node_map(q));
......@@ -62,7 +72,7 @@ namespace mln::morpho
image2d<double> res(res_width, res_height);
fill(res, 0);
const std::vector<mln::morpho::edge_t<int, double>>& s_map = saliency_map(node_map);
const std::vector<internal::edge_t<int, double>>& s_map = saliency_map(node_map);
for (const auto [u, v, w] : s_map)
{
......@@ -104,4 +114,4 @@ namespace mln::morpho
return res;
}
}
} // namespace mln::morpho
......@@ -133,7 +133,7 @@ TEST(Morpho, AlphaTreeMST)
using I = mln::image2d<std::uint8_t>;
using P = mln::image_point_t<I>;
using W = std::uint8_t;
using E = mln::morpho::edge_t<P, W>;
using E = mln::morpho::internal::edge_t<P, W>;
I ima = {
{4, 0, 0, 1}, //
......
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