Commit a11be2f2 authored by Michaël Roynard's avatar Michaël Roynard
Browse files

Migrate fill algorithm

parent c5a4a079
......@@ -179,11 +179,11 @@ void fill_baseline(mln::image2d<mln::rgb8>& ima, mln::rgb8 v)
}
void fill(mln::image2d<mln::uint8>& ima, mln::uint8 v)
{
mln::experimental::fill(ima, v);
mln::fill(ima, v);
}
void fill(mln::image2d<mln::rgb8>& ima, mln::rgb8 v)
{
mln::experimental::fill(ima, v);
mln::fill(ima, v);
}
......
......@@ -12,84 +12,30 @@
namespace mln
{
/// \brief \p fill assigns the value \p val to every element of the image \p
/// ima.
/// \brief Assigns the value \p val to every element of the image \p ima.
///
/// \ingroup Algorithms
///
/// \param[out] output The output image.
/// \param val The value to assign.
/// \param[out] f The output image.
/// \param v The value to assign.
///
/// \return The image.
///
/// \tparam OutputImage is a model of the Writable Forward Image.
/// \tparam Value must be convertible to Image's value type.
/// \ingroup algorithms
template <typename OutputImage, typename Value>
[[deprecated]] OutputImage& fill(Image<OutputImage>& output, const Value& val);
/// \overload
/// \ingroup Algorithms
template <typename OutputImage, typename Value>
[[deprecated]] OutputImage&& fill(Image<OutputImage>&& output, const Value& val);
namespace experimental
{
/// \brief Assigns the value \p val to every element of the image \p ima.
///
/// \ingroup Algorithms
///
/// \param[out] f The output image.
/// \param v The value to assign.
///
///
/// \tparam OutputImage is a model of the Writable Forward Image.
/// \tparam Value must be convertible to Image's value type.
template <class OutputImage, class Value>
void fill(OutputImage f, const Value& v);
} // namespace experimental
template <class OutputImage, class Value>
void fill(OutputImage f, const Value& v);
/******************************************/
/**** Implementation ****/
/******************************************/
namespace impl
template <class OutputImage, class Value>
void fill(OutputImage f, const Value& v)
{
template <typename I, typename V>
void fill(I& ima, const V& v)
{
mln_viter(pin, ima);
mln_forall (pin)
*pin = v;
}
} // namespace impl
static_assert(mln::is_a<OutputImage, experimental::Image>());
template <typename OutputImage, typename Value>
OutputImage&& fill(Image<OutputImage>&& output_, const Value& val)
{
fill(output_, val);
return move_exact(output_);
}
template <typename OutputImage, typename Value>
OutputImage& fill(Image<OutputImage>& output_, const Value& val)
{
OutputImage& output = exact(output_);
impl::fill(output, val);
return output;
auto&& vals = f.new_values();
for (auto row : ranges::rows(vals))
::ranges::fill(row, v);
}
namespace experimental
{
template <class OutputImage, class Value>
void fill(OutputImage f, const Value& v)
{
static_assert(mln::is_a<OutputImage, Image>());
auto&& vals = f.new_values();
for (auto row : ranges::rows(vals))
::ranges::fill(row, v);
}
} // namespace experimental
} // namespace mln
......@@ -7,6 +7,32 @@
#include <queue>
namespace impl
{
template <typename I, typename V>
void fill(I& ima, const V& v)
{
mln_viter(pin, ima);
mln_forall (pin)
*pin = v;
}
} // namespace impl
template <typename OutputImage, typename Value>
OutputImage& __fill(mln::Image<OutputImage>& output_, const Value& val)
{
OutputImage& output = mln::exact(output_);
impl::fill(output, val);
return output;
}
template <typename OutputImage, typename Value>
OutputImage&& __fill(mln::Image<OutputImage>&& output_, const Value& val)
{
__fill(output_, val);
return mln::move_exact(output_);
}
namespace mln
{
......@@ -61,7 +87,7 @@ namespace mln
static_assert(std::is_same<mln_value(J), bool>::value, "Output image value type must be bool");
mln::fill(out, true);
__fill(out, true);
extension::fill(out, false);
impl::saturate(ima, nbh, out, pinf);
}
......
......@@ -10,6 +10,33 @@
#include <mln/morpho/tos/private/propagation.hpp>
// FIXME
namespace impl
{
template <typename I, typename V>
void fill(I& ima, const V& v)
{
mln_viter(pin, ima);
mln_forall (pin)
*pin = v;
}
} // namespace impl
template <typename OutputImage, typename Value>
OutputImage& __fill(mln::Image<OutputImage>& output_, const Value& val)
{
OutputImage& output = mln::exact(output_);
impl::fill(output, val);
return output;
}
template <typename OutputImage, typename Value>
OutputImage&& __fill(mln::Image<OutputImage>&& output_, const Value& val)
{
__fill(output_, val);
return mln::move_exact(output_);
}
namespace mln
{
namespace morpho
......@@ -49,7 +76,8 @@ namespace mln
mln_ch_value(J, bool) is2F = imchvalue<bool>(pmap).init(false);
auto dom = is2F.domain();
mln_point(J) step = 2; // {2,2} or {2,2,2}
mln::fill(is2F | make_strided_box(dom.pmin, dom.pmax, step), true);
// FIXME
__fill(is2F | make_strided_box(dom.pmin, dom.pmax, step), true);
for (unsigned p = 0; p < S.size(); ++p)
{
......
......@@ -25,8 +25,7 @@ TEST(Core, Algorithm_Exp_Fill)
using namespace mln::experimental::ops;
mln::image2d<std::uint8_t> ima(10, 10);
mln::experimental::fill(ima, 69);
mln::fill(ima, 69);
ASSERT_TRUE(mln::experimental::all(ima == 69));
}
......@@ -31,10 +31,10 @@ TEST(Core, Algorithm_Paste)
TEST(Core, Experimental_Algorithm_Paste)
{
mln::box2d b = {{1, 1}, {3, 3}};
mln::box2d b = {{1, 1}, {3, 3}};
mln::image2d<uint8_t> ima(b);
mln::image2d<uint8_t> out(15, 15);
mln::experimental::fill(ima, 69);
mln::fill(ima, 69);
mln::iota(out, 1);
mln::experimental::paste(ima, out);
// 1 2 3 4..
......@@ -45,4 +45,3 @@ TEST(Core, Experimental_Algorithm_Paste)
ASSERT_EQ(r, 225 * 226 / 2 - (17 + 18 + 32 + 33) + 69 * 4);
}
#include <mln/core/algorithm/all_of.hpp>
#include <mln/core/algorithm/fill.hpp>
#include <mln/core/algorithm/iota.hpp>
#include <mln/core/grays.hpp>
......@@ -5,6 +6,7 @@
#include <mln/core/image/image_ops.hpp>
#include <mln/core/image/private/image_operators.hpp>
#include <mln/core/image/private/where.hpp>
#include <mln/core/image/view/transform.hpp>
#include <mln/io/imprint.hpp>
......@@ -12,6 +14,7 @@
#include <gtest/gtest.h>
mln::image2d<int> make_image()
{
mln::image2d<int> x(5, 5);
......@@ -26,14 +29,6 @@ struct rgb
bool operator==(const rgb& other) const { return r == other.r and g == other.g and b == other.b; }
};
struct red
{
int& operator()(rgb& x) const { return x.r; }
const int& operator()(const rgb& x) const { return x.r; }
};
std::ostream& operator<<(std::ostream& ss, const rgb& x)
{
return ss << boost::make_tuple(x.r, x.g, x.b);
......@@ -42,16 +37,19 @@ std::ostream& operator<<(std::ostream& ss, const rgb& x)
TEST(Core, Image2d_LValueOperator)
{
using namespace mln;
using namespace mln::experimental::ops;
image2d<rgb> ima(5, 5);
rgb zero = {0, 0, 0};
rgb douze = {12, 0, 0};
mln::fill(ima, zero);
auto x = make_unary_image_expr(ima, red());
auto x = view::transform(ima, &rgb::r);
mln::fill(x, 12);
ASSERT_TRUE(mln::all(ima == douze));
ASSERT_TRUE(mln::all_of(ima == douze));
ASSERT_TRUE(mln::all_of(x == 12));
}
TEST(Core, Image2d_Operators)
......@@ -77,7 +75,7 @@ TEST(Core, Image2d_MixedOperator)
image2d<char> x(5, 5);
image2d<short> y(5, 5);
mln::iota(x, 0);
mln::iota(y, 0);
......@@ -207,7 +205,7 @@ TEST(Core, IfElse)
{1, 2, 3}};
// FIXME: issue https://github.com/ericniebler/range-v3/issues/996 with gcc8.2
// mln::experimental::fill(f2, 42);
// mln::fill(f2, 42);
// ASSERT_TRUE(mln::experimental::all(x == ref_x));
// ASSERT_TRUE(mln::experimental::all(y == ref_y));
......@@ -238,16 +236,16 @@ TEST(Core, Where)
struct mask_archetype : mln::experimental::Image<mask_archetype>
{
using value_type = bool;
using reference = const bool&;
using domain_type = mln::archetypes::Domain;
using point_type = ::ranges::range_value_t<domain_type>;
using category_type = mln::forward_image_tag;
using concrete_type = mask_archetype;
using value_type = bool;
using reference = const bool&;
using domain_type = mln::archetypes::Domain;
using point_type = ::ranges::range_value_t<domain_type>;
using category_type = mln::forward_image_tag;
using concrete_type = mask_archetype;
struct new_pixel_type
{
bool val() const;
bool val() const;
point_type point() const;
};
......@@ -261,11 +259,11 @@ struct mask_archetype : mln::experimental::Image<mask_archetype>
using view = std::false_type;
domain_type domain() const;
reference operator()(point_type);
reference at(point_type);
new_pixel_type new_pixel(point_type);
new_pixel_type new_pixel_at(point_type);
domain_type domain() const;
reference operator()(point_type);
reference at(point_type);
new_pixel_type new_pixel(point_type);
new_pixel_type new_pixel_at(point_type);
struct pixel_range
{
......
#include <mln/core/algorithm/all_of.hpp>
#include <mln/core/algorithm/fill.hpp>
#include <mln/core/algorithm/iota.hpp>
#include <mln/core/image/image2d.hpp>
#include <mln/core/image/private/image_operators.hpp>
#include <mln/core/image/view/filter.hpp>
#include <mln/core/neighb2d.hpp>
#include <mln/io/imprint.hpp>
#include <gtest/gtest.h>
TEST(Core, FilteredImage_filtered_bypix)
{
using namespace mln;
typedef image2d<int> I;
box2d dom{{-1, -2}, {3, 3}};
image2d<int> ima(dom);
typedef I::const_pixel_type Pix;
iota(ima, 0);
auto x = imfilter(ima, [](const Pix& px) { return px.val() > 10; });
ASSERT_TRUE(all(x > 10));
{mln_foreach (const Pix& pix, ima.pixels()){if (pix.val() > 10) ASSERT_EQ(pix.val(), x(pix.point()));
else
{
ASSERT_TRUE(!x.domain().has(pix.point()));
ASSERT_EQ(pix.val(), x.at(pix.point()));
}
}
}
{
mln_foreach (const auto& pix, x.pixels())
{
ASSERT_EQ(pix.val(), ima(pix.point()));
}
}
}
TEST(Core, FilteredImage_filtered_byval)
{
using namespace mln;
typedef image2d<int> I;
using namespace mln::experimental::ops;
box2d dom{{-1, -2}, {3, 3}};
image2d<int> ima(dom);
typedef I::const_pixel_type Pix;
iota(ima, 0);
auto x = imfilter(ima, [](int v) { return v > 10; });
auto x = view::filter(ima, [](int v) { return v > 10; });
ASSERT_TRUE(all(x > 10));
ASSERT_TRUE(all_of(x > 10));
{
mln_foreach (const Pix& pix, ima.pixels())
for (auto&& pix : ima.new_pixels())
{
if (pix.val() > 10)
ASSERT_EQ(pix.val(), x(pix.point()));
else
......@@ -64,10 +33,11 @@ TEST(Core, FilteredImage_filtered_byval)
ASSERT_TRUE(!x.domain().has(pix.point()));
ASSERT_EQ(pix.val(), x.at(pix.point()));
}
}
}
{
mln_foreach (const auto& pix, x.pixels())
for (auto&& pix : x.new_pixels())
{
ASSERT_EQ(pix.val(), ima(pix.point()));
}
......@@ -77,50 +47,49 @@ TEST(Core, FilteredImage_filtered_byval)
TEST(Core, FilteredImage_filtered_bypix_writing)
{
using namespace mln;
typedef image2d<int> I;
using namespace mln::experimental::ops;
box2d dom{{-1, -2}, {3, 3}};
image2d<int> ima(dom);
typedef I::const_pixel_type Pix;
iota(ima, 0);
auto x = imfilter(ima, [](const Pix& px) { return px.val() > 10; });
auto x = view::filter(ima, [](int v) { return v > 10; });
mln::fill(x, 10);
ASSERT_TRUE(all(ima <= 10));
ASSERT_TRUE(all_of(ima <= 10));
}
TEST(Core, FilteredImage_filtered_byval_writing)
{
using namespace mln;
using namespace mln::experimental::ops;
box2d dom{{-1, -2}, {3, 3}};
image2d<int> ima(dom);
iota(ima, 0);
auto x = imfilter(ima, [](int x) { return x > 10; });
auto x = view::filter(ima, [](int x) { return x > 10; });
mln::fill(x, 10);
ASSERT_TRUE(all(ima <= 10));
ASSERT_TRUE(all_of(ima <= 10));
}
TEST(Core, FilteredImage_filtered_chaining)
{
using namespace mln;
using namespace mln::experimental::ops;
box2d dom{{-1, -2}, {3, 3}};
image2d<int> ima(dom);
iota(ima, 0);
auto x = imfilter(ima, [](int v) { return v > 10; });
auto u = imfilter(x, [](int v) { return v < 15; });
auto x = view::filter(ima, [](int v) { return v > 10; });
auto u = view::filter(x, [](int v) { return v < 15; });
ASSERT_TRUE(all(land(u > 10, u < 15)));
ASSERT_TRUE(all_of(u > 10 && u < 15));
{
mln_foreach (const auto& pix, ima.pixels())
for (auto&& pix : ima.new_pixels())
if (pix.val() > 10 and pix.val() < 15)
ASSERT_EQ(pix.val(), u(pix.point()));
else
......@@ -131,7 +100,7 @@ TEST(Core, FilteredImage_filtered_chaining)
}
{
mln_foreach (const auto& pix, u.pixels())
for (auto&& pix : u.new_pixels())
{
ASSERT_EQ(pix.val(), ima(pix.point()));
}
......@@ -140,21 +109,22 @@ TEST(Core, FilteredImage_filtered_chaining)
const image2d<int> before = clone(ima);
mln::fill(u, 1);
{
mln_pixter(px, ima);
mln_pixter(px_before, before);
mln_forall (px, px_before)
auto z = view::zip(ima, before);
for (auto&& z_pix : z.new_pixels())
{
if (px_before->val() > 10 and px_before->val() < 15)
ASSERT_EQ(px->val(), 1);
auto&& [v_ima, v_before] = z_pix.val();
if (v_before > 10 and v_before < 15)
ASSERT_EQ(v_ima, 1);
else
{
ASSERT_TRUE(!u.domain().has(px->point()));
ASSERT_EQ(px->val(), px_before->val());
ASSERT_TRUE(!u.domain().has(z_pix.point()));
ASSERT_EQ(v_ima, v_before);
}
}
}
{
mln_foreach (const auto& pix, u.pixels())
for (auto&& pix : u.new_pixels())
{
ASSERT_EQ(pix.val(), ima(pix.point()));
}
......
......@@ -2,7 +2,10 @@
#include <mln/core/algorithm/iota.hpp>
#include <mln/core/image/image2d.hpp>
#include <mln/core/image/morphers/transformed_image.hpp>
#include <mln/core/image/view/transform.hpp>
#include <mln/core/image/view/zip.hpp>
#include <mln/core/neighb2d.hpp>
#include <mln/core/rangev3/rows.hpp>
#include <gtest/gtest.h>
......@@ -86,36 +89,31 @@ TEST(Core, TransformedImage_transform_byval_lvalue)
image2d<V> ima(dom);
{
auto c1 = imtransform(ima, [](std::pair<int, int>& x) -> int& { return x.first; });
auto c2 = imtransform(ima, [](const std::pair<int, int>& x) -> const int& { return x.second; });
auto c1 = view::transform(ima, &std::pair<int, int>::first);
auto c2 = view::transform(ima, &std::pair<int, int>::second);
mln::fill(ima, std::make_pair(12, 12));
mln::fill(c1, 69);
// Test pixel iteration
// check that properties of pixels are preserved (point + index)
{
mln_pixter(px0, ima);
mln_pixter(px1, c1);
mln_pixter(px2, c2);
mln_forall (px0, px1, px2)
auto z = view::zip(ima, c1, c2);
for (auto&& z_pix : z.new_pixels())
{
ASSERT_EQ(px1->point(), px0->point());
ASSERT_EQ(px1->index(), px0->index());
ASSERT_EQ(px1->val(), px0->val().first);
ASSERT_EQ(px1->val(), 69);
ASSERT_EQ(px2->val(), 12);
auto&& [v0, v1, v2] = z_pix.val();
ASSERT_EQ(v1, v0.first);
ASSERT_EQ(v1, 69);
ASSERT_EQ(v2, 12);
}
}
// Test value iteration
{
mln_viter(v0, ima);
mln_viter(v1, c1);
mln_viter(v2, c2);
mln_forall (v0, v1, v2)
auto z = view::zip(ima, c1, c2);
for (auto&& [v0, v1, v2] : z.new_values())
{
ASSERT_EQ(v0->first, *v1);
ASSERT_EQ(v0->second, *v2);
ASSERT_EQ(v0.first, v1);
ASSERT_EQ(v0.second, v2);
}
}
}
......
#include <mln/core/algorithm/all_of.hpp>
#include <mln/core/algorithm/fill.hpp>
#include <mln/core/algorithm/iota.hpp>
#include <mln/core/image/image2d.hpp>
#include <mln/core/image/private/image_operators.hpp>
#include <mln/core/image/view/mask.hpp>
#include <mln/io/imprint.hpp>
#include <gtest/gtest.h>
......@@ -72,6 +75,7 @@ TEST(Core, SubImage_sub_domain_with_box)
TEST(Core, SubImage_sub_domain)
{
using namespace mln;