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.
:class: full
+-----------------------------------------------------------+--------------------------------------------------------------------------------------------+
| :cpp:func:`view::transform(ima,f) <mln::view::transform>` | Views the image with values applied to a function. |
+-----------------------------------------------------------+--------------------------------------------------------------------------------------------+
| ``view::filter(ima, pred)`` | Views the image restricted to pixels with values passing a predicate. |
+-----------------------------------------------------------+--------------------------------------------------------------------------------------------+
| ``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::zip(ima1, ima2, ..., imaN)`` | Views a list of images as a single image where values are tuples of the each image values. |
+-----------------------------------------------------------+--------------------------------------------------------------------------------------------+
+------------------------------------------------------------+--------------------------------------------------------------------------------------------+
| :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 whose values pass a predicate. |
+------------------------------------------------------------+--------------------------------------------------------------------------------------------+
| ``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::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)
......
......@@ -9,7 +9,7 @@ Include :file:`<mln/core/image/view/transform.hpp>`
#. .. 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))`
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
......
......@@ -66,7 +66,8 @@ namespace mln
static_assert(mln::is_a<InputImage, Image>());
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)
a.take(v);
return ex(a);
......@@ -78,7 +79,8 @@ namespace mln
{
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)
init = op(init, v);
......
......@@ -29,7 +29,8 @@ namespace mln
static_assert(mln::is_a<InputImage, Image>());
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))
return false;
return true;
......@@ -42,7 +43,8 @@ namespace mln
static_assert(mln::is_a<InputImage, Image>());
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)
if (!v)
return false;
......
......@@ -29,7 +29,8 @@ namespace mln
static_assert(mln::is_a<InputImage, Image>());
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))
return true;
return false;
......@@ -41,7 +42,8 @@ namespace mln
static_assert(mln::is_a<InputImage, Image>());
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)
if (v)
return true;
......
......@@ -113,10 +113,10 @@ namespace mln
static_assert(mln::is_a<OutputImage, Image>());
static_assert(std::is_convertible_v<image_value_t<InputImage>, image_value_t<OutputImage>>);
auto input_rows = ranges::rows(input.new_values());
auto output_rows = ranges::rows(output.new_values());
auto&& ivals = input.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));
}
} // namespace experimental
......
......@@ -84,7 +84,8 @@ namespace mln
{
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);
}
} // namespace experimental
......
......@@ -29,7 +29,8 @@ namespace mln
static_assert(mln::is_a<InputImage, Image>());
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);
}
} // namespace experimental
......
......@@ -23,7 +23,8 @@ namespace mln
static_assert(mln::is_a<OutputImage, Image>());
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)
v = g();
}
......
......@@ -73,7 +73,8 @@ namespace mln
static_assert(mln::is_a<OutputImage, Image>());
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)
v = val++;
}
......
......@@ -29,7 +29,8 @@ namespace mln
static_assert(mln::is_a<InputImage, Image>());
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))
return false;
return true;
......@@ -41,7 +42,8 @@ namespace mln
static_assert(mln::is_a<InputImage, Image>());
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)
if (v)
return false;
......
......@@ -82,10 +82,9 @@ namespace mln
static_assert(mln::is_a<OutputImage, Image>());
static_assert(std::is_convertible_v<image_value_t<InputImage>, image_value_t<OutputImage>>);
auto input_rows = ranges::rows(src.new_pixels());
for (auto r : input_rows)
for (auto px : r)
auto&& pixels = src.new_pixels();
for (auto row : ranges::rows(pixels))
for (auto px : row)
dest(px.point()) = px.val();
}
......
......@@ -122,9 +122,9 @@ namespace mln
mln_entering("mln::experimental::transform");
mln_precondition(in.domain() == out.domain());
auto input_rows = ranges::rows(in.new_values());
auto output_rows = ranges::rows(out.new_values());
for (auto [r1, r2] : ranges::view::zip(input_rows, output_rows))
auto&& ivals = in.new_values();
auto&& ovals = out.new_values();
for (auto [r1, r2] : ranges::view::zip(ranges::rows(ivals), ranges::rows(ovals)))
::ranges::transform(r1, ::ranges::begin(r2), f);
}
......
......@@ -23,7 +23,6 @@ namespace mln::concepts
requires(const Dom cdom, ::ranges::range_value_t<Dom> p) {
{ cdom.has(p) } -> 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
friend ::ranges::range_access;
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;
struct cursor
......
#pragma once
#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/clip.hpp>
#include <mln/core/rangev3/view/filter.hpp>
#include <mln/core/rangev3/view/remove_if.hpp>
#include <range/v3/empty.hpp>
#include <range/v3/size.hpp>
......@@ -24,25 +25,58 @@ namespace mln
public:
/// 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::reference;
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
/// \{
using accessible = image_accessible_t<I>;
using indexable = std::false_type;
using indexable = image_indexable_t<I>;
using view = std::true_type;
// May be too restrictive (might be extended by image)
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>
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:
struct pix_filter_fn
......@@ -56,6 +90,7 @@ namespace mln
}
};
public:
filter_view(I ima, F fun)
: filter_view::image_adaptor{std::move(ima)}
......@@ -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); }
......@@ -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
/// \{
template <typename Ret = reference>
......@@ -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
/// \{
auto data() const = delete;
......
......@@ -23,8 +23,11 @@
if (bool __mln_has_been_broken = false; false) \
{ \
} \
else if (auto&& __mln_rng = RNG; false) \
{ \
} \
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) \
break; \
else \
......
......@@ -15,6 +15,7 @@ namespace mln::ranges
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
{
static_assert(std::is_lvalue_reference<R>(), "Cannot apply on a temporary range.");
return rng.rows();
}
......
......@@ -33,7 +33,7 @@ namespace mln::ranges
private:
using base_t = ::ranges::remove_if_view<Rng, Pred>;
::ranges::semiregular_t<Pred> get_pred() const
auto get_pred() const
{
return reinterpret_cast<const details::remove_if_view_access<Rng, Pred>*>(this)
->details::template remove_if_view_access<Rng, Pred>::box::get();
......@@ -51,8 +51,8 @@ namespace mln::ranges
auto rows() const
#endif
{
auto f = [this](auto row) {
return remove_if_view<decltype(row), Pred>(std::forward<decltype(row)>(row), this->get_pred());
auto f = [pred_ = this->get_pred()](auto row) {
return remove_if_view<decltype(row), Pred>(std::forward<decltype(row)>(row), pred_);
};
return view::transform(this->base().rows(), f);
}
......
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