// // Copyright 2005-2007 Adobe Systems Incorporated // // Distributed under the Boost Software License, Version 1.0 // See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt // #ifndef BOOST_GIL_EXTENSION_DYNAMIC_IMAGE_GIL_REDUCE_HPP #define BOOST_GIL_EXTENSION_DYNAMIC_IMAGE_GIL_REDUCE_HPP #ifdef BOOST_GIL_DOXYGEN_ONLY #undef BOOST_GIL_REDUCE_CODE_BLOAT #endif #ifdef BOOST_GIL_REDUCE_CODE_BLOAT #include #include #include #include #include #include #include #include #include #include #include #include #include // Max number of cases in the cross-expension of binary operation for it to be reduced as unary #define GIL_BINARY_REDUCE_LIMIT 226 namespace boost { namespace mpl { // Constructs for static-to-dynamic integer convesion /////////////////////////////////////////////////////// /// Mapping vector - represents the mapping of one type vector to another /// It is not a full-blown Boost.MP11-compatible list; just has at_c and size implemented /// /// SrcTypes, DstTypes: Boost.MP11-compatible list /// /// Implements size and at_c to behave as if this is an Boost.MP11-compatible list of integers /////////////////////////////////////////////////////// template struct mapping_vector {}; template struct at_c, K> { static const std::size_t value=size::value - order::type>::value +1; using type = size_t; }; template struct size> { using type = typename size::type; static const std::size_t value=type::value; }; /////////////////////////////////////////////////////// /// copy_to_vector - copies a sequence (mpl::set) to vector. /// /// Temporary solution because I couldn't get mpl::copy to do this. /// This is what I tried: /// mpl::copy>>::type; /// It works when SET is mpl::vector, but not when SET is mpl::set... /////////////////////////////////////////////////////// namespace detail { template struct copy_to_vector_impl { private: using T = typename deref::type; using next = typename next::type; using rest = typename copy_to_vector_impl::type; public: using type = typename push_front::type; }; template struct copy_to_vector_impl { using type = vector::type>; }; } template struct copy_to_vector { using type = typename detail::copy_to_vector_impl::type, size::value>::type; }; template <> struct copy_to_vector> { using type = vector0<>; }; } } // boost::mpl namespace boost { namespace gil { /////////////////////////////////////////////////////// /// /// unary_reduce, binary_reduce - given an MPL Random Access Sequence, /// dynamically specified index to that container, the bits of an instance of the corresponding type and /// a generic operation, invokes the operation on the given type /// /////////////////////////////////////////////////////// /////////////////////////////////////////////////////// /// /// \brief Unary reduce. /// /// Given a set of types and an operation, reduces each type in the set (to reduced_t), then removes duplicates (to unique_t) /// To apply the operation, first constructs a lookup table that maps each element from Types to its place in unique_t and uses it to map /// the index to anther index (in map_index). Then invokes apply_operation_base on the unique types with the new index. /// /////////////////////////////////////////////////////// template struct unary_reduce_impl { using reduced_t = typename mpl::transform >::type; using unique_t = typename mpl::copy, mpl::insert>>::type; static const bool is_single=mpl::size::value==1; }; template ::is_single> struct unary_reduce : public unary_reduce_impl { using reduced_t = typename unary_reduce_impl::reduced_t; using unique_t = typename unary_reduce_impl::unique_t; static unsigned short inline map_index(std::size_t index) { using indices_t = typename mpl::mapping_vector; return gil::at_c(index); } template BOOST_FORCEINLINE static typename Op::result_type applyc(const Bits& bits, std::size_t index, Op op) { return apply_operation_basec(bits,map_index(index),op); } template BOOST_FORCEINLINE static typename Op::result_type apply(Bits& bits, std::size_t index, Op op) { return apply_operation_base(bits,map_index(index),op); } }; template struct unary_reduce : public unary_reduce_impl { using unique_t = typename unary_reduce_impl::unique_t; static unsigned short inline map_index(std::size_t index) { return 0; } template BOOST_FORCEINLINE static typename Op::result_type applyc(const Bits& bits, std::size_t index, Op op) { return op(*gil_reinterpret_cast_c::type*>(&bits)); } template BOOST_FORCEINLINE static typename Op::result_type apply(Bits& bits, std::size_t index, Op op) { return op(*gil_reinterpret_cast::type*>(&bits)); } }; /////////////////////////////////////////////////////// /// /// \brief Binary reduce. /// /// Given two sets of types, Types1 and Types2, first performs unary reduction on each. Then checks if the product of their sizes is above /// the GIL_BINARY_REDUCE_LIMIT limit. If so, the operation is too complex to be binary-reduced and uses a specialization of binary_reduce_impl /// to simply call the binary apply_operation_base (which performs two nested 1D apply operations) /// If the operation is not too complex, uses the other specialization of binary_reduce_impl to create a cross-product of the input types /// and performs unary reduction on the result (bin_reduced_t). To apply the binary operation, it simply invokes a unary apply_operation_base /// on the reduced cross-product types /// /////////////////////////////////////////////////////// namespace detail { struct pair_generator { template struct apply { using type = std::pair::type*, const typename mpl::at_c::type*>; }; }; // When the types are not too large, applies reduce on their cross product template struct binary_reduce_impl { //private: using vec1_types = typename mpl::copy_to_vector::type; using vec2_types = typename mpl::copy_to_vector::type; using BIN_TYPES = mpl::cross_vector, pair_generator>; using bin_reduced_t = unary_reduce; static unsigned short inline map_index(std::size_t index1, std::size_t index2) { unsigned short r1=Unary1::map_index(index1); unsigned short r2=Unary2::map_index(index2); return bin_reduced_t::map_index(r2*mpl::size::value + r1); } public: using unique_t = typename bin_reduced_t::unique_t template static typename Op::result_type inline apply(const Bits1& bits1, std::size_t index1, const Bits2& bits2, std::size_t index2, Op op) { std::pair pr(&bits1, &bits2); return apply_operation_basec(pr, map_index(index1,index2),op); } }; // When the types are large performs a double-dispatch. Binary reduction is not done. template struct binary_reduce_impl { template static typename Op::result_type inline apply(const Bits1& bits1, std::size_t index1, const Bits2& bits2, std::size_t index2, Op op) { return apply_operation_base(bits1, index1, bits2, index2, op); } }; } template struct binary_reduce { //private: using unary1_t = unary_reduce; using unary2_t = unary_reduce; static const std::size_t CROSS_SIZE = mpl::size::value * mpl::size::value; using impl = detail::binary_reduce_implGIL_BINARY_REDUCE_LIMIT)>; public: template static typename Op::result_type inline apply(const Bits1& bits1, std::size_t index1, const Bits2& bits2, std::size_t index2, Op op) { return impl::apply(bits1,index1,bits2,index2,op); } }; template BOOST_FORCEINLINE typename UnaryOp::result_type apply_operation(variant& arg, UnaryOp op) { return unary_reduce::template apply(arg._bits, arg._index ,op); } template BOOST_FORCEINLINE typename UnaryOp::result_type apply_operation(const variant& arg, UnaryOp op) { return unary_reduce::template applyc(arg._bits, arg._index ,op); } template BOOST_FORCEINLINE typename BinaryOp::result_type apply_operation(const variant& arg1, const variant& arg2, BinaryOp op) { return binary_reduce::template apply(arg1._bits, arg1._index, arg2._bits, arg2._index, op); } #undef GIL_BINARY_REDUCE_LIMIT } } // namespace gil namespace boost { namespace mpl { /////////////////////////////////////////////////////// /// \brief Represents the virtual cross-product of the types generated from VecOfVecs. /// \ingroup CrossVector /// INPUT: /// VecOfVecs - a vector of vector types. For example [ [A1,A2,A3], [B1,B2], [C1,C2,C3,C4] ] /// Each element must be a non-empty mpl vector /// TypeGen - a metafunction that generates a type from a vector of types, each of which can be /// selected from the corresponding vector in VecOfVecs. For example, [A1, B2, C4] /// /// Represents the virtual cross-product of the types generated from VecOfVecs. /// For example, [ TypeGen[A1,B1,C1], TypeGen[A2,B1,C1], TypeGen[A3,B1,C1], /// TypeGen[A1,B2,C1], TypeGen[A2,B2,C1], TypeGen[A3,B2,C1], /// TypeGen[A1,B1,C2], TypeGen[A2,B1,C2], TypeGen[A3,B1,C2], ... ] /// /// Models an immutable MPL Random Access Sequence /// Traversal, random-access, etc, is defined, but mutable operations, /// such as push_back and pop_front are not supported /////////////////////////////////////////////////////// template struct cross_vector {}; /// \brief Iterator of cross_vector /// \ingroup CrossVectorIterator template struct cross_iterator { using category = mpl::random_access_iterator_tag; }; /////////////////////////////////////////////////////// /// Implementation of the iterator functions of cross vector /////////////////////////////////////////////////////// /// \brief Dereferences a cross-vector iterator /// \ingroup CrossVectorIterator /// Creates a vector of the sizes of each type vector in VecOfVecs, then uses it as a basis /// to represent the iterator's position K as a vector of indices. Extracts the corresponding type of /// each input vector and passes the element types to the type generation function, which returns the dereferenced type template struct deref> { private: using DerefTypes = typename detail::select_subvector_c::type; public: using type = typename TypeGen::template apply::type; }; /// \brief Increments a cross-vector iterator. /// \ingroup CrossVectorIterator template struct next> { using type = cross_iterator; }; /// \brief Decrements a cross-vector iterator. /// \ingroup CrossVectorIterator template struct prior> { using type = cross_iterator; }; /// \brief Advances a cross-vector iterator. /// \ingroup CrossVectorIterator template struct advance, Distance> { using type = cross_iterator; }; /// \brief Computes the distance between two cross-vector iterator-s. /// \ingroup CrossVectorIterator // (shortened the names of the template arguments - otherwise doxygen cannot parse this...) template struct distance, cross_iterator> { using type = size_t; }; /////////////////////////////////////////////////////// /// Implementation of cross vector /////////////////////////////////////////////////////// /// \brief Computes the size of a cross vector as the product of the sizes of all vectors in VecOfVecs /// \ingroup CrossVector template struct size> { using type = typename fold, times<_1, size<_2>>>::type; static const std::size_t value=type::value; }; /// \brief Determines whether a cross vector is empty /// \ingroup CrossVector template struct empty> { using type = typename empty::type; }; /// \brief Returns the K-th element of a cross vector /// \ingroup CrossVector template struct at, K> { private: using KthIterator = cross_iterator; public: using type = typename deref::type; }; /// \brief Returns an iterator to the first element of a cross vector /// \ingroup CrossVector template struct begin> { using type = cross_iterator; }; /// \brief Returns an iterator to the last element of a cross vector /// \ingroup CrossVector template struct end> { private: using this_t = cross_vector; public: using type = cross_iterator::value>; }; /// \brief Returns the first element of a cross vector /// \ingroup CrossVector template struct front> { private: using this_t = cross_vector; public: using type = typename deref::type>::type; }; /// \brief Returns the last element of a cross vector /// \ingroup CrossVector template struct back> { private: using this_t = cross_vector; using size = typename size::type; using last_index = typename minus>::type; public: using type = typename at::type; }; /// \brief Transforms the elements of a cross vector /// \ingroup CrossVector template struct transform, OPP> { using Op = typename lambda::type; struct adapter { template struct apply { using orig_t = typename TypeGen::template apply::type; using type = typename Op::template apply::type; }; }; using type = cross_vector; }; } } // boost::mpl namespace boost { namespace gil { template struct type_to_index; template struct view_is_basic; struct rgb_t; struct lab_t; struct hsb_t; struct cmyk_t; struct rgba_t; struct error_t; namespace detail { //////////////////////////////////////////////////////// //// //// Generic reduce operation //// //////////////////////////////////////////////////////// template struct reduce { using type = T; }; //////////////////////////////////////////////////////// //// //// Unary reduce_view operation. Splits into basic and non-basic views. //// Algorithm-specific reduce should specialize for basic views //// //////////////////////////////////////////////////////// template struct reduce_view_basic { using type = View; }; template struct reduce> : public reduce_view_basic,view_is_basic>::value> {}; //////////////////////////////////////////////////////// //// //// Unary reduce_image operation. Splits into basic and non-basic images. //// Algorithm-specific reduce should specialize for basic images //// //////////////////////////////////////////////////////// template struct reduce_image_basic { using type = Img; }; template struct reduce> : public reduce_image_basic,image_is_basic>::value > {}; //////////////////////////////////////////////////////// //// //// Binary reduce_view operation. Splits into basic and non-basic views. //// Algorithm-specific reduce should specialize for basic views //// //////////////////////////////////////////////////////// template struct reduce_views_basic { using type = std::pair; }; template struct reduce*, const image_view*>> : public reduce_views_basic,image_view, mpl::and_>, view_is_basic>>::value > {}; //////////////////////////////////////////////////////// //// //// Color space unary reduce operation. Reduce a color space to a base with the same number of channels //// //////////////////////////////////////////////////////// template struct reduce_color_space { using type = CS; }; template <> struct reduce_color_space { using type = rgb_t; }; template <> struct reduce_color_space { using type = rgb_t; }; template <> struct reduce_color_space { using type = rgba_t; }; /* //////////////////////////////////////////////////////// //// //// Color space binary reduce operation. Given a source and destination color spaces, //// returns a reduced source and destination color spaces that have the same mapping of channels //// //// Precondition: The two color spaces must be compatible (i.e. must have the same set of channels) //////////////////////////////////////////////////////// template struct type_vec_to_integer_impl { using last = typename mpl::back::type; using rest = typename mpl::pop_back::type; static const int value = type_vec_to_integer_impl::value * Basis + last::value; }; template struct type_vec_to_integer_impl { static const int value=0; }; template struct type_vec_to_integer { static const int value = type_vec_to_integer_impl::value>::value; }; // Given two color spaces and the mapping of the channels between them, returns the reduced pair of color spaces // The default version performs no reduction template struct reduce_color_spaces_impl { using first_t = SrcColorSpace; using second_t = DstColorSpace; }; // 012: RGB-RGB, bgr-bgr, lab-lab, hsb-hsb template struct reduce_color_spaces_impl { using first_t = rgb_t; using second_t = rgb_t; }; // 210: RGB-bgr, bgr-RGB template struct reduce_color_spaces_impl { using first_t = rgb_t; using second_t = bgr_t; }; // 0123: RGBA-RGBA, bgra-bgra, argb-argb, abgr-abgr cmyk-cmyk template struct reduce_color_spaces_impl { using first_t = rgba_t; using second_t = rgba_t; }; // 3210: RGBA-abgr, bgra-argb, argb-bgra, abgr-RGBA template struct reduce_color_spaces_impl { using first_t = rgba_t; using second_t = abgr_t; }; // 1230: RGBA-argb, bgra-abgr template struct reduce_color_spaces_impl { using first_t = rgba_t; using second_t = argb_t; }; // 2103: RGBA-bgra, bgra-RGBA (uses subclass to ensure that base color space is not reduced to derived) template struct reduce_color_spaces_impl { using first_t = rgba_t; using second_t = bgra_t; }; // 3012: argb-RGBA, abgr-bgra template struct reduce_color_spaces_impl { using first_t = argb_t; using second_t = rgba_t; }; // 0321: argb-abgr, abgr-argb template struct reduce_color_spaces_impl { using first_t = argb_t; using second_t = abgr_t; }; template struct reduce_color_spaces { using src_order_t = typename channel_order::type; using dst_order_t = typename channel_order::type; using mapping = typename mpl::transform>::type; static const int mapping_val = type_vec_to_integer::value; using _first_t = typename reduce_color_spaces_impl::first_t; using _second_t = typename reduce_color_spaces_impl::second_t; using swap_t = typename mpl::and_, mpl::not_< color_space_is_base<_second_t>>>; public: using first_t = typename mpl::if_::type; using second_t = typename mpl::if_::type; }; */ // TODO: Use the old code for reduce_color_spaces above to do color layout reduction template struct reduce_color_layouts { using first_t = SrcLayout; using second_t = DstLayout; }; //////////////////////////////////////////////////////// //// //// Reduce for copy_pixels //// //////////////////////////////////////////////////////// struct copy_pixels_fn; /* // 1D reduce for copy_pixels reduces the channel to mutable and the color space to its base with same dimensions template struct reduce_view_basic { private: using color_space_t = typename reduce_color_space::type color_space_t; // reduce the color space using layout_t = layout; public: using type = typename derived_view_type::type; }; */ // Incompatible views cannot be used in copy_pixels - will throw std::bad_cast template struct reduce_copy_pixop_compat { using type = error_t; }; // For compatible basic views, reduce their color spaces based on their channel mapping. // Make the source immutable and the destination mutable (they should already be that way) template struct reduce_copy_pixop_compat { using layout1 = layout; using layout2 = layout; using L1 = typename reduce_color_layouts::first_t; using L2 = typename reduce_color_layouts::second_t; using DV1 = typename derived_view_type::type; using DV2 = typename derived_view_type::type; using type = std::pair; }; // The general 2D version branches into compatible and incompatible views template struct reduce_views_basic : public reduce_copy_pixop_compat, view_is_mutable>::value > { }; //////////////////////////////////////////////////////// //// //// Reduce for variant destructor (basic views have no destructor) //// //////////////////////////////////////////////////////// struct destructor_op; template struct reduce_view_basic { using type = gray8_view_t; }; //////////////////////////////////////////////////////// //// //// Reduce for get_dimensions (basic views and images have the same structure and the dimensions are contained at the beginning) //// //////////////////////////////////////////////////////// struct any_type_get_dimensions; template struct reduce_view_basic { using type = gray8_view_t; }; template struct reduce_image_basic { using type = gray8_image_t; }; //////////////////////////////////////////////////////// //// //// Reduce for get_num_channels (only color space matters) //// //////////////////////////////////////////////////////// struct any_type_get_num_channels; template struct reduce_view_basic { using color_space_t = typename View::color_space_t::base; using type = typename view_type::type>::type; }; template struct reduce_image_basic { using color_space_t = typename Img::color_space_t::base; using type = typename image_type::type>::type; }; //////////////////////////////////////////////////////// //// //// Reduce for resample_pixels (same as copy_pixels) //// //////////////////////////////////////////////////////// template struct resample_pixels_fn; template struct reduce_view_basic, V, IsBasic> : public reduce_view_basic {}; template struct reduce_views_basic, V1, V2, IsBasic> : public reduce_views_basic {}; //////////////////////////////////////////////////////// //// //// Reduce for copy_and_convert_pixels //// (the only reduction could be made when views are compatible and have the same mapping, planarity and stepness) //// //////////////////////////////////////////////////////// template class copy_and_convert_pixels_fn; // the only thing for 1D reduce is making them all mutable... template struct reduce_view_basic, View, IsBasic> : public derived_view_type { }; // For 2D reduce, if they have the same channels and color spaces (i.e. the same pixels) then copy_and_convert is just copy. // In this case, reduce their common color space. In general make the first immutable and the second mutable template struct reduce_views_basic, V1, V2, AreBasic> { using Same = std::is_same; using CsR = reduce_color_space; using Cs1 = typename mpl::if_::type; using Cs2 = typename mpl::if_::type; using DV1 = typename derived_view_type, use_default, use_default, mpl::false_>::type; using DV2 = typename derived_view_type, use_default, use_default, mpl::true_ >::type; using type = std::pair; }; //integral_image_generator //resize_clobber_image_fnobj //image_default_construct_fnobj //fill_converted_pixels_fn //std::bind(gil::detail::copy_pixels_fn(), std::placeholders::_1, dst) //std::bind(gil::detail::copy_pixels_fn(), src, std::placeholders::_1) //std::bind(detail::copy_and_convert_pixels_fn(), std::placeholders::_1, dst) //std::bind(detail::copy_and_convert_pixels_fn(), src, std::placeholders::_1) //gil::detail::fill_pixels_fn(val) //detail::copy_construct_in_place_fn //detail::equal_to_fn::base_t> //detail::any_image_get_view::view_t> //detail::any_image_get_const_view::view_t> //detail::flipped_up_down_view_fn> //detail::flipped_left_right_view_fn::dynamic_step_t> //detail::tranposed_view_fn::dynamic_step_t> //detail::rotated90cw_view_fn::dynamic_step_t> //detail::rotated90ccw_view_fn::dynamic_step_t> //detail::rotated180_view_fn::dynamic_step_t> //detail::subimage_view_fn> //detail::subsampled_view_fn::dynamic_step_t> //detail::nth_channel_view_fn> //detail::color_converted_view_fn, DstP>::type > } }} // namespace boost::gil #endif // defined(BOOST_GIL_REDUCE_CODE_BLOAT) #endif