algorithm.hpp 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042
  1. /*
  2. Copyright 2005-2007 Adobe Systems Incorporated
  3. Use, modification and distribution are subject to the Boost Software License,
  4. Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5. http://www.boost.org/LICENSE_1_0.txt).
  6. See http://opensource.adobe.com/gil for most recent version including documentation.
  7. */
  8. /*************************************************************************************************/
  9. #ifndef GIL_ALGORITHM_HPP
  10. #define GIL_ALGORITHM_HPP
  11. #include <cassert>
  12. #include <cstddef>
  13. #include <cstring>
  14. #include <algorithm>
  15. #include <iterator>
  16. #include <memory>
  17. #include <typeinfo>
  18. #include <boost/config.hpp>
  19. #include <boost/utility/enable_if.hpp>
  20. #include <boost/mpl/and.hpp>
  21. #include <boost/mpl/or.hpp>
  22. #include "gil_config.hpp"
  23. #include "gil_concept.hpp"
  24. #include "color_base_algorithm.hpp"
  25. #include "image_view.hpp"
  26. #include "image_view_factory.hpp"
  27. #include "bit_aligned_pixel_iterator.hpp"
  28. ////////////////////////////////////////////////////////////////////////////////////////
  29. /// \file
  30. /// \brief Some basic STL-style algorithms when applied to image views
  31. /// \author Lubomir Bourdev and Hailin Jin \n
  32. /// Adobe Systems Incorporated
  33. /// \date 2005-2008 \n Last updated on March 12, 2008
  34. ///
  35. ////////////////////////////////////////////////////////////////////////////////////////
  36. //#ifdef _MSC_VER
  37. //#pragma warning(push)
  38. //#pragma warning(disable : 4244) // conversion from 'gil::image<V,Alloc>::coord_t' to 'int', possible loss of data (visual studio compiler doesn't realize that the two types are the same)
  39. //#endif
  40. namespace boost { namespace gil {
  41. //forward declarations
  42. template <typename ChannelPtr, typename ColorSpace>
  43. struct planar_pixel_iterator;
  44. template <typename Iterator>
  45. class memory_based_step_iterator;
  46. template <typename StepIterator>
  47. class memory_based_2d_locator;
  48. // a tag denoting incompatible arguments
  49. struct error_t {};
  50. /// \defgroup ImageViewSTLAlgorithms STL-like Algorithms
  51. /// \ingroup ImageViewAlgorithm
  52. /// \brief Image view-equivalents of STL algorithms
  53. ///
  54. /// Image views provide 1D iteration of their pixels via \p begin() and \p end() methods,
  55. /// which makes it possible to use STL algorithms with them. However, using nested loops
  56. /// over X and Y is in many cases more efficient. The algorithms in this section resemble
  57. /// STL algorithms, but they abstract away the nested loops and take views (as opposed to ranges) as input.
  58. ///
  59. /// Most algorithms check whether the image views are 1D-traversable. A 1D-traversable image view has no gaps
  60. /// at the end of the rows. In other words, if an x_iterator of that view is advanced past the last pixel in a row
  61. /// it will move to the first pixel of the next row. When image views are 1D-traversable, the algorithms use
  62. /// a single loop and run more efficiently. If one or more of the input views are not 1D-traversable, the algorithms
  63. /// fall-back to an X-loop nested inside a Y-loop.
  64. ///
  65. /// The algorithms typically delegate the work to their corresponding STL algorithms. For example, \p copy_pixels calls
  66. /// \p std::copy either for each row, or, when the images are 1D-traversable, once for all pixels.
  67. ///
  68. /// In addition, overloads are sometimes provided for the STL algorithms. For example, std::copy for planar iterators
  69. /// is overloaded to perform \p std::copy for each of the planes. \p std::copy over bitwise-copiable pixels results in
  70. /// std::copy over unsigned char, which STL typically implements via \p memmove.
  71. ///
  72. /// As a result \p copy_pixels may result in a single call to \p memmove for interleaved 1D-traversable views,
  73. /// or one per each plane of planar 1D-traversable views, or one per each row of interleaved non-1D-traversable images, etc.
  74. /// \defgroup STLOptimizations Performance overloads of STL algorithms
  75. /// \ingroup ImageViewAlgorithm
  76. /// \brief overloads of STL algorithms allowing more efficient implementation when used with GIL constructs
  77. /// \brief A generic binary operation on views
  78. /// \ingroup ImageViewSTLAlgorithms
  79. ///
  80. /// Use this class as a convenience superclass when defining an operation for any image views.
  81. /// Many operations have different behavior when the two views are compatible. This class checks
  82. /// for compatibility and invokes apply_compatible(V1,V2) or apply_incompatible(V1,V2) of the subclass.
  83. /// You must provide apply_compatible(V1,V2) method in your subclass, but apply_incompatible(V1,V2)
  84. /// is not required and the default throws std::bad_cast.
  85. template <typename Derived, typename Result=void>
  86. struct binary_operation_obj {
  87. typedef Result result_type;
  88. template <typename V1, typename V2> BOOST_FORCEINLINE
  89. result_type operator()(const std::pair<const V1*,const V2*>& p) const {
  90. return apply(*p.first, *p.second, typename views_are_compatible<V1,V2>::type());
  91. }
  92. template <typename V1, typename V2> BOOST_FORCEINLINE
  93. result_type operator()(const V1& v1, const V2& v2) const {
  94. return apply(v1, v2, typename views_are_compatible<V1,V2>::type());
  95. }
  96. result_type operator()(const error_t&) const { throw std::bad_cast(); }
  97. private:
  98. // dispatch from apply overload to a function with distinct name
  99. template <typename V1, typename V2>
  100. BOOST_FORCEINLINE result_type apply(const V1& v1, const V2& v2, mpl::false_) const {
  101. return ((const Derived*)this)->apply_incompatible(v1,v2);
  102. }
  103. // dispatch from apply overload to a function with distinct name
  104. template <typename V1, typename V2>
  105. BOOST_FORCEINLINE result_type apply(const V1& v1, const V2& v2, mpl::true_) const {
  106. return ((const Derived*)this)->apply_compatible(v1,v2);
  107. }
  108. // function with distinct name - it can be overloaded by subclasses
  109. template <typename V1, typename V2>
  110. BOOST_FORCEINLINE result_type apply_incompatible(const V1&, const V2&) const {
  111. throw std::bad_cast();
  112. }
  113. };
  114. } } // namespace boost::gil
  115. //////////////////////////////////////////////////////////////////////////////////////
  116. ///
  117. /// std::copy and gil::copy_pixels
  118. ///
  119. //////////////////////////////////////////////////////////////////////////////////////
  120. /// \defgroup ImageViewSTLAlgorithmsCopyPixels copy_pixels
  121. /// \ingroup ImageViewSTLAlgorithms
  122. /// \brief std::copy for image views
  123. namespace std {
  124. /// \ingroup STLOptimizations
  125. /// \brief Copy when both src and dst are interleaved and of the same type can be just memmove
  126. template<typename T, typename Cs>
  127. BOOST_FORCEINLINE boost::gil::pixel<T,Cs>*
  128. copy(boost::gil::pixel<T,Cs>* first, boost::gil::pixel<T,Cs>* last,
  129. boost::gil::pixel<T,Cs>* dst) {
  130. return (boost::gil::pixel<T,Cs>*)std::copy((unsigned char*)first,(unsigned char*)last, (unsigned char*)dst);
  131. }
  132. /// \ingroup STLOptimizations
  133. /// \brief Copy when both src and dst are interleaved and of the same type can be just memmove
  134. template<typename T, typename Cs>
  135. BOOST_FORCEINLINE boost::gil::pixel<T,Cs>*
  136. copy(const boost::gil::pixel<T,Cs>* first, const boost::gil::pixel<T,Cs>* last,
  137. boost::gil::pixel<T,Cs>* dst) {
  138. return (boost::gil::pixel<T,Cs>*)std::copy((unsigned char*)first,(unsigned char*)last, (unsigned char*)dst);
  139. }
  140. } // namespace std
  141. namespace boost { namespace gil {
  142. namespace detail {
  143. template <typename I, typename O> struct copy_fn {
  144. BOOST_FORCEINLINE I operator()(I first, I last, O dst) const { return std::copy(first,last,dst); }
  145. };
  146. } // namespace detail
  147. } } // namespace boost::gil
  148. namespace std {
  149. /// \ingroup STLOptimizations
  150. /// \brief Copy when both src and dst are planar pointers is copy for each channel
  151. template<typename Cs, typename IC1, typename IC2> BOOST_FORCEINLINE
  152. boost::gil::planar_pixel_iterator<IC2,Cs> copy(boost::gil::planar_pixel_iterator<IC1,Cs> first, boost::gil::planar_pixel_iterator<IC1,Cs> last, boost::gil::planar_pixel_iterator<IC2,Cs> dst) {
  153. boost::gil::gil_function_requires<boost::gil::ChannelsCompatibleConcept<typename std::iterator_traits<IC1>::value_type,typename std::iterator_traits<IC2>::value_type> >();
  154. static_for_each(first,last,dst,boost::gil::detail::copy_fn<IC1,IC2>());
  155. return dst+(last-first);
  156. }
  157. } // namespace std
  158. namespace boost { namespace gil {
  159. namespace detail {
  160. /// Does a copy-n. If the inputs contain image iterators, performs a copy at each row using the row iterators
  161. /// \ingroup CopyPixels
  162. template <typename I, typename O>
  163. struct copier_n {
  164. BOOST_FORCEINLINE void operator()(I src, typename std::iterator_traits<I>::difference_type n, O dst) const { std::copy(src,src+n, dst); }
  165. };
  166. /// Source range is delimited by image iterators
  167. template <typename IL, typename O> // IL Models ConstPixelLocatorConcept, O Models PixelIteratorConcept
  168. struct copier_n<iterator_from_2d<IL>,O> {
  169. typedef typename std::iterator_traits<iterator_from_2d<IL> >::difference_type diff_t;
  170. BOOST_FORCEINLINE void operator()(iterator_from_2d<IL> src, diff_t n, O dst) const {
  171. gil_function_requires<PixelLocatorConcept<IL> >();
  172. gil_function_requires<MutablePixelIteratorConcept<O> >();
  173. while (n>0) {
  174. diff_t l=src.width()-src.x_pos();
  175. diff_t numToCopy=(n<l ? n:l);
  176. detail::copy_n(src.x(), numToCopy, dst);
  177. dst+=numToCopy;
  178. src+=numToCopy;
  179. n-=numToCopy;
  180. }
  181. }
  182. };
  183. /// Destination range is delimited by image iterators
  184. template <typename I, typename OL> // I Models ConstPixelIteratorConcept, OL Models PixelLocatorConcept
  185. struct copier_n<I,iterator_from_2d<OL> > {
  186. typedef typename std::iterator_traits<I>::difference_type diff_t;
  187. BOOST_FORCEINLINE void operator()(I src, diff_t n, iterator_from_2d<OL> dst) const {
  188. gil_function_requires<PixelIteratorConcept<I> >();
  189. gil_function_requires<MutablePixelLocatorConcept<OL> >();
  190. while (n>0) {
  191. diff_t l=dst.width()-dst.x_pos();
  192. diff_t numToCopy=(n<l ? n:l);
  193. detail::copy_n(src, numToCopy, dst.x());
  194. dst+=numToCopy;
  195. src+=numToCopy;
  196. n-=numToCopy;
  197. }
  198. }
  199. };
  200. /// Both source and destination ranges are delimited by image iterators
  201. template <typename IL, typename OL>
  202. struct copier_n<iterator_from_2d<IL>,iterator_from_2d<OL> > {
  203. typedef typename iterator_from_2d<IL>::difference_type diff_t;
  204. BOOST_FORCEINLINE void operator()(iterator_from_2d<IL> src, diff_t n, iterator_from_2d<OL> dst) const {
  205. gil_function_requires<PixelLocatorConcept<IL> >();
  206. gil_function_requires<MutablePixelLocatorConcept<OL> >();
  207. if (src.x_pos()!=dst.x_pos() || src.width()!=dst.width()) {
  208. while(n-->0) {
  209. *dst++=*src++;
  210. }
  211. }
  212. while (n>0) {
  213. diff_t l=dst.width()-dst.x_pos();
  214. diff_t numToCopy=(n<l ? n : l);
  215. detail::copy_n(src.x(), numToCopy, dst.x());
  216. dst+=numToCopy;
  217. src+=numToCopy;
  218. n-=numToCopy;
  219. }
  220. }
  221. };
  222. template <typename SrcIterator, typename DstIterator>
  223. BOOST_FORCEINLINE DstIterator copy_with_2d_iterators(SrcIterator first, SrcIterator last, DstIterator dst) {
  224. typedef typename SrcIterator::x_iterator src_x_iterator;
  225. typedef typename DstIterator::x_iterator dst_x_iterator;
  226. typename SrcIterator::difference_type n = last - first;
  227. if (first.is_1d_traversable()) {
  228. if (dst.is_1d_traversable())
  229. copier_n<src_x_iterator,dst_x_iterator>()(first.x(),n, dst.x());
  230. else
  231. copier_n<src_x_iterator,DstIterator >()(first.x(),n, dst);
  232. } else {
  233. if (dst.is_1d_traversable())
  234. copier_n<SrcIterator,dst_x_iterator>()(first,n, dst.x());
  235. else
  236. copier_n<SrcIterator,DstIterator>()(first,n,dst);
  237. }
  238. return dst+n;
  239. }
  240. } // namespace detail
  241. } } // namespace boost::gil
  242. namespace std {
  243. /// \ingroup STLOptimizations
  244. /// \brief std::copy(I1,I1,I2) with I1 and I2 being a iterator_from_2d
  245. template <typename IL, typename OL>
  246. BOOST_FORCEINLINE boost::gil::iterator_from_2d<OL> copy1(boost::gil::iterator_from_2d<IL> first, boost::gil::iterator_from_2d<IL> last, boost::gil::iterator_from_2d<OL> dst) {
  247. return boost::gil::detail::copy_with_2d_iterators(first,last,dst);
  248. }
  249. } // namespace std
  250. namespace boost { namespace gil {
  251. /// \ingroup ImageViewSTLAlgorithmsCopyPixels
  252. /// \brief std::copy for image views
  253. template <typename View1, typename View2> BOOST_FORCEINLINE
  254. void copy_pixels(const View1& src, const View2& dst) {
  255. assert(src.dimensions()==dst.dimensions());
  256. detail::copy_with_2d_iterators(src.begin(),src.end(),dst.begin());
  257. }
  258. //////////////////////////////////////////////////////////////////////////////////////
  259. ///
  260. /// copy_and_convert_pixels
  261. ///
  262. //////////////////////////////////////////////////////////////////////////////////////
  263. /// \defgroup ImageViewSTLAlgorithmsCopyAndConvertPixels copy_and_convert_pixels
  264. /// \ingroup ImageViewSTLAlgorithms
  265. /// \brief copies src view into dst view, color converting if necessary.
  266. ///
  267. /// Versions taking static and runtime views are provided. Versions taking user-defined color convered are provided.
  268. namespace detail {
  269. template <typename CC>
  270. class copy_and_convert_pixels_fn : public binary_operation_obj<copy_and_convert_pixels_fn<CC> > {
  271. private:
  272. CC _cc;
  273. public:
  274. typedef typename binary_operation_obj<copy_and_convert_pixels_fn<CC> >::result_type result_type;
  275. copy_and_convert_pixels_fn() {}
  276. copy_and_convert_pixels_fn(CC cc_in) : _cc(cc_in) {}
  277. // when the two color spaces are incompatible, a color conversion is performed
  278. template <typename V1, typename V2> BOOST_FORCEINLINE
  279. result_type apply_incompatible(const V1& src, const V2& dst) const {
  280. copy_pixels(color_converted_view<typename V2::value_type>(src,_cc),dst);
  281. }
  282. // If the two color spaces are compatible, copy_and_convert is just copy
  283. template <typename V1, typename V2> BOOST_FORCEINLINE
  284. result_type apply_compatible(const V1& src, const V2& dst) const {
  285. copy_pixels(src,dst);
  286. }
  287. };
  288. } // namespace detail
  289. /// \ingroup ImageViewSTLAlgorithmsCopyAndConvertPixels
  290. template <typename V1, typename V2,typename CC>
  291. BOOST_FORCEINLINE
  292. void copy_and_convert_pixels(const V1& src, const V2& dst,CC cc) {
  293. detail::copy_and_convert_pixels_fn<CC> ccp(cc);
  294. ccp(src,dst);
  295. }
  296. struct default_color_converter;
  297. /// \ingroup ImageViewSTLAlgorithmsCopyAndConvertPixels
  298. template <typename View1, typename View2>
  299. BOOST_FORCEINLINE
  300. void copy_and_convert_pixels(const View1& src, const View2& dst) {
  301. detail::copy_and_convert_pixels_fn<default_color_converter> ccp;
  302. ccp(src,dst);
  303. }
  304. } } // namespace boost::gil
  305. //////////////////////////////////////////////////////////////////////////////////////
  306. //
  307. // std::fill and gil::fill_pixels
  308. //
  309. //////////////////////////////////////////////////////////////////////////////////////
  310. /// \defgroup ImageViewSTLAlgorithmsFillPixels fill_pixels
  311. /// \ingroup ImageViewSTLAlgorithms
  312. /// \brief std::fill for image views
  313. namespace std {
  314. /// \ingroup STLOptimizations
  315. /// \brief std::fill(I,I,V) with I being a iterator_from_2d
  316. ///
  317. /// Invoked when one calls std::fill(I,I,V) with I being a iterator_from_2d (which is
  318. /// a 1D iterator over the pixels in an image). For contiguous images (i.e. images that have
  319. /// no alignment gap at the end of each row) it is more efficient to use the underlying
  320. /// pixel iterator that does not check for the end of rows. For non-contiguous images fill
  321. /// resolves to fill of each row using the underlying pixel iterator, which is still faster
  322. template <typename IL, typename V>
  323. void fill(boost::gil::iterator_from_2d<IL> first, boost::gil::iterator_from_2d<IL> last, const V& val) {
  324. boost::gil::gil_function_requires<boost::gil::MutablePixelLocatorConcept<IL> >();
  325. if (first.is_1d_traversable()) {
  326. std::fill(first.x(), last.x(), val);
  327. } else {
  328. // fill row by row
  329. std::ptrdiff_t n=last-first;
  330. while (n>0) {
  331. std::ptrdiff_t numToDo=std::min<const std::ptrdiff_t>(n,(std::ptrdiff_t)(first.width()-first.x_pos()));
  332. fill_n(first.x(), numToDo, val);
  333. first+=numToDo;
  334. n-=numToDo;
  335. }
  336. }
  337. }
  338. } // namespace std
  339. namespace boost { namespace gil {
  340. namespace detail {
  341. /// struct to do std::fill
  342. struct std_fill_t {
  343. template <typename It, typename P>
  344. void operator()(It first, It last, const P& p_in) {
  345. std::fill(first,last,p_in);
  346. }
  347. };
  348. /// std::fill for planar iterators
  349. template <typename It, typename P>
  350. BOOST_FORCEINLINE
  351. void fill_aux(It first, It last, const P& p, mpl::true_) {
  352. static_for_each(first,last,p,std_fill_t());
  353. }
  354. /// std::fill for interleaved iterators
  355. template <typename It, typename P>
  356. BOOST_FORCEINLINE
  357. void fill_aux(It first, It last, const P& p,mpl::false_) {
  358. std::fill(first,last,p);
  359. }
  360. } // namespace detail
  361. /// \ingroup ImageViewSTLAlgorithmsFillPixels
  362. /// \brief std::fill for image views
  363. template <typename View, typename Value> BOOST_FORCEINLINE
  364. void fill_pixels(const View& img_view, const Value& val) {
  365. if (img_view.is_1d_traversable())
  366. detail::fill_aux(img_view.begin().x(), img_view.end().x(),
  367. val,is_planar<View>());
  368. else
  369. for (std::ptrdiff_t y=0; y<img_view.height(); ++y)
  370. detail::fill_aux(img_view.row_begin(y),img_view.row_end(y),
  371. val,is_planar<View>());
  372. }
  373. //////////////////////////////////////////////////////////////////////////////////////
  374. ///
  375. /// destruct_pixels
  376. ///
  377. //////////////////////////////////////////////////////////////////////////////////////
  378. /// \defgroup ImageViewSTLAlgorithmsDestructPixels destruct_pixels
  379. /// \ingroup ImageViewSTLAlgorithms
  380. /// \brief invokes the destructor on every pixel of an image view
  381. namespace detail {
  382. template <typename It> BOOST_FORCEINLINE
  383. void destruct_range_impl( It first
  384. , It last
  385. , typename enable_if< mpl::and_< is_pointer< It >
  386. , mpl::not_< boost::has_trivial_destructor< typename std::iterator_traits<It>::value_type > >
  387. >
  388. >::type* /*ptr*/ = 0
  389. )
  390. {
  391. while (first!=last) {
  392. first->~value_t();
  393. ++first;
  394. }
  395. }
  396. template <typename It> BOOST_FORCEINLINE
  397. void destruct_range_impl( It
  398. , It
  399. , typename enable_if< mpl::or_< mpl::not_< is_pointer< It > >
  400. , boost::has_trivial_destructor< typename std::iterator_traits< It >::value_type >
  401. >
  402. >::type* /* ptr */ = 0)
  403. {}
  404. template <typename It> BOOST_FORCEINLINE
  405. void destruct_range(It first, It last) {
  406. destruct_range_impl( first
  407. , last
  408. );
  409. }
  410. struct std_destruct_t {
  411. template <typename It> void operator()(It first, It last) const { destruct_range(first,last); }
  412. };
  413. /// destruct for planar iterators
  414. template <typename It>
  415. BOOST_FORCEINLINE
  416. void destruct_aux(It first, It last, mpl::true_) {
  417. static_for_each(first,last,std_destruct_t());
  418. }
  419. /// destruct for interleaved iterators
  420. template <typename It>
  421. BOOST_FORCEINLINE
  422. void destruct_aux(It first, It last, mpl::false_) {
  423. destruct_range(first,last);
  424. }
  425. } // namespace detail
  426. /// \ingroup ImageViewSTLAlgorithmsDestructPixels
  427. /// \brief Invokes the in-place destructor on every pixel of the view
  428. template <typename View> BOOST_FORCEINLINE
  429. void destruct_pixels(const View& img_view) {
  430. if (img_view.is_1d_traversable())
  431. detail::destruct_aux(img_view.begin().x(), img_view.end().x(),
  432. is_planar<View>());
  433. else
  434. for (std::ptrdiff_t y=0; y<img_view.height(); ++y)
  435. detail::destruct_aux(img_view.row_begin(y),img_view.row_end(y),
  436. is_planar<View>());
  437. }
  438. //////////////////////////////////////////////////////////////////////////////////////
  439. ///
  440. /// uninitialized_fill_pixels
  441. ///
  442. //////////////////////////////////////////////////////////////////////////////////////
  443. /// \defgroup ImageViewSTLAlgorithmsUninitializedFillPixels uninitialized_fill_pixels
  444. /// \ingroup ImageViewSTLAlgorithms
  445. /// \brief std::uninitialized_fill for image views
  446. namespace detail {
  447. /// std::uninitialized_fill for planar iterators
  448. /// If an exception is thrown destructs any in-place copy-constructed objects
  449. template <typename It, typename P>
  450. BOOST_FORCEINLINE
  451. void uninitialized_fill_aux(It first, It last,
  452. const P& p, mpl::true_) {
  453. int channel=0;
  454. try {
  455. typedef typename std::iterator_traits<It>::value_type pixel_t;
  456. while (channel < num_channels<pixel_t>::value) {
  457. std::uninitialized_fill(dynamic_at_c(first,channel), dynamic_at_c(last,channel),
  458. dynamic_at_c(p,channel));
  459. ++channel;
  460. }
  461. } catch (...) {
  462. for (int c=0; c<channel; ++c)
  463. destruct_range(dynamic_at_c(first,c), dynamic_at_c(last,c));
  464. throw;
  465. }
  466. }
  467. /// std::uninitialized_fill for interleaved iterators
  468. /// If an exception is thrown destructs any in-place copy-constructed objects
  469. template <typename It, typename P>
  470. BOOST_FORCEINLINE
  471. void uninitialized_fill_aux(It first, It last,
  472. const P& p,mpl::false_) {
  473. std::uninitialized_fill(first,last,p);
  474. }
  475. } // namespace detail
  476. /// \ingroup ImageViewSTLAlgorithmsUninitializedFillPixels
  477. /// \brief std::uninitialized_fill for image views.
  478. /// Does not support planar heterogeneous views.
  479. /// If an exception is thrown destructs any in-place copy-constructed pixels
  480. template <typename View, typename Value>
  481. void uninitialized_fill_pixels(const View& img_view, const Value& val) {
  482. if (img_view.is_1d_traversable())
  483. detail::uninitialized_fill_aux(img_view.begin().x(), img_view.end().x(),
  484. val,is_planar<View>());
  485. else {
  486. typename View::y_coord_t y = 0;
  487. try {
  488. for (y=0; y<img_view.height(); ++y)
  489. detail::uninitialized_fill_aux(img_view.row_begin(y),img_view.row_end(y),
  490. val,is_planar<View>());
  491. } catch(...) {
  492. for (typename View::y_coord_t y0=0; y0<y; ++y0)
  493. detail::destruct_aux(img_view.row_begin(y0),img_view.row_end(y0), is_planar<View>());
  494. throw;
  495. }
  496. }
  497. }
  498. //////////////////////////////////////////////////////////////////////////////////////
  499. ///
  500. /// default_construct_pixels
  501. ///
  502. //////////////////////////////////////////////////////////////////////////////////////
  503. /// \defgroup ImageViewSTLAlgorithmsDefaultConstructPixels default_construct_pixels
  504. /// \ingroup ImageViewSTLAlgorithms
  505. /// \brief invokes the default constructor on every pixel of an image view
  506. namespace detail {
  507. template <typename It> BOOST_FORCEINLINE
  508. void default_construct_range_impl(It first, It last, mpl::true_) {
  509. typedef typename std::iterator_traits<It>::value_type value_t;
  510. It first1=first;
  511. try {
  512. while (first!=last) {
  513. new (first) value_t();
  514. ++first;
  515. }
  516. } catch (...) {
  517. destruct_range(first1,first);
  518. throw;
  519. }
  520. }
  521. template <typename It> BOOST_FORCEINLINE
  522. void default_construct_range_impl(It, It, mpl::false_) {}
  523. template <typename It> BOOST_FORCEINLINE
  524. void default_construct_range(It first, It last) { default_construct_range_impl(first, last, typename is_pointer<It>::type()); }
  525. /// uninitialized_default_construct for planar iterators
  526. template <typename It>
  527. BOOST_FORCEINLINE
  528. void default_construct_aux(It first, It last, mpl::true_) {
  529. int channel=0;
  530. try {
  531. typedef typename std::iterator_traits<It>::value_type pixel_t;
  532. while (channel < num_channels<pixel_t>::value) {
  533. default_construct_range(dynamic_at_c(first,channel), dynamic_at_c(last,channel));
  534. ++channel;
  535. }
  536. } catch (...) {
  537. for (int c=0; c<channel; ++c)
  538. destruct_range(dynamic_at_c(first,c), dynamic_at_c(last,c));
  539. throw;
  540. }
  541. }
  542. /// uninitialized_default_construct for interleaved iterators
  543. template <typename It>
  544. BOOST_FORCEINLINE
  545. void default_construct_aux(It first, It last, mpl::false_) {
  546. default_construct_range(first,last);
  547. }
  548. template <typename View, bool IsPlanar>
  549. struct has_trivial_pixel_constructor : public boost::has_trivial_constructor<typename View::value_type> {};
  550. template <typename View>
  551. struct has_trivial_pixel_constructor<View, true> : public boost::has_trivial_constructor<typename channel_type<View>::type> {};
  552. } // namespace detail
  553. namespace detail {
  554. template< typename View, bool B > BOOST_FORCEINLINE
  555. void default_construct_pixels_impl( const View& img_view
  556. , boost::enable_if< is_same< mpl::bool_< B >
  557. , mpl::false_
  558. >
  559. >* /* ptr */ = 0
  560. )
  561. {
  562. if( img_view.is_1d_traversable() )
  563. {
  564. detail::default_construct_aux( img_view.begin().x()
  565. , img_view.end().x()
  566. , is_planar<View>()
  567. );
  568. }
  569. else
  570. {
  571. typename View::y_coord_t y = 0;
  572. try
  573. {
  574. for( y = 0; y < img_view.height(); ++y )
  575. {
  576. detail::default_construct_aux( img_view.row_begin( y )
  577. ,img_view.row_end( y )
  578. , is_planar<View>()
  579. );
  580. }
  581. } catch(...)
  582. {
  583. for (typename View::y_coord_t y0 = 0; y0 < y; ++y0 )
  584. {
  585. detail::destruct_aux( img_view.row_begin(y0)
  586. , img_view.row_end(y0)
  587. , is_planar<View>()
  588. );
  589. }
  590. throw;
  591. }
  592. }
  593. }
  594. } // namespace detail
  595. /// \ingroup ImageViewSTLAlgorithmsDefaultConstructPixels
  596. /// \brief Invokes the in-place default constructor on every pixel of the (uninitialized) view.
  597. /// Does not support planar heterogeneous views.
  598. /// If an exception is thrown destructs any in-place default-constructed pixels
  599. template <typename View>
  600. void default_construct_pixels(const View& img_view) {
  601. detail::default_construct_pixels_impl< View
  602. , detail::has_trivial_pixel_constructor< View
  603. , is_planar< View >::value
  604. >::value
  605. >( img_view );
  606. }
  607. //////////////////////////////////////////////////////////////////////////////////////
  608. ///
  609. /// uninitialized_copy_pixels
  610. ///
  611. //////////////////////////////////////////////////////////////////////////////////////
  612. /// \defgroup ImageViewSTLAlgorithmsUninitializedCopyPixels uninitialized_copy_pixels
  613. /// \ingroup ImageViewSTLAlgorithms
  614. /// \brief std::uninitialized_copy for image views
  615. namespace detail {
  616. /// std::uninitialized_copy for pairs of planar iterators
  617. template <typename It1, typename It2>
  618. BOOST_FORCEINLINE
  619. void uninitialized_copy_aux(It1 first1, It1 last1,
  620. It2 first2, mpl::true_) {
  621. int channel=0;
  622. try {
  623. typedef typename std::iterator_traits<It1>::value_type pixel_t;
  624. while (channel < num_channels<pixel_t>::value) {
  625. std::uninitialized_copy(dynamic_at_c(first1,channel), dynamic_at_c(last1,channel), dynamic_at_c(first2,channel));
  626. ++channel;
  627. }
  628. } catch (...) {
  629. It2 last2=first2;
  630. std::advance(last2, std::distance(first1,last1));
  631. for (int c=0; c<channel; ++c)
  632. destruct_range(dynamic_at_c(first2,c), dynamic_at_c(last2,c));
  633. throw;
  634. }
  635. }
  636. /// std::uninitialized_copy for interleaved or mixed iterators
  637. template <typename It1, typename It2>
  638. BOOST_FORCEINLINE
  639. void uninitialized_copy_aux(It1 first1, It1 last1,
  640. It2 first2,mpl::false_) {
  641. std::uninitialized_copy(first1,last1,first2);
  642. }
  643. } // namespace detail
  644. /// \ingroup ImageViewSTLAlgorithmsUninitializedCopyPixels
  645. /// \brief std::uninitialized_copy for image views.
  646. /// Does not support planar heterogeneous views.
  647. /// If an exception is thrown destructs any in-place copy-constructed objects
  648. template <typename View1, typename View2>
  649. void uninitialized_copy_pixels(const View1& view1, const View2& view2) {
  650. typedef mpl::bool_<is_planar<View1>::value && is_planar<View2>::value> is_planar;
  651. assert(view1.dimensions()==view2.dimensions());
  652. if (view1.is_1d_traversable() && view2.is_1d_traversable())
  653. detail::uninitialized_copy_aux(view1.begin().x(), view1.end().x(),
  654. view2.begin().x(),
  655. is_planar());
  656. else {
  657. typename View1::y_coord_t y = 0;
  658. try {
  659. for (y=0; y<view1.height(); ++y)
  660. detail::uninitialized_copy_aux(view1.row_begin(y), view1.row_end(y),
  661. view2.row_begin(y),
  662. is_planar());
  663. } catch(...) {
  664. for (typename View1::y_coord_t y0=0; y0<y; ++y0)
  665. detail::destruct_aux(view2.row_begin(y0),view2.row_end(y0), is_planar());
  666. throw;
  667. }
  668. }
  669. }
  670. //////////////////////////////////////////////////////////////////////////////////////
  671. ///
  672. /// for_each_pixel
  673. ///
  674. //////////////////////////////////////////////////////////////////////////////////////
  675. /// \defgroup ImageViewSTLAlgorithmsForEachPixel for_each_pixel
  676. /// \ingroup ImageViewSTLAlgorithms
  677. /// \brief std::for_each for image views
  678. ///
  679. /// For contiguous images (i.e. images that have no alignment gap at the end of each row) it is
  680. /// more efficient to use the underlying pixel iterator that does not check for the end of rows.
  681. /// For non-contiguous images for_each_pixel resolves to for_each of each row using the underlying
  682. /// pixel iterator, which is still faster
  683. /// \ingroup ImageViewSTLAlgorithmsForEachPixel
  684. template <typename V, typename F>
  685. F for_each_pixel(const V& img, F fun) {
  686. if (img.is_1d_traversable()) {
  687. return std::for_each(img.begin().x(), img.end().x(), fun);
  688. } else {
  689. for (std::ptrdiff_t y=0; y<img.height(); ++y)
  690. fun = std::for_each(img.row_begin(y),img.row_end(y),fun);
  691. return fun;
  692. }
  693. }
  694. /// \defgroup ImageViewSTLAlgorithmsForEachPixelPosition for_each_pixel_position
  695. /// \ingroup ImageViewSTLAlgorithms
  696. /// \brief adobe::for_each_position for image views (passes locators, instead of pixel references, to the function object)
  697. /// \ingroup ImageViewSTLAlgorithmsForEachPixelPosition
  698. template <typename View, typename F>
  699. F for_each_pixel_position(const View& img, F fun) {
  700. typename View::xy_locator loc=img.xy_at(0,0);
  701. for (std::ptrdiff_t y=0; y<img.height(); ++y) {
  702. for (std::ptrdiff_t x=0; x<img.width(); ++x, ++loc.x())
  703. fun(loc);
  704. loc.x()-=img.width(); ++loc.y();
  705. }
  706. return fun;
  707. }
  708. //////////////////////////////////////////////////////////////////////////////////////
  709. ///
  710. /// generate_pixels
  711. ///
  712. //////////////////////////////////////////////////////////////////////////////////////
  713. /// \defgroup ImageViewSTLAlgorithmsGeneratePixels generate_pixels
  714. /// \ingroup ImageViewSTLAlgorithms
  715. /// \brief std::generate for image views
  716. /// \ingroup ImageViewSTLAlgorithmsGeneratePixels
  717. /// \brief std::generate for image views
  718. template <typename View, typename F>
  719. void generate_pixels(const View& v, F fun) {
  720. if (v.is_1d_traversable()) {
  721. std::generate(v.begin().x(), v.end().x(), fun);
  722. } else {
  723. for (std::ptrdiff_t y=0; y<v.height(); ++y)
  724. std::generate(v.row_begin(y),v.row_end(y),fun);
  725. }
  726. }
  727. //////////////////////////////////////////////////////////////////////////////////////
  728. ///
  729. /// std::equal and gil::equal_pixels for GIL constructs
  730. ///
  731. //////////////////////////////////////////////////////////////////////////////////////
  732. /// \defgroup ImageViewSTLAlgorithmsEqualPixels equal_pixels
  733. /// \ingroup ImageViewSTLAlgorithms
  734. /// \brief std::equal for image views
  735. template <typename I1, typename I2> BOOST_FORCEINLINE bool equal_n(I1 i1, std::ptrdiff_t n, I2 i2);
  736. namespace detail {
  737. template <typename I1, typename I2>
  738. struct equal_n_fn {
  739. BOOST_FORCEINLINE bool operator()(I1 i1, std::ptrdiff_t n, I2 i2) const { return std::equal(i1,i1+n, i2); }
  740. };
  741. /// Equal when both ranges are interleaved and of the same type.
  742. /// GIL pixels are bitwise comparable, so memcmp is used. User-defined pixels that are not bitwise comparable need to provide an overload
  743. template<typename T, typename Cs>
  744. struct equal_n_fn<const pixel<T,Cs>*, const pixel<T,Cs>*> {
  745. BOOST_FORCEINLINE bool operator()(const pixel<T,Cs>* i1, std::ptrdiff_t n, const pixel<T,Cs>* i2) const {
  746. return memcmp(i1, i2, n*sizeof(pixel<T,Cs>))==0;
  747. }
  748. };
  749. template<typename T, typename Cs>
  750. struct equal_n_fn<pixel<T,Cs>*, pixel<T,Cs>*> : equal_n_fn<const pixel<T,Cs>*, const pixel<T,Cs>*> {};
  751. /// EqualPixels
  752. /// Equal when both ranges are planar pointers of the same type. memcmp is invoked for each channel plane
  753. /// User-defined channels that are not bitwise comparable need to provide an overload
  754. template<typename IC, typename Cs>
  755. struct equal_n_fn<planar_pixel_iterator<IC,Cs>, planar_pixel_iterator<IC,Cs> > {
  756. BOOST_FORCEINLINE bool operator()(const planar_pixel_iterator<IC,Cs> i1, std::ptrdiff_t n, const planar_pixel_iterator<IC,Cs> i2) const {
  757. std::ptrdiff_t numBytes=n*sizeof(typename std::iterator_traits<IC>::value_type);
  758. for (std::ptrdiff_t i=0; i<mpl::size<Cs>::value; ++i)
  759. if (memcmp(dynamic_at_c(i1,i), dynamic_at_c(i2,i), numBytes)!=0)
  760. return false;
  761. return true;
  762. }
  763. };
  764. /// Source range is delimited by image iterators
  765. template <typename Loc, typename I2> // IL Models ConstPixelLocatorConcept, O Models PixelIteratorConcept
  766. struct equal_n_fn<boost::gil::iterator_from_2d<Loc>,I2> {
  767. BOOST_FORCEINLINE bool operator()(boost::gil::iterator_from_2d<Loc> i1, std::ptrdiff_t n, I2 i2) const {
  768. gil_function_requires<boost::gil::PixelLocatorConcept<Loc> >();
  769. gil_function_requires<boost::gil::PixelIteratorConcept<I2> >();
  770. while (n>0) {
  771. std::ptrdiff_t num=std::min<const std::ptrdiff_t>(n, i1.width()-i1.x_pos());
  772. if (!equal_n(i1.x(), num, i2))
  773. return false;
  774. i1+=num;
  775. i2+=num;
  776. n-=num;
  777. }
  778. return true;
  779. }
  780. };
  781. /// Destination range is delimited by image iterators
  782. template <typename I1, typename Loc> // I Models PixelIteratorConcept, OL Models PixelLocatorConcept
  783. struct equal_n_fn<I1,boost::gil::iterator_from_2d<Loc> > {
  784. BOOST_FORCEINLINE bool operator()(I1 i1, std::ptrdiff_t n, boost::gil::iterator_from_2d<Loc> i2) const {
  785. gil_function_requires<boost::gil::PixelIteratorConcept<I1> >();
  786. gil_function_requires<boost::gil::PixelLocatorConcept<Loc> >();
  787. while (n>0) {
  788. std::ptrdiff_t num=std::min<const std::ptrdiff_t>(n,i2.width()-i2.x_pos());
  789. if (!equal_n(i1, num, i2.x()))
  790. return false;
  791. i1+=num;
  792. i2+=num;
  793. n-=num;
  794. }
  795. return true;
  796. }
  797. };
  798. /// Both source and destination ranges are delimited by image iterators
  799. template <typename Loc1, typename Loc2>
  800. struct equal_n_fn<boost::gil::iterator_from_2d<Loc1>,boost::gil::iterator_from_2d<Loc2> > {
  801. BOOST_FORCEINLINE bool operator()(boost::gil::iterator_from_2d<Loc1> i1, std::ptrdiff_t n, boost::gil::iterator_from_2d<Loc2> i2) const {
  802. gil_function_requires<boost::gil::PixelLocatorConcept<Loc1> >();
  803. gil_function_requires<boost::gil::PixelLocatorConcept<Loc2> >();
  804. if (i1.x_pos()!=i2.x_pos() || i1.width()!=i2.width()) {
  805. while(n-->0) {
  806. if (*i1++!=*i2++) return false;
  807. }
  808. }
  809. while (n>0) {
  810. std::ptrdiff_t num=std::min<const std::ptrdiff_t>(n,i2.width()-i2.x_pos());
  811. if (!equal_n(i1.x(), num, i2.x()))
  812. return false;
  813. i1+=num;
  814. i2+=num;
  815. n-=num;
  816. }
  817. return true;
  818. }
  819. };
  820. } // namespace detail
  821. template <typename I1, typename I2> BOOST_FORCEINLINE
  822. bool equal_n(I1 i1, std::ptrdiff_t n, I2 i2) {
  823. return detail::equal_n_fn<I1,I2>()(i1,n,i2);
  824. }
  825. } } // namespace boost::gil
  826. namespace std {
  827. /// \ingroup STLOptimizations
  828. /// \brief std::equal(I1,I1,I2) with I1 and I2 being a iterator_from_2d
  829. ///
  830. /// Invoked when one calls std::equal(I1,I1,I2) with I1 and I2 being a iterator_from_2d (which is
  831. /// a 1D iterator over the pixels in an image). Attempts to demote the source and destination
  832. /// iterators to simpler/faster types if the corresponding range is contiguous.
  833. /// For contiguous images (i.e. images that have
  834. /// no alignment gap at the end of each row) it is more efficient to use the underlying
  835. /// pixel iterator that does not check for the end of rows. If the underlying pixel iterator
  836. /// happens to be a fundamental planar/interleaved pointer, the call may further resolve
  837. /// to memcmp. Otherwise it resolves to copying each row using the underlying pixel iterator
  838. template <typename Loc1, typename Loc2> BOOST_FORCEINLINE
  839. bool equal(boost::gil::iterator_from_2d<Loc1> first, boost::gil::iterator_from_2d<Loc1> last, boost::gil::iterator_from_2d<Loc2> first2) {
  840. boost::gil::gil_function_requires<boost::gil::PixelLocatorConcept<Loc1> >();
  841. boost::gil::gil_function_requires<boost::gil::PixelLocatorConcept<Loc2> >();
  842. std::ptrdiff_t n=last-first;
  843. if (first.is_1d_traversable()) {
  844. if (first2.is_1d_traversable())
  845. return boost::gil::detail::equal_n_fn<typename Loc1::x_iterator,typename Loc2::x_iterator>()(first.x(),n, first2.x());
  846. else
  847. return boost::gil::detail::equal_n_fn<typename Loc1::x_iterator,boost::gil::iterator_from_2d<Loc2> >()(first.x(),n, first2);
  848. } else {
  849. if (first2.is_1d_traversable())
  850. return boost::gil::detail::equal_n_fn<boost::gil::iterator_from_2d<Loc1>,typename Loc2::x_iterator>()(first,n, first2.x());
  851. else
  852. return boost::gil::detail::equal_n_fn<boost::gil::iterator_from_2d<Loc1>,boost::gil::iterator_from_2d<Loc2> >()(first,n,first2);
  853. }
  854. }
  855. } // namespace std
  856. namespace boost { namespace gil {
  857. /// \ingroup ImageViewSTLAlgorithmsEqualPixels
  858. /// \brief std::equal for image views
  859. template <typename View1, typename View2> BOOST_FORCEINLINE
  860. bool equal_pixels(const View1& v1, const View2& v2) {
  861. assert(v1.dimensions()==v2.dimensions());
  862. return std::equal(v1.begin(),v1.end(),v2.begin()); // std::equal has overloads with GIL iterators for optimal performance
  863. }
  864. //////////////////////////////////////////////////////////////////////////////////////
  865. ///
  866. /// transform_pixels
  867. ///
  868. //////////////////////////////////////////////////////////////////////////////////////
  869. /// \defgroup ImageViewSTLAlgorithmsTransformPixels transform_pixels
  870. /// \ingroup ImageViewSTLAlgorithms
  871. /// \brief std::transform for image views
  872. /// \ingroup ImageViewSTLAlgorithmsTransformPixels
  873. /// \brief std::transform for image views
  874. template <typename View1, typename View2, typename F> BOOST_FORCEINLINE
  875. F transform_pixels(const View1& src,const View2& dst, F fun) {
  876. assert(src.dimensions()==dst.dimensions());
  877. for (std::ptrdiff_t y=0; y<src.height(); ++y) {
  878. typename View1::x_iterator srcIt=src.row_begin(y);
  879. typename View2::x_iterator dstIt=dst.row_begin(y);
  880. for (std::ptrdiff_t x=0; x<src.width(); ++x)
  881. dstIt[x]=fun(srcIt[x]);
  882. }
  883. return fun;
  884. }
  885. /// \ingroup ImageViewSTLAlgorithmsTransformPixels
  886. /// \brief transform_pixels with two sources
  887. template <typename View1, typename View2, typename View3, typename F> BOOST_FORCEINLINE
  888. F transform_pixels(const View1& src1, const View2& src2,const View3& dst, F fun) {
  889. for (std::ptrdiff_t y=0; y<dst.height(); ++y) {
  890. typename View1::x_iterator srcIt1=src1.row_begin(y);
  891. typename View2::x_iterator srcIt2=src2.row_begin(y);
  892. typename View3::x_iterator dstIt=dst.row_begin(y);
  893. for (std::ptrdiff_t x=0; x<dst.width(); ++x)
  894. dstIt[x]=fun(srcIt1[x],srcIt2[x]);
  895. }
  896. return fun;
  897. }
  898. /// \defgroup ImageViewSTLAlgorithmsTransformPixelPositions transform_pixel_positions
  899. /// \ingroup ImageViewSTLAlgorithms
  900. /// \brief adobe::transform_positions for image views (passes locators, instead of pixel references, to the function object)
  901. /// \ingroup ImageViewSTLAlgorithmsTransformPixelPositions
  902. /// \brief Like transform_pixels but passes to the function object pixel locators instead of pixel references
  903. template <typename View1, typename View2, typename F> BOOST_FORCEINLINE
  904. F transform_pixel_positions(const View1& src,const View2& dst, F fun) {
  905. assert(src.dimensions()==dst.dimensions());
  906. typename View1::xy_locator loc=src.xy_at(0,0);
  907. for (std::ptrdiff_t y=0; y<src.height(); ++y) {
  908. typename View2::x_iterator dstIt=dst.row_begin(y);
  909. for (std::ptrdiff_t x=0; x<src.width(); ++x, ++loc.x())
  910. dstIt[x]=fun(loc);
  911. loc.x()-=src.width(); ++loc.y();
  912. }
  913. return fun;
  914. }
  915. /// \ingroup ImageViewSTLAlgorithmsTransformPixelPositions
  916. /// \brief transform_pixel_positions with two sources
  917. template <typename View1, typename View2, typename View3, typename F> BOOST_FORCEINLINE
  918. F transform_pixel_positions(const View1& src1,const View2& src2,const View3& dst, F fun) {
  919. assert(src1.dimensions()==dst.dimensions());
  920. assert(src2.dimensions()==dst.dimensions());
  921. typename View1::xy_locator loc1=src1.xy_at(0,0);
  922. typename View2::xy_locator loc2=src2.xy_at(0,0);
  923. for (std::ptrdiff_t y=0; y<src1.height(); ++y) {
  924. typename View3::x_iterator dstIt=dst.row_begin(y);
  925. for (std::ptrdiff_t x=0; x<src1.width(); ++x, ++loc1.x(), ++loc2.x())
  926. dstIt[x]=fun(loc1,loc2);
  927. loc1.x()-=src1.width(); ++loc1.y();
  928. loc2.x()-=src2.width(); ++loc2.y();
  929. }
  930. return fun;
  931. }
  932. } } // namespace boost::gil
  933. //#ifdef _MSC_VER
  934. //#pragma warning(pop)
  935. //#endif
  936. #endif