reduce.hpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834
  1. //
  2. // Copyright 2005-2007 Adobe Systems Incorporated
  3. //
  4. // Distributed under the Boost Software License, Version 1.0
  5. // See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt
  7. //
  8. #ifndef BOOST_GIL_EXTENSION_DYNAMIC_IMAGE_GIL_REDUCE_HPP
  9. #define BOOST_GIL_EXTENSION_DYNAMIC_IMAGE_GIL_REDUCE_HPP
  10. #ifdef BOOST_GIL_DOXYGEN_ONLY
  11. #undef BOOST_GIL_REDUCE_CODE_BLOAT
  12. #endif
  13. #ifdef BOOST_GIL_REDUCE_CODE_BLOAT
  14. #include <boost/gil/extension/dynamic_image/dynamic_at_c.hpp>
  15. #include <boost/gil/metafunctions.hpp>
  16. #include <boost/gil/typedefs.hpp>
  17. #include <boost/mpl/back.hpp>
  18. #include <boost/mpl/insert.hpp>
  19. #include <boost/mpl/insert_range.hpp>
  20. #include <boost/mpl/long.hpp>
  21. #include <boost/mpl/logical.hpp>
  22. #include <boost/mpl/range_c.hpp>
  23. #include <boost/mpl/vector.hpp>
  24. #include <boost/mpl/vector_c.hpp>
  25. #include <boost/mpl/transform.hpp>
  26. #include <type_traits>
  27. // Max number of cases in the cross-expension of binary operation for it to be reduced as unary
  28. #define GIL_BINARY_REDUCE_LIMIT 226
  29. namespace boost { namespace mpl {
  30. // Constructs for static-to-dynamic integer convesion
  31. ///////////////////////////////////////////////////////
  32. /// Mapping vector - represents the mapping of one type vector to another
  33. /// It is not a full-blown Boost.MP11-compatible list; just has at_c and size implemented
  34. ///
  35. /// SrcTypes, DstTypes: Boost.MP11-compatible list
  36. ///
  37. /// Implements size and at_c to behave as if this is an Boost.MP11-compatible list of integers
  38. ///////////////////////////////////////////////////////
  39. template <typename SrcTypes, typename DstTypes>
  40. struct mapping_vector {};
  41. template <typename SrcTypes, typename DstTypes, long K>
  42. struct at_c<mapping_vector<SrcTypes,DstTypes>, K>
  43. {
  44. static const std::size_t value=size<DstTypes>::value - order<DstTypes, typename gil::at_c<SrcTypes,K>::type>::value +1;
  45. using type = size_t<value>;
  46. };
  47. template <typename SrcTypes, typename DstTypes>
  48. struct size<mapping_vector<SrcTypes,DstTypes>>
  49. {
  50. using type = typename size<SrcTypes>::type;
  51. static const std::size_t value=type::value;
  52. };
  53. ///////////////////////////////////////////////////////
  54. /// copy_to_vector - copies a sequence (mpl::set) to vector.
  55. ///
  56. /// Temporary solution because I couldn't get mpl::copy to do this.
  57. /// This is what I tried:
  58. /// mpl::copy<SET, mpl::back_inserter<mpl::vector<>>>::type;
  59. /// It works when SET is mpl::vector, but not when SET is mpl::set...
  60. ///////////////////////////////////////////////////////
  61. namespace detail {
  62. template <typename SFirst, std::size_t NLeft>
  63. struct copy_to_vector_impl {
  64. private:
  65. using T = typename deref<SFirst>::type;
  66. using next = typename next<SFirst>::type;
  67. using rest = typename copy_to_vector_impl<next, NLeft-1>::type;
  68. public:
  69. using type = typename push_front<rest, T>::type;
  70. };
  71. template <typename SFirst>
  72. struct copy_to_vector_impl<SFirst,1>
  73. {
  74. using type = vector<typename deref<SFirst>::type>;
  75. };
  76. }
  77. template <typename Src>
  78. struct copy_to_vector
  79. {
  80. using type = typename detail::copy_to_vector_impl<typename begin<Src>::type, size<Src>::value>::type;
  81. };
  82. template <>
  83. struct copy_to_vector<set<>>
  84. {
  85. using type = vector0<>;
  86. };
  87. } } // boost::mpl
  88. namespace boost { namespace gil {
  89. ///////////////////////////////////////////////////////
  90. ///
  91. /// unary_reduce, binary_reduce - given an MPL Random Access Sequence,
  92. /// dynamically specified index to that container, the bits of an instance of the corresponding type and
  93. /// a generic operation, invokes the operation on the given type
  94. ///
  95. ///////////////////////////////////////////////////////
  96. ///////////////////////////////////////////////////////
  97. ///
  98. /// \brief Unary reduce.
  99. ///
  100. /// Given a set of types and an operation, reduces each type in the set (to reduced_t), then removes duplicates (to unique_t)
  101. /// 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
  102. /// the index to anther index (in map_index). Then invokes apply_operation_base on the unique types with the new index.
  103. ///
  104. ///////////////////////////////////////////////////////
  105. template <typename Types, typename Op>
  106. struct unary_reduce_impl {
  107. using reduced_t = typename mpl::transform<Types, detail::reduce<Op, mpl::_1> >::type;
  108. using unique_t = typename mpl::copy<reduced_t, mpl::inserter<mpl::set<>, mpl::insert<mpl::_1,mpl::_2>>>::type;
  109. static const bool is_single=mpl::size<unique_t>::value==1;
  110. };
  111. template <typename Types, typename Op, bool IsSingle=unary_reduce_impl<Types,Op>::is_single>
  112. struct unary_reduce : public unary_reduce_impl<Types,Op>
  113. {
  114. using reduced_t = typename unary_reduce_impl<Types,Op>::reduced_t;
  115. using unique_t = typename unary_reduce_impl<Types,Op>::unique_t;
  116. static unsigned short inline map_index(std::size_t index)
  117. {
  118. using indices_t = typename mpl::mapping_vector<reduced_t, unique_t>;
  119. return gil::at_c<indices_t, unsigned short>(index);
  120. }
  121. template <typename Bits> BOOST_FORCEINLINE static typename Op::result_type applyc(const Bits& bits, std::size_t index, Op op) {
  122. return apply_operation_basec<unique_t>(bits,map_index(index),op);
  123. }
  124. template <typename Bits> BOOST_FORCEINLINE static typename Op::result_type apply(Bits& bits, std::size_t index, Op op) {
  125. return apply_operation_base<unique_t>(bits,map_index(index),op);
  126. }
  127. };
  128. template <typename Types, typename Op>
  129. struct unary_reduce<Types,Op,true> : public unary_reduce_impl<Types,Op> {
  130. using unique_t = typename unary_reduce_impl<Types,Op>::unique_t;
  131. static unsigned short inline map_index(std::size_t index) { return 0; }
  132. template <typename Bits> BOOST_FORCEINLINE static typename Op::result_type applyc(const Bits& bits, std::size_t index, Op op) {
  133. return op(*gil_reinterpret_cast_c<const typename mpl::front<unique_t>::type*>(&bits));
  134. }
  135. template <typename Bits> BOOST_FORCEINLINE static typename Op::result_type apply(Bits& bits, std::size_t index, Op op) {
  136. return op(*gil_reinterpret_cast<typename mpl::front<unique_t>::type*>(&bits));
  137. }
  138. };
  139. ///////////////////////////////////////////////////////
  140. ///
  141. /// \brief Binary reduce.
  142. ///
  143. /// Given two sets of types, Types1 and Types2, first performs unary reduction on each. Then checks if the product of their sizes is above
  144. /// 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
  145. /// to simply call the binary apply_operation_base (which performs two nested 1D apply operations)
  146. /// If the operation is not too complex, uses the other specialization of binary_reduce_impl to create a cross-product of the input types
  147. /// and performs unary reduction on the result (bin_reduced_t). To apply the binary operation, it simply invokes a unary apply_operation_base
  148. /// on the reduced cross-product types
  149. ///
  150. ///////////////////////////////////////////////////////
  151. namespace detail {
  152. struct pair_generator {
  153. template <typename Vec2> struct apply
  154. {
  155. using type = std::pair<const typename mpl::at_c<Vec2,0>::type*, const typename mpl::at_c<Vec2,1>::type*>;
  156. };
  157. };
  158. // When the types are not too large, applies reduce on their cross product
  159. template <typename Unary1, typename Unary2, typename Op, bool IsComplex>
  160. struct binary_reduce_impl
  161. {
  162. //private:
  163. using vec1_types = typename mpl::copy_to_vector<typename Unary1::unique_t>::type;
  164. using vec2_types = typename mpl::copy_to_vector<typename Unary2::unique_t>::type;
  165. using BIN_TYPES = mpl::cross_vector<mpl::vector2<vec1_types, vec2_types>, pair_generator>;
  166. using bin_reduced_t = unary_reduce<BIN_TYPES,Op>;
  167. static unsigned short inline map_index(std::size_t index1, std::size_t index2) {
  168. unsigned short r1=Unary1::map_index(index1);
  169. unsigned short r2=Unary2::map_index(index2);
  170. return bin_reduced_t::map_index(r2*mpl::size<vec1_types>::value + r1);
  171. }
  172. public:
  173. using unique_t = typename bin_reduced_t::unique_t
  174. template <typename Bits1, typename Bits2>
  175. static typename Op::result_type inline apply(const Bits1& bits1, std::size_t index1, const Bits2& bits2, std::size_t index2, Op op) {
  176. std::pair<const void*,const void*> pr(&bits1, &bits2);
  177. return apply_operation_basec<unique_t>(pr, map_index(index1,index2),op);
  178. }
  179. };
  180. // When the types are large performs a double-dispatch. Binary reduction is not done.
  181. template <typename Unary1, typename Unary2, typename Op>
  182. struct binary_reduce_impl<Unary1,Unary2,Op,true> {
  183. template <typename Bits1, typename Bits2>
  184. static typename Op::result_type inline apply(const Bits1& bits1, std::size_t index1, const Bits2& bits2, std::size_t index2, Op op) {
  185. return apply_operation_base<Unary1::unique_t,Unary2::unique_t>(bits1, index1, bits2, index2, op);
  186. }
  187. };
  188. }
  189. template <typename Types1, typename Types2, typename Op>
  190. struct binary_reduce
  191. {
  192. //private:
  193. using unary1_t = unary_reduce<Types1,Op>;
  194. using unary2_t = unary_reduce<Types2,Op>;
  195. static const std::size_t CROSS_SIZE = mpl::size<typename unary1_t::unique_t>::value *
  196. mpl::size<typename unary2_t::unique_t>::value;
  197. using impl = detail::binary_reduce_impl<unary1_t,unary2_t,Op, (CROSS_SIZE>GIL_BINARY_REDUCE_LIMIT)>;
  198. public:
  199. template <typename Bits1, typename Bits2>
  200. static typename Op::result_type inline apply(const Bits1& bits1, std::size_t index1, const Bits2& bits2, std::size_t index2, Op op) {
  201. return impl::apply(bits1,index1,bits2,index2,op);
  202. }
  203. };
  204. template <typename Types, typename UnaryOp>
  205. BOOST_FORCEINLINE typename UnaryOp::result_type apply_operation(variant<Types>& arg, UnaryOp op) {
  206. return unary_reduce<Types,UnaryOp>::template apply(arg._bits, arg._index ,op);
  207. }
  208. template <typename Types, typename UnaryOp>
  209. BOOST_FORCEINLINE typename UnaryOp::result_type apply_operation(const variant<Types>& arg, UnaryOp op) {
  210. return unary_reduce<Types,UnaryOp>::template applyc(arg._bits, arg._index ,op);
  211. }
  212. template <typename Types1, typename Types2, typename BinaryOp>
  213. BOOST_FORCEINLINE typename BinaryOp::result_type apply_operation(const variant<Types1>& arg1, const variant<Types2>& arg2, BinaryOp op) {
  214. return binary_reduce<Types1,Types2,BinaryOp>::template apply(arg1._bits, arg1._index, arg2._bits, arg2._index, op);
  215. }
  216. #undef GIL_BINARY_REDUCE_LIMIT
  217. } } // namespace gil
  218. namespace boost { namespace mpl {
  219. ///////////////////////////////////////////////////////
  220. /// \brief Represents the virtual cross-product of the types generated from VecOfVecs.
  221. /// \ingroup CrossVector
  222. /// INPUT:
  223. /// VecOfVecs - a vector of vector types. For example [ [A1,A2,A3], [B1,B2], [C1,C2,C3,C4] ]
  224. /// Each element must be a non-empty mpl vector
  225. /// TypeGen - a metafunction that generates a type from a vector of types, each of which can be
  226. /// selected from the corresponding vector in VecOfVecs. For example, [A1, B2, C4]
  227. ///
  228. /// Represents the virtual cross-product of the types generated from VecOfVecs.
  229. /// For example, [ TypeGen[A1,B1,C1], TypeGen[A2,B1,C1], TypeGen[A3,B1,C1],
  230. /// TypeGen[A1,B2,C1], TypeGen[A2,B2,C1], TypeGen[A3,B2,C1],
  231. /// TypeGen[A1,B1,C2], TypeGen[A2,B1,C2], TypeGen[A3,B1,C2], ... ]
  232. ///
  233. /// Models an immutable MPL Random Access Sequence
  234. /// Traversal, random-access, etc, is defined, but mutable operations,
  235. /// such as push_back and pop_front are not supported
  236. ///////////////////////////////////////////////////////
  237. template <typename VecOfVecs, typename TypeGen>
  238. struct cross_vector {};
  239. /// \brief Iterator of cross_vector
  240. /// \ingroup CrossVectorIterator
  241. template <typename VecOfVecs, typename TypeGen, std::size_t K>
  242. struct cross_iterator
  243. {
  244. using category = mpl::random_access_iterator_tag;
  245. };
  246. ///////////////////////////////////////////////////////
  247. /// Implementation of the iterator functions of cross vector
  248. ///////////////////////////////////////////////////////
  249. /// \brief Dereferences a cross-vector iterator
  250. /// \ingroup CrossVectorIterator
  251. /// Creates a vector of the sizes of each type vector in VecOfVecs, then uses it as a basis
  252. /// to represent the iterator's position K as a vector of indices. Extracts the corresponding type of
  253. /// each input vector and passes the element types to the type generation function, which returns the dereferenced type
  254. template <typename VecOfVecs, typename TypeGen, std::size_t K>
  255. struct deref<cross_iterator<VecOfVecs,TypeGen,K>>
  256. {
  257. private:
  258. using DerefTypes = typename detail::select_subvector_c<VecOfVecs, K>::type;
  259. public:
  260. using type = typename TypeGen::template apply<DerefTypes>::type;
  261. };
  262. /// \brief Increments a cross-vector iterator.
  263. /// \ingroup CrossVectorIterator
  264. template <typename VecOfVecs, typename TypeGen, std::size_t K>
  265. struct next<cross_iterator<VecOfVecs,TypeGen,K>>
  266. {
  267. using type = cross_iterator<VecOfVecs,TypeGen,K+1>;
  268. };
  269. /// \brief Decrements a cross-vector iterator.
  270. /// \ingroup CrossVectorIterator
  271. template <typename VecOfVecs, typename TypeGen, std::size_t K>
  272. struct prior<cross_iterator<VecOfVecs,TypeGen,K>>
  273. {
  274. using type = cross_iterator<VecOfVecs,TypeGen,K-1>;
  275. };
  276. /// \brief Advances a cross-vector iterator.
  277. /// \ingroup CrossVectorIterator
  278. template <typename VecOfVecs, typename TypeGen, std::size_t K, typename Distance>
  279. struct advance<cross_iterator<VecOfVecs,TypeGen,K>, Distance>
  280. {
  281. using type = cross_iterator<VecOfVecs,TypeGen,K+Distance::value>;
  282. };
  283. /// \brief Computes the distance between two cross-vector iterator-s.
  284. /// \ingroup CrossVectorIterator
  285. // (shortened the names of the template arguments - otherwise doxygen cannot parse this...)
  286. template <typename VecOfVecs, typename TypeGen, std::size_t K1, std::size_t K2>
  287. struct distance<cross_iterator<VecOfVecs,TypeGen,K1>, cross_iterator<VecOfVecs,TypeGen,K2>>
  288. {
  289. using type = size_t<K2-K1>;
  290. };
  291. ///////////////////////////////////////////////////////
  292. /// Implementation of cross vector
  293. ///////////////////////////////////////////////////////
  294. /// \brief Computes the size of a cross vector as the product of the sizes of all vectors in VecOfVecs
  295. /// \ingroup CrossVector
  296. template <typename VecOfVecs, typename TypeGen>
  297. struct size<cross_vector<VecOfVecs,TypeGen>>
  298. {
  299. using type = typename fold<VecOfVecs, size_t<1>, times<_1, size<_2>>>::type;
  300. static const std::size_t value=type::value;
  301. };
  302. /// \brief Determines whether a cross vector is empty
  303. /// \ingroup CrossVector
  304. template <typename VecOfVecs, typename TypeGen>
  305. struct empty<cross_vector<VecOfVecs,TypeGen>> {
  306. using type = typename empty<VecOfVecs>::type;
  307. };
  308. /// \brief Returns the K-th element of a cross vector
  309. /// \ingroup CrossVector
  310. template <typename VecOfVecs, typename TypeGen, typename K>
  311. struct at<cross_vector<VecOfVecs,TypeGen>, K>
  312. {
  313. private:
  314. using KthIterator = cross_iterator<VecOfVecs,TypeGen,K::value>;
  315. public:
  316. using type = typename deref<KthIterator>::type;
  317. };
  318. /// \brief Returns an iterator to the first element of a cross vector
  319. /// \ingroup CrossVector
  320. template <typename VecOfVecs, typename TypeGen>
  321. struct begin<cross_vector<VecOfVecs,TypeGen>>
  322. {
  323. using type = cross_iterator<VecOfVecs,TypeGen,0>;
  324. };
  325. /// \brief Returns an iterator to the last element of a cross vector
  326. /// \ingroup CrossVector
  327. template <typename VecOfVecs, typename TypeGen>
  328. struct end<cross_vector<VecOfVecs,TypeGen>>
  329. {
  330. private:
  331. using this_t = cross_vector<VecOfVecs,TypeGen>;
  332. public:
  333. using type = cross_iterator<VecOfVecs,TypeGen,size<this_t>::value>;
  334. };
  335. /// \brief Returns the first element of a cross vector
  336. /// \ingroup CrossVector
  337. template <typename VecOfVecs, typename TypeGen>
  338. struct front<cross_vector<VecOfVecs,TypeGen>> {
  339. private:
  340. using this_t = cross_vector<VecOfVecs,TypeGen>;
  341. public:
  342. using type = typename deref<typename begin<this_t>::type>::type;
  343. };
  344. /// \brief Returns the last element of a cross vector
  345. /// \ingroup CrossVector
  346. template <typename VecOfVecs, typename TypeGen>
  347. struct back<cross_vector<VecOfVecs,TypeGen>>
  348. {
  349. private:
  350. using this_t = cross_vector<VecOfVecs,TypeGen>;
  351. using size = typename size<this_t>::type;
  352. using last_index = typename minus<size, size_t<1>>::type;
  353. public:
  354. using type = typename at<this_t, last_index>::type;
  355. };
  356. /// \brief Transforms the elements of a cross vector
  357. /// \ingroup CrossVector
  358. template <typename VecOfVecs, typename TypeGen, typename OPP>
  359. struct transform<cross_vector<VecOfVecs,TypeGen>, OPP>
  360. {
  361. using Op = typename lambda<OPP>::type;
  362. struct adapter
  363. {
  364. template <typename Elements>
  365. struct apply
  366. {
  367. using orig_t = typename TypeGen::template apply<Elements>::type;
  368. using type = typename Op::template apply<orig_t>::type;
  369. };
  370. };
  371. using type = cross_vector<VecOfVecs, adapter>;
  372. };
  373. } } // boost::mpl
  374. namespace boost { namespace gil {
  375. template <typename Types, typename T> struct type_to_index;
  376. template <typename V> struct view_is_basic;
  377. struct rgb_t;
  378. struct lab_t;
  379. struct hsb_t;
  380. struct cmyk_t;
  381. struct rgba_t;
  382. struct error_t;
  383. namespace detail {
  384. ////////////////////////////////////////////////////////
  385. ////
  386. //// Generic reduce operation
  387. ////
  388. ////////////////////////////////////////////////////////
  389. template <typename Op, typename T>
  390. struct reduce
  391. {
  392. using type = T;
  393. };
  394. ////////////////////////////////////////////////////////
  395. ////
  396. //// Unary reduce_view operation. Splits into basic and non-basic views.
  397. //// Algorithm-specific reduce should specialize for basic views
  398. ////
  399. ////////////////////////////////////////////////////////
  400. template <typename Op, typename View, bool IsBasic>
  401. struct reduce_view_basic
  402. {
  403. using type = View;
  404. };
  405. template <typename Op, typename Loc>
  406. struct reduce<Op, image_view<Loc>>
  407. : public reduce_view_basic<Op,image_view<Loc>,view_is_basic<image_view<Loc>>::value> {};
  408. ////////////////////////////////////////////////////////
  409. ////
  410. //// Unary reduce_image operation. Splits into basic and non-basic images.
  411. //// Algorithm-specific reduce should specialize for basic images
  412. ////
  413. ////////////////////////////////////////////////////////
  414. template <typename Op, typename Img, bool IsBasic>
  415. struct reduce_image_basic
  416. {
  417. using type = Img;
  418. };
  419. template <typename Op, typename V, typename Alloc>
  420. struct reduce<Op, image<V,Alloc>> : public reduce_image_basic<Op,image<V,Alloc>,image_is_basic<image<V,Alloc>>::value > {};
  421. ////////////////////////////////////////////////////////
  422. ////
  423. //// Binary reduce_view operation. Splits into basic and non-basic views.
  424. //// Algorithm-specific reduce should specialize for basic views
  425. ////
  426. ////////////////////////////////////////////////////////
  427. template <typename Op, typename V1, typename V2, bool AreBasic>
  428. struct reduce_views_basic
  429. {
  430. using type = std::pair<const V1*, const V2*>;
  431. };
  432. template <typename Op, typename L1, typename L2>
  433. struct reduce<Op, std::pair<const image_view<L1>*, const image_view<L2>*>>
  434. : public reduce_views_basic<Op,image_view<L1>,image_view<L2>,
  435. mpl::and_<view_is_basic<image_view<L1>>, view_is_basic<image_view<L2>>>::value >
  436. {};
  437. ////////////////////////////////////////////////////////
  438. ////
  439. //// Color space unary reduce operation. Reduce a color space to a base with the same number of channels
  440. ////
  441. ////////////////////////////////////////////////////////
  442. template <typename CS>
  443. struct reduce_color_space
  444. {
  445. using type = CS;
  446. };
  447. template <> struct reduce_color_space<lab_t> { using type = rgb_t; };
  448. template <> struct reduce_color_space<hsb_t> { using type = rgb_t; };
  449. template <> struct reduce_color_space<cmyk_t> { using type = rgba_t; };
  450. /*
  451. ////////////////////////////////////////////////////////
  452. ////
  453. //// Color space binary reduce operation. Given a source and destination color spaces,
  454. //// returns a reduced source and destination color spaces that have the same mapping of channels
  455. ////
  456. //// Precondition: The two color spaces must be compatible (i.e. must have the same set of channels)
  457. ////////////////////////////////////////////////////////
  458. template <typename Vec, int Basis, int VecSize>
  459. struct type_vec_to_integer_impl {
  460. using last = typename mpl::back<Vec>::type;
  461. using rest = typename mpl::pop_back<Vec>::type;
  462. static const int value = type_vec_to_integer_impl<rest, Basis, VecSize-1>::value * Basis + last::value;
  463. };
  464. template <typename Vec, int Basis>
  465. struct type_vec_to_integer_impl<Vec,Basis,0> {
  466. static const int value=0;
  467. };
  468. template <typename Vec, int Basis=10>
  469. struct type_vec_to_integer {
  470. static const int value = type_vec_to_integer_impl<Vec,Basis, mpl::size<Vec>::value>::value;
  471. };
  472. // Given two color spaces and the mapping of the channels between them, returns the reduced pair of color spaces
  473. // The default version performs no reduction
  474. template <typename SrcColorSpace, typename DstColorSpace, int Mapping>
  475. struct reduce_color_spaces_impl {
  476. using first_t = SrcColorSpace;
  477. using second_t = DstColorSpace;
  478. };
  479. // 012: RGB-RGB, bgr-bgr, lab-lab, hsb-hsb
  480. template <typename SrcColorSpace, typename DstColorSpace>
  481. struct reduce_color_spaces_impl<SrcColorSpace,DstColorSpace,12> {
  482. using first_t = rgb_t;
  483. using second_t = rgb_t;
  484. };
  485. // 210: RGB-bgr, bgr-RGB
  486. template <typename SrcColorSpace, typename DstColorSpace>
  487. struct reduce_color_spaces_impl<SrcColorSpace,DstColorSpace,210> {
  488. using first_t = rgb_t;
  489. using second_t = bgr_t;
  490. };
  491. // 0123: RGBA-RGBA, bgra-bgra, argb-argb, abgr-abgr cmyk-cmyk
  492. template <typename SrcColorSpace, typename DstColorSpace>
  493. struct reduce_color_spaces_impl<SrcColorSpace,DstColorSpace,123> {
  494. using first_t = rgba_t;
  495. using second_t = rgba_t;
  496. };
  497. // 3210: RGBA-abgr, bgra-argb, argb-bgra, abgr-RGBA
  498. template <typename SrcColorSpace, typename DstColorSpace>
  499. struct reduce_color_spaces_impl<SrcColorSpace,DstColorSpace,3210> {
  500. using first_t = rgba_t;
  501. using second_t = abgr_t;
  502. };
  503. // 1230: RGBA-argb, bgra-abgr
  504. template <typename SrcColorSpace, typename DstColorSpace>
  505. struct reduce_color_spaces_impl<SrcColorSpace,DstColorSpace,1230> {
  506. using first_t = rgba_t;
  507. using second_t = argb_t;
  508. };
  509. // 2103: RGBA-bgra, bgra-RGBA (uses subclass to ensure that base color space is not reduced to derived)
  510. template <typename SrcColorSpace, typename DstColorSpace>
  511. struct reduce_color_spaces_impl<SrcColorSpace,DstColorSpace,2103> {
  512. using first_t = rgba_t;
  513. using second_t = bgra_t;
  514. };
  515. // 3012: argb-RGBA, abgr-bgra
  516. template <typename SrcColorSpace, typename DstColorSpace>
  517. struct reduce_color_spaces_impl<SrcColorSpace,DstColorSpace,3012> {
  518. using first_t = argb_t;
  519. using second_t = rgba_t;
  520. };
  521. // 0321: argb-abgr, abgr-argb
  522. template <typename SrcColorSpace, typename DstColorSpace>
  523. struct reduce_color_spaces_impl<SrcColorSpace,DstColorSpace,321> {
  524. using first_t = argb_t;
  525. using second_t = abgr_t;
  526. };
  527. template <typename SrcColorSpace, typename DstColorSpace>
  528. struct reduce_color_spaces {
  529. using src_order_t = typename channel_order<SrcColorSpace>::type;
  530. using dst_order_t = typename channel_order<DstColorSpace>::type;
  531. using mapping = typename mpl::transform<src_order_t, type_to_index<dst_order_t,mpl::_1>>::type;
  532. static const int mapping_val = type_vec_to_integer<mapping>::value;
  533. using _first_t = typename reduce_color_spaces_impl<SrcColorSpace,DstColorSpace,mapping_val>::first_t;
  534. using _second_t = typename reduce_color_spaces_impl<SrcColorSpace,DstColorSpace,mapping_val>::second_t;
  535. using swap_t = typename mpl::and_<color_space_is_base<DstColorSpace>, mpl::not_< color_space_is_base<_second_t>>>;
  536. public:
  537. using first_t = typename mpl::if_<swap_t, _second_t, _first_t>::type;
  538. using second_t = typename mpl::if_<swap_t, _first_t, _second_t>::type;
  539. };
  540. */
  541. // TODO: Use the old code for reduce_color_spaces above to do color layout reduction
  542. template <typename SrcLayout, typename DstLayout>
  543. struct reduce_color_layouts
  544. {
  545. using first_t = SrcLayout;
  546. using second_t = DstLayout;
  547. };
  548. ////////////////////////////////////////////////////////
  549. ////
  550. //// Reduce for copy_pixels
  551. ////
  552. ////////////////////////////////////////////////////////
  553. struct copy_pixels_fn;
  554. /*
  555. // 1D reduce for copy_pixels reduces the channel to mutable and the color space to its base with same dimensions
  556. template <typename View>
  557. struct reduce_view_basic<copy_pixels_fn,View,true> {
  558. private:
  559. using color_space_t = typename reduce_color_space<typename View::color_space_t>::type color_space_t; // reduce the color space
  560. using layout_t = layout<color_space_t, typename View::channel_mapping_t>;
  561. public:
  562. using type = typename derived_view_type<View, use_default, layout_t, use_default, use_default, mpl::true_>::type;
  563. };
  564. */
  565. // Incompatible views cannot be used in copy_pixels - will throw std::bad_cast
  566. template <typename V1, typename V2, bool Compatible>
  567. struct reduce_copy_pixop_compat
  568. {
  569. using type = error_t;
  570. };
  571. // For compatible basic views, reduce their color spaces based on their channel mapping.
  572. // Make the source immutable and the destination mutable (they should already be that way)
  573. template <typename V1, typename V2>
  574. struct reduce_copy_pixop_compat<V1,V2,true>
  575. {
  576. using layout1 = layout<typename V1::color_space_t, typename V1::channel_mapping_t>;
  577. using layout2 = layout<typename V2::color_space_t, typename V2::channel_mapping_t>;
  578. using L1 = typename reduce_color_layouts<layout1,layout2>::first_t;
  579. using L2 = typename reduce_color_layouts<layout1,layout2>::second_t;
  580. using DV1 = typename derived_view_type<V1, use_default, L1, use_default, use_default, use_default, mpl::false_>::type;
  581. using DV2 = typename derived_view_type<V2, use_default, L2, use_default, use_default, use_default, mpl::true_ >::type;
  582. using type = std::pair<const DV1*, const DV2*>;
  583. };
  584. // The general 2D version branches into compatible and incompatible views
  585. template <typename V1, typename V2>
  586. struct reduce_views_basic<copy_pixels_fn, V1, V2, true>
  587. : public reduce_copy_pixop_compat<V1, V2, mpl::and_<views_are_compatible<V1,V2>, view_is_mutable<V2>>::value > {
  588. };
  589. ////////////////////////////////////////////////////////
  590. ////
  591. //// Reduce for variant destructor (basic views have no destructor)
  592. ////
  593. ////////////////////////////////////////////////////////
  594. struct destructor_op;
  595. template <typename View>
  596. struct reduce_view_basic<destructor_op,View,true>
  597. {
  598. using type = gray8_view_t;
  599. };
  600. ////////////////////////////////////////////////////////
  601. ////
  602. //// Reduce for get_dimensions (basic views and images have the same structure and the dimensions are contained at the beginning)
  603. ////
  604. ////////////////////////////////////////////////////////
  605. struct any_type_get_dimensions;
  606. template <typename View>
  607. struct reduce_view_basic<any_type_get_dimensions,View,true>
  608. {
  609. using type = gray8_view_t;
  610. };
  611. template <typename Img>
  612. struct reduce_image_basic<any_type_get_dimensions,Img,true>
  613. {
  614. using type = gray8_image_t;
  615. };
  616. ////////////////////////////////////////////////////////
  617. ////
  618. //// Reduce for get_num_channels (only color space matters)
  619. ////
  620. ////////////////////////////////////////////////////////
  621. struct any_type_get_num_channels;
  622. template <typename View>
  623. struct reduce_view_basic<any_type_get_num_channels,View,true>
  624. {
  625. using color_space_t = typename View::color_space_t::base;
  626. using type = typename view_type<uint8_t,typename reduce_color_space<color_space_t>::type>::type;
  627. };
  628. template <typename Img>
  629. struct reduce_image_basic<any_type_get_num_channels,Img,true>
  630. {
  631. using color_space_t = typename Img::color_space_t::base;
  632. using type = typename image_type<uint8_t,typename reduce_color_space<color_space_t>::type>::type;
  633. };
  634. ////////////////////////////////////////////////////////
  635. ////
  636. //// Reduce for resample_pixels (same as copy_pixels)
  637. ////
  638. ////////////////////////////////////////////////////////
  639. template <typename Sampler, typename MapFn> struct resample_pixels_fn;
  640. template <typename S, typename M, typename V, bool IsBasic>
  641. struct reduce_view_basic<resample_pixels_fn<S,M>, V, IsBasic> : public reduce_view_basic<copy_pixels_fn, V, IsBasic> {};
  642. template <typename S, typename M, typename V1, typename V2, bool IsBasic>
  643. struct reduce_views_basic<resample_pixels_fn<S,M>, V1, V2, IsBasic> : public reduce_views_basic<copy_pixels_fn, V1, V2, IsBasic> {};
  644. ////////////////////////////////////////////////////////
  645. ////
  646. //// Reduce for copy_and_convert_pixels
  647. //// (the only reduction could be made when views are compatible and have the same mapping, planarity and stepness)
  648. ////
  649. ////////////////////////////////////////////////////////
  650. template <typename CC> class copy_and_convert_pixels_fn;
  651. // the only thing for 1D reduce is making them all mutable...
  652. template <typename CC, typename View, bool IsBasic>
  653. struct reduce_view_basic<copy_and_convert_pixels_fn<CC>, View, IsBasic>
  654. : public derived_view_type<View, use_default, use_default, use_default, use_default, mpl::true_> {
  655. };
  656. // For 2D reduce, if they have the same channels and color spaces (i.e. the same pixels) then copy_and_convert is just copy.
  657. // In this case, reduce their common color space. In general make the first immutable and the second mutable
  658. template <typename CC, typename V1, typename V2, bool AreBasic>
  659. struct reduce_views_basic<copy_and_convert_pixels_fn<CC>, V1, V2, AreBasic>
  660. {
  661. using Same = std::is_same<typename V1::pixel_t, typename V2::pixel_t>;
  662. using CsR = reduce_color_space<typename V1::color_space_t::base>;
  663. using Cs1 = typename mpl::if_<Same, typename CsR::type, typename V1::color_space_t>::type;
  664. using Cs2 = typename mpl::if_<Same, typename CsR::type, typename V2::color_space_t>::type;
  665. using DV1 = typename derived_view_type<V1, use_default, layout<Cs1, typename V1::channel_mapping_t>, use_default, use_default, mpl::false_>::type;
  666. using DV2 = typename derived_view_type<V2, use_default, layout<Cs2, typename V2::channel_mapping_t>, use_default, use_default, mpl::true_ >::type;
  667. using type = std::pair<const DV1*, const DV2*>;
  668. };
  669. //integral_image_generator
  670. //resize_clobber_image_fnobj
  671. //image_default_construct_fnobj
  672. //fill_converted_pixels_fn
  673. //std::bind(gil::detail::copy_pixels_fn(), std::placeholders::_1, dst)
  674. //std::bind(gil::detail::copy_pixels_fn(), src, std::placeholders::_1)
  675. //std::bind(detail::copy_and_convert_pixels_fn(), std::placeholders::_1, dst)
  676. //std::bind(detail::copy_and_convert_pixels_fn(), src, std::placeholders::_1)
  677. //gil::detail::fill_pixels_fn<Value>(val)
  678. //detail::copy_construct_in_place_fn<base_t>
  679. //detail::equal_to_fn<typename variant<Types>::base_t>
  680. //detail::any_image_get_view<typename any_image<Types>::view_t>
  681. //detail::any_image_get_const_view<typename any_image<Types>::view_t>
  682. //detail::flipped_up_down_view_fn<any_image_view<ViewTypes>>
  683. //detail::flipped_left_right_view_fn<typename any_image_view<ViewTypes>::dynamic_step_t>
  684. //detail::tranposed_view_fn<typename any_image_view<ViewTypes>::dynamic_step_t>
  685. //detail::rotated90cw_view_fn<typename any_image_view<ViewTypes>::dynamic_step_t>
  686. //detail::rotated90ccw_view_fn<typename any_image_view<ViewTypes>::dynamic_step_t>
  687. //detail::rotated180_view_fn<typename any_image_view<ViewTypes>::dynamic_step_t>
  688. //detail::subimage_view_fn<any_image_view<ViewTypes>>
  689. //detail::subsampled_view_fn<typename any_image_view<ViewTypes>::dynamic_step_t>
  690. //detail::nth_channel_view_fn<typename nth_channel_view_type<any_image_view<ViewTypes>>
  691. //detail::color_converted_view_fn<DstP,typename color_convert_view_type<any_image_view<ViewTypes>, DstP>::type >
  692. }
  693. }} // namespace boost::gil
  694. #endif // defined(BOOST_GIL_REDUCE_CODE_BLOAT)
  695. #endif