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

Merge remote-tracking branch 'origin/development/filter_view' into development/sanitizer

parents 724c10c6 5879495a
Pipeline #12914 failed with stages
in 10 minutes and 51 seconds
...@@ -54,17 +54,17 @@ See :doc:`core/images` for a description of the image concepts and image basics. ...@@ -54,17 +54,17 @@ See :doc:`core/images` for a description of the image concepts and image basics.
:class: full :class: full
+-----------------------------------------------------------+--------------------------------------------------------------------------------------------+ +------------------------------------------------------------+--------------------------------------------------------------------------------------------+
| :cpp:func:`view::transform(ima,f) <mln::view::transform>` | Views the image with values applied to a function. | | :cpp:func:`view::transform(ima, f) <mln::view::transform>` | Views the image with a function applied to the values. |
+-----------------------------------------------------------+--------------------------------------------------------------------------------------------+ +------------------------------------------------------------+--------------------------------------------------------------------------------------------+
| ``view::filter(ima, pred)`` | Views the image restricted to pixels with values passing a predicate. | | ``view::filter(ima, pred)`` | Views the image restricted to pixels whose values pass a predicate. |
+-----------------------------------------------------------+--------------------------------------------------------------------------------------------+ +------------------------------------------------------------+--------------------------------------------------------------------------------------------+
| ``view::mask(ima, mask)`` | Views the image restricted to pixels in a binary mask. | | ``view::mask(ima, mask)`` | Views the image restricted to pixels in a binary mask. |
+-----------------------------------------------------------+--------------------------------------------------------------------------------------------+ +------------------------------------------------------------+--------------------------------------------------------------------------------------------+
| ``view::clip(ima, roi)`` | Views the image restricted to a sub-region. | | ``view::clip(ima, roi)`` | Views the image restricted to a sub-region. |
+-----------------------------------------------------------+--------------------------------------------------------------------------------------------+ +------------------------------------------------------------+--------------------------------------------------------------------------------------------+
| ``view::zip(ima1, ima2, ..., imaN)`` | Views a list of images as a single image where values are tuples of the each image values. | | ``view::zip(ima1, ima2, ..., imaN)`` | Views a list of images as a single image whose values are tuples of the each image values. |
+-----------------------------------------------------------+--------------------------------------------------------------------------------------------+ +------------------------------------------------------------+--------------------------------------------------------------------------------------------+
.. topic:: Common image operators (views) .. topic:: Common image operators (views)
......
...@@ -9,7 +9,7 @@ Include :file:`<mln/core/image/view/transform.hpp>` ...@@ -9,7 +9,7 @@ Include :file:`<mln/core/image/view/transform.hpp>`
#. .. cpp:function:: auto transform(Image ima, Image ima2, BinaryFunction f) #. .. cpp:function:: auto transform(Image ima, Image ima2, BinaryFunction f)
1. Makes a view from `ima` where for each pixel value evals to `out(p) = f(ima(p))` 1. Makes a view from `ima` where for each pixel value evals to `out(p) = f(ima(p))`
2. Makes a view from `ima` where for each pixel value evals to `out(p) = f(ima(p),ima2(p))`. For this overload, the domain of both image must be equal. 2. Makes a view from `ima` where for each pixel value evals to `out(p) = f(ima(p), ima2(p))`. For this overload, the domain of both image must be equal.
:param ima: Input range :param ima: Input range
......
...@@ -66,7 +66,8 @@ namespace mln ...@@ -66,7 +66,8 @@ namespace mln
static_assert(mln::is_a<InputImage, Image>()); static_assert(mln::is_a<InputImage, Image>());
auto a = accu::make_accumulator(exact(accu), image_value_t<InputImage>()); auto a = accu::make_accumulator(exact(accu), image_value_t<InputImage>());
for (auto row : mln::ranges::rows(input.new_values())) auto&& vals = input.new_values();
for (auto row : mln::ranges::rows(vals))
for (auto&& v : row) for (auto&& v : row)
a.take(v); a.take(v);
return ex(a); return ex(a);
...@@ -78,7 +79,8 @@ namespace mln ...@@ -78,7 +79,8 @@ namespace mln
{ {
static_assert(mln::is_a<InputImage, Image>()); static_assert(mln::is_a<InputImage, Image>());
for (auto row : mln::ranges::rows(input.new_values())) auto&& vals = input.new_values();
for (auto row : mln::ranges::rows(vals))
for (auto&& v : row) for (auto&& v : row)
init = op(init, v); init = op(init, v);
......
...@@ -29,7 +29,8 @@ namespace mln ...@@ -29,7 +29,8 @@ namespace mln
static_assert(mln::is_a<InputImage, Image>()); static_assert(mln::is_a<InputImage, Image>());
static_assert(::ranges::Predicate<UnaryPredicate, image_reference_t<InputImage>>()); static_assert(::ranges::Predicate<UnaryPredicate, image_reference_t<InputImage>>());
for (auto r : ranges::rows(input.new_values())) auto&& vals = input.new_values();
for (auto r : ranges::rows(vals))
if (!::ranges::all_of(r, p)) if (!::ranges::all_of(r, p))
return false; return false;
return true; return true;
...@@ -42,7 +43,8 @@ namespace mln ...@@ -42,7 +43,8 @@ namespace mln
static_assert(mln::is_a<InputImage, Image>()); static_assert(mln::is_a<InputImage, Image>());
static_assert(std::is_convertible_v<image_reference_t<InputImage>, bool>); static_assert(std::is_convertible_v<image_reference_t<InputImage>, bool>);
for (auto r : ranges::rows(input.new_values())) auto&& vals = input.new_values();
for (auto r : ranges::rows(vals))
for (auto&& v : r) for (auto&& v : r)
if (!v) if (!v)
return false; return false;
......
...@@ -29,7 +29,8 @@ namespace mln ...@@ -29,7 +29,8 @@ namespace mln
static_assert(mln::is_a<InputImage, Image>()); static_assert(mln::is_a<InputImage, Image>());
static_assert(::ranges::Predicate<UnaryPredicate, image_reference_t<InputImage>>()); static_assert(::ranges::Predicate<UnaryPredicate, image_reference_t<InputImage>>());
for (auto r : ranges::rows(input.new_values())) auto&& vals = input.new_values();
for (auto r : ranges::rows(vals))
if (::ranges::any_of(r, p)) if (::ranges::any_of(r, p))
return true; return true;
return false; return false;
...@@ -41,7 +42,8 @@ namespace mln ...@@ -41,7 +42,8 @@ namespace mln
static_assert(mln::is_a<InputImage, Image>()); static_assert(mln::is_a<InputImage, Image>());
static_assert(std::is_convertible_v<image_reference_t<InputImage>, bool>); static_assert(std::is_convertible_v<image_reference_t<InputImage>, bool>);
for (auto r : ranges::rows(input.new_values())) auto&& vals = input.new_values();
for (auto r : ranges::rows(vals))
for (auto&& v : r) for (auto&& v : r)
if (v) if (v)
return true; return true;
......
...@@ -113,10 +113,10 @@ namespace mln ...@@ -113,10 +113,10 @@ namespace mln
static_assert(mln::is_a<OutputImage, Image>()); static_assert(mln::is_a<OutputImage, Image>());
static_assert(std::is_convertible_v<image_value_t<InputImage>, image_value_t<OutputImage>>); static_assert(std::is_convertible_v<image_value_t<InputImage>, image_value_t<OutputImage>>);
auto input_rows = ranges::rows(input.new_values()); auto&& ivals = input.new_values();
auto output_rows = ranges::rows(output.new_values()); auto&& ovals = output.new_values();
for (auto [r1, r2] : ranges::view::zip(input_rows, output_rows)) for (auto [r1, r2] : ranges::view::zip(ranges::rows(ivals), ranges::rows(ovals)))
::ranges::copy(r1, ::ranges::begin(r2)); ::ranges::copy(r1, ::ranges::begin(r2));
} }
} // namespace experimental } // namespace experimental
......
...@@ -84,7 +84,8 @@ namespace mln ...@@ -84,7 +84,8 @@ namespace mln
{ {
static_assert(mln::is_a<OutputImage, Image>()); static_assert(mln::is_a<OutputImage, Image>());
for (auto row : ranges::rows(f.new_values())) auto&& vals = f.new_values();
for (auto row : ranges::rows(vals))
::ranges::fill(row, v); ::ranges::fill(row, v);
} }
} // namespace experimental } // namespace experimental
......
...@@ -29,7 +29,8 @@ namespace mln ...@@ -29,7 +29,8 @@ namespace mln
static_assert(mln::is_a<InputImage, Image>()); static_assert(mln::is_a<InputImage, Image>());
static_assert(::ranges::Invocable<UnaryFunction, image_reference_t<InputImage>>()); static_assert(::ranges::Invocable<UnaryFunction, image_reference_t<InputImage>>());
for (auto r : ranges::rows(input.new_values())) auto&& vals = input.new_values();
for (auto r : ranges::rows(vals))
::ranges::for_each(r, f); ::ranges::for_each(r, f);
} }
} // namespace experimental } // namespace experimental
......
...@@ -23,7 +23,8 @@ namespace mln ...@@ -23,7 +23,8 @@ namespace mln
static_assert(mln::is_a<OutputImage, Image>()); static_assert(mln::is_a<OutputImage, Image>());
static_assert(std::is_convertible_v<std::invoke_result_t<Generator>, image_value_t<OutputImage>>); static_assert(std::is_convertible_v<std::invoke_result_t<Generator>, image_value_t<OutputImage>>);
for (auto row : mln::ranges::rows(output.new_values())) auto&& vals = output.new_values();
for (auto row : mln::ranges::rows(vals))
for (auto& v : row) for (auto& v : row)
v = g(); v = g();
} }
......
...@@ -73,7 +73,8 @@ namespace mln ...@@ -73,7 +73,8 @@ namespace mln
static_assert(mln::is_a<OutputImage, Image>()); static_assert(mln::is_a<OutputImage, Image>());
static_assert(std::is_convertible_v<Value, image_value_t<OutputImage>>); static_assert(std::is_convertible_v<Value, image_value_t<OutputImage>>);
for (auto row : mln::ranges::rows(output.new_values())) auto&& vals = output.new_values();
for (auto row : mln::ranges::rows(vals))
for (auto& v : row) for (auto& v : row)
v = val++; v = val++;
} }
......
...@@ -29,7 +29,8 @@ namespace mln ...@@ -29,7 +29,8 @@ namespace mln
static_assert(mln::is_a<InputImage, Image>()); static_assert(mln::is_a<InputImage, Image>());
static_assert(::ranges::Predicate<UnaryPredicate, image_reference_t<InputImage>>()); static_assert(::ranges::Predicate<UnaryPredicate, image_reference_t<InputImage>>());
for (auto r : ranges::rows(input.new_values())) auto&& vals = input.new_values();
for (auto r : ranges::rows(vals))
if (!::ranges::none_of(r, p)) if (!::ranges::none_of(r, p))
return false; return false;
return true; return true;
...@@ -41,7 +42,8 @@ namespace mln ...@@ -41,7 +42,8 @@ namespace mln
static_assert(mln::is_a<InputImage, Image>()); static_assert(mln::is_a<InputImage, Image>());
static_assert(std::is_convertible_v<image_reference_t<InputImage>, bool>); static_assert(std::is_convertible_v<image_reference_t<InputImage>, bool>);
for (auto r : ranges::rows(input.new_values())) auto&& vals = input.new_values();
for (auto r : ranges::rows(vals))
for (auto&& v : r) for (auto&& v : r)
if (v) if (v)
return false; return false;
......
...@@ -82,10 +82,9 @@ namespace mln ...@@ -82,10 +82,9 @@ namespace mln
static_assert(mln::is_a<OutputImage, Image>()); static_assert(mln::is_a<OutputImage, Image>());
static_assert(std::is_convertible_v<image_value_t<InputImage>, image_value_t<OutputImage>>); static_assert(std::is_convertible_v<image_value_t<InputImage>, image_value_t<OutputImage>>);
auto input_rows = ranges::rows(src.new_pixels()); auto&& pixels = src.new_pixels();
for (auto row : ranges::rows(pixels))
for (auto r : input_rows) for (auto px : row)
for (auto px : r)
dest(px.point()) = px.val(); dest(px.point()) = px.val();
} }
......
...@@ -122,9 +122,9 @@ namespace mln ...@@ -122,9 +122,9 @@ namespace mln
mln_entering("mln::experimental::transform"); mln_entering("mln::experimental::transform");
mln_precondition(in.domain() == out.domain()); mln_precondition(in.domain() == out.domain());
auto input_rows = ranges::rows(in.new_values()); auto&& ivals = in.new_values();
auto output_rows = ranges::rows(out.new_values()); auto&& ovals = out.new_values();
for (auto [r1, r2] : ranges::view::zip(input_rows, output_rows)) for (auto [r1, r2] : ranges::view::zip(ranges::rows(ivals), ranges::rows(ovals)))
::ranges::transform(r1, ::ranges::begin(r2), f); ::ranges::transform(r1, ::ranges::begin(r2), f);
} }
......
...@@ -23,7 +23,6 @@ namespace mln::concepts ...@@ -23,7 +23,6 @@ namespace mln::concepts
requires(const Dom cdom, ::ranges::range_value_t<Dom> p) { requires(const Dom cdom, ::ranges::range_value_t<Dom> p) {
{ cdom.has(p) } -> bool; { cdom.has(p) } -> bool;
{ cdom.empty() } -> bool; { cdom.empty() } -> bool;
// { cdom.size() } -> stl::UnsignedIntegral&&;
}; };
......
#pragma once
#include <mln/core/image/private/image_traits.hpp>
#include <mln/core/rangev3/view/filter.hpp>
#include <range/v3/begin_end.hpp>
#include <range/v3/empty.hpp>
#include <utility>
namespace mln::detail
{
template <typename I, typename F>
struct filtered
{
using value_type = image_value_t<I>;
using reference = image_reference_t<I>;
filtered(I ima, F f)
: rng_(mln::ranges::view::filter(ima.domain(), f))
, ima_(ima)
, f_(f)
{
}
auto begin() { return ::ranges::begin(rng_); }
auto end() { return ::ranges::end(rng_); }
bool has(value_type p) const { return f_(ima_(p)); }
bool empty() const { return ::ranges::empty(rng_); }
private:
using rng_t = decltype(mln::ranges::view::filter(std::declval<I>().domain(), std::declval<F>()));
rng_t rng_;
I ima_;
F f_;
};
} // namespace mln::detail
...@@ -18,7 +18,7 @@ namespace mln ...@@ -18,7 +18,7 @@ namespace mln
friend ::ranges::range_access; friend ::ranges::range_access;
using pixel_range_type = decltype(std::declval<I&>().new_pixels()); using pixel_range_type = decltype(std::declval<I&>().new_pixels());
mutable I m_ima; mutable I m_ima; // required because has/empty required to be const.
pixel_range_type m_pixels; pixel_range_type m_pixels;
struct cursor struct cursor
......
#pragma once #pragma once
#include <mln/core/image/image.hpp> #include <mln/core/image/image.hpp>
#include <mln/core/image/private/filtered.hpp>
#include <mln/core/image/view/adaptor.hpp> #include <mln/core/image/view/adaptor.hpp>
#include <mln/core/image/view/clip.hpp>
#include <mln/core/rangev3/view/filter.hpp> #include <mln/core/rangev3/view/filter.hpp>
#include <mln/core/rangev3/view/remove_if.hpp>
#include <range/v3/empty.hpp> #include <range/v3/empty.hpp>
#include <range/v3/size.hpp> #include <range/v3/size.hpp>
...@@ -24,25 +25,58 @@ namespace mln ...@@ -24,25 +25,58 @@ namespace mln
public: public:
/// Type definitions /// Type definitions
/// \{ /// \{
using typename filter_view::image_adaptor::new_pixel_type; using new_pixel_type = image_pixel_t<I>;
using typename filter_view::image_adaptor::point_type; using typename filter_view::image_adaptor::point_type;
using typename filter_view::image_adaptor::reference; using typename filter_view::image_adaptor::reference;
using typename filter_view::image_adaptor::value_type; using typename filter_view::image_adaptor::value_type;
using domain_type = detail::filtered<I, F>;
class domain_type : ::ranges::view_base
{
using fun_t = ::ranges::composed<F, std::reference_wrapper<I>>; // f o I::operator()
using dom_t = decltype(std::declval<I*>()->domain());
using rng_t = mln::ranges::remove_if_view<::ranges::view::all_t<dom_t>, ::ranges::logical_negate<fun_t>>;
fun_t m_fun;
dom_t m_dom;
mutable rng_t m_rng; // domain can be a range, so non-const
static_assert(::ranges::ForwardRange<rng_t>());
static_assert(::ranges::View<::ranges::view::all_t<dom_t>>());
public:
using value_type = ::ranges::range_value_t<rng_t>;
using reference = ::ranges::range_reference_t<rng_t>;
domain_type(I* ima, F f)
: m_fun(std::move(f), std::ref(*ima))
, m_dom(ima->domain())
, m_rng(mln::ranges::view::filter(::ranges::view::all(m_dom), m_fun))
{
}
auto begin() const { return ::ranges::begin(m_rng); }
auto end() const { return ::ranges::end(m_rng); }
bool has(point_type p) const { return m_dom.has(p) && m_fun(p); }
bool empty() const { return ::ranges::empty(m_rng); }
};
/// \} /// \}
/// Traits & Image Properties /// Traits & Image Properties
/// \{ /// \{
using accessible = image_accessible_t<I>; using accessible = image_accessible_t<I>;
using indexable = std::false_type; using indexable = image_indexable_t<I>;
using view = std::true_type; using view = std::true_type;
// May be too restrictive (might be extended by image) // May be too restrictive (might be extended by image)
using extension_category = mln::extension::none_extension_tag; using extension_category = mln::extension::none_extension_tag;
using concrete_type = void; // This image has no automatic concrete type using concrete_type = clip_view<image_concrete_t<I>, domain_type>;
template <class V> template <class V>
using ch_value_type = void; // This image has no automatic concrete type using ch_value_type = clip_view<image_ch_value_t<I, V>, domain_type>;
/// \} /// \}
// Checks
PYLENE_CONCEPT_TS_ASSERT(mln::concepts::AccessibleImage<I>, "The image must be accessible.");
private: private:
struct pix_filter_fn struct pix_filter_fn
...@@ -56,6 +90,7 @@ namespace mln ...@@ -56,6 +90,7 @@ namespace mln
} }
}; };
public: public:
filter_view(I ima, F fun) filter_view(I ima, F fun)
: filter_view::image_adaptor{std::move(ima)} : filter_view::image_adaptor{std::move(ima)}
...@@ -63,8 +98,18 @@ namespace mln ...@@ -63,8 +98,18 @@ namespace mln
{ {
} }
domain_type domain() const { return detail::filtered{this->base(), this->f}; } internal::initializer<concrete_type, clip_view<I, domain_type>> concretize() const
{
return mln::clip_view{this->base(), domain()};
}
template <typename V>
internal::initializer<ch_value_type<V>, clip_view<I, domain_type>> ch_value() const
{
return mln::clip_view{this->base(), domain()};
}
domain_type domain() const { return {const_cast<I*>(&this->base()), this->f}; }
auto new_values() { return mln::ranges::view::filter(this->base().new_values(), f); } auto new_values() { return mln::ranges::view::filter(this->base().new_values(), f); }
...@@ -75,6 +120,16 @@ namespace mln ...@@ -75,6 +120,16 @@ namespace mln
} }
/// Indexable-image related methods
/// \{
template <typename dummy = I>
reference operator[](image_index_t<dummy> i)
{
return this->base()[i];
}
/// \}
/// Accessible-image related methods /// Accessible-image related methods
/// \{ /// \{
template <typename Ret = reference> template <typename Ret = reference>
...@@ -104,6 +159,28 @@ namespace mln ...@@ -104,6 +159,28 @@ namespace mln
/// \} /// \}
/// IndexableAndAccessible-image related methods
/// \{
template <typename dummy = I>
std::enable_if_t<(indexable::value && accessible::value), image_index_t<dummy>> index_of_point(point_type p) const
{
return this->base().index_of_point(p);
}
template <typename dummy = I>
point_type point_at_index(std::enable_if_t<(indexable::value && accessible::value), image_index_t<dummy>> i) const
{
return this->base().point_at_index(i);
}
template <typename dummy = I>
std::enable_if_t<(indexable::value && accessible::value), image_index_t<dummy>> delta_index(point_type p) const
{
return this->base().delta_index(p);
}
/// \}
/// Raw-image related methods /// Raw-image related methods
/// \{ /// \{
auto data() const = delete; auto data() const = delete;
......
...@@ -23,8 +23,11 @@ ...@@ -23,8 +23,11 @@
if (bool __mln_has_been_broken = false; false) \ if (bool __mln_has_been_broken = false; false) \
{ \ { \
} \ } \
else if (auto&& __mln_rng = RNG; false) \
{ \
} \
else \ else \
for (auto&& __mln_inner_rng : mln::ranges::rows(RNG)) \ for (auto&& __mln_inner_rng : mln::ranges::rows(__mln_rng)) \
if (__mln_has_been_broken) \ if (__mln_has_been_broken) \
break; \ break; \
else \ else \
......
...@@ -15,6 +15,7 @@ namespace mln::ranges ...@@ -15,6 +15,7 @@ namespace mln::ranges
template <class R, typename = std::enable_if_t<is_segmented_range_v<std::remove_reference_t<R>>>> template <class R, typename = std::enable_if_t<is_segmented_range_v<std::remove_reference_t<R>>>>
decltype(auto) rows(R&& rng) // decltype for perfect forwarding decltype(auto) rows(R&& rng) // decltype for perfect forwarding
{ {
static_assert(std::is_lvalue_reference<R>(), "Cannot apply on a temporary range.");