algorithm.hpp 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607
  1. //
  2. // Copyright 2005-2007 Adobe Systems Incorporated
  3. // Copyright 2021 Pranam Lashkari <[email protected]>
  4. //
  5. // Distributed under the Boost Software License, Version 1.0
  6. // See accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt
  8. //
  9. #ifndef BOOST_GIL_ALGORITHM_HPP
  10. #define BOOST_GIL_ALGORITHM_HPP
  11. #include <boost/gil/metafunctions.hpp>
  12. #include <boost/gil/pixel_iterator.hpp>
  13. #include <boost/gil/pixel_numeric_operations.hpp>
  14. #include <boost/gil/image.hpp>
  15. #include <boost/gil/bit_aligned_pixel_iterator.hpp>
  16. #include <boost/gil/color_base_algorithm.hpp>
  17. #include <boost/gil/concepts.hpp>
  18. #include <boost/gil/image_view.hpp>
  19. #include <boost/gil/image_view_factory.hpp>
  20. #include <boost/gil/detail/mp11.hpp>
  21. #include <boost/gil/detail/type_traits.hpp>
  22. #include <boost/assert.hpp>
  23. #include <boost/config.hpp>
  24. #include <algorithm>
  25. #include <cstddef>
  26. #include <cstring>
  27. #include <iterator>
  28. #include <memory>
  29. #include <type_traits>
  30. #include <typeinfo>
  31. #include <numeric>
  32. namespace boost { namespace gil {
  33. //forward declarations
  34. template <typename ChannelPtr, typename ColorSpace>
  35. struct planar_pixel_iterator;
  36. template <typename Iterator>
  37. class memory_based_step_iterator;
  38. template <typename StepIterator>
  39. class memory_based_2d_locator;
  40. // a tag denoting incompatible arguments
  41. struct error_t {};
  42. /// \defgroup ImageViewSTLAlgorithms STL-like Algorithms
  43. /// \ingroup ImageViewAlgorithm
  44. /// \brief Image view-equivalents of STL algorithms
  45. ///
  46. /// Image views provide 1D iteration of their pixels via \p begin() and \p end() methods,
  47. /// which makes it possible to use STL algorithms with them. However, using nested loops
  48. /// over X and Y is in many cases more efficient. The algorithms in this section resemble
  49. /// STL algorithms, but they abstract away the nested loops and take views (as opposed to ranges) as input.
  50. ///
  51. /// Most algorithms check whether the image views are 1D-traversable. A 1D-traversable image view has no gaps
  52. /// 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
  53. /// it will move to the first pixel of the next row. When image views are 1D-traversable, the algorithms use
  54. /// a single loop and run more efficiently. If one or more of the input views are not 1D-traversable, the algorithms
  55. /// fall-back to an X-loop nested inside a Y-loop.
  56. ///
  57. /// The algorithms typically delegate the work to their corresponding STL algorithms. For example, \p copy_pixels calls
  58. /// \p std::copy either for each row, or, when the images are 1D-traversable, once for all pixels.
  59. ///
  60. /// In addition, overloads are sometimes provided for the STL algorithms. For example, std::copy for planar iterators
  61. /// is overloaded to perform \p std::copy for each of the planes. \p std::copy over bitwise-copiable pixels results in
  62. /// std::copy over unsigned char, which STL typically implements via \p memmove.
  63. ///
  64. /// As a result \p copy_pixels may result in a single call to \p memmove for interleaved 1D-traversable views,
  65. /// or one per each plane of planar 1D-traversable views, or one per each row of interleaved non-1D-traversable images, etc.
  66. /// \defgroup STLOptimizations Performance overloads of STL algorithms
  67. /// \ingroup ImageViewAlgorithm
  68. /// \brief overloads of STL algorithms allowing more efficient implementation when used with GIL constructs
  69. /// \brief A generic binary operation on views
  70. /// \ingroup ImageViewSTLAlgorithms
  71. ///
  72. /// Use this class as a convenience superclass when defining an operation for any image views.
  73. /// Many operations have different behavior when the two views are compatible. This class checks
  74. /// for compatibility and invokes apply_compatible(V1,V2) or apply_incompatible(V1,V2) of the subclass.
  75. /// You must provide apply_compatible(V1,V2) method in your subclass, but apply_incompatible(V1,V2)
  76. /// is not required and the default throws std::bad_cast.
  77. template <typename Derived, typename Result=void>
  78. struct binary_operation_obj
  79. {
  80. using result_type = Result;
  81. template <typename V1, typename V2> BOOST_FORCEINLINE
  82. auto operator()(const std::pair<const V1*,const V2*>& p) const -> result_type {
  83. return apply(*p.first, *p.second, typename views_are_compatible<V1,V2>::type());
  84. }
  85. template <typename V1, typename V2> BOOST_FORCEINLINE
  86. auto operator()(const V1& v1, const V2& v2) const -> result_type {
  87. return apply(v1, v2, typename views_are_compatible<V1,V2>::type());
  88. }
  89. auto operator()(const error_t&) const -> result_type { throw std::bad_cast(); }
  90. private:
  91. // dispatch from apply overload to a function with distinct name
  92. template <typename V1, typename V2>
  93. BOOST_FORCEINLINE
  94. auto apply(V1 const& v1, V2 const& v2, std::false_type) const -> result_type
  95. {
  96. return ((const Derived*)this)->apply_incompatible(v1, v2);
  97. }
  98. // dispatch from apply overload to a function with distinct name
  99. template <typename V1, typename V2>
  100. BOOST_FORCEINLINE
  101. auto apply(V1 const& v1, V2 const& v2, std::true_type) const -> result_type
  102. {
  103. return ((const Derived*)this)->apply_compatible(v1, v2);
  104. }
  105. // function with distinct name - it can be overloaded by subclasses
  106. template <typename V1, typename V2>
  107. BOOST_FORCEINLINE
  108. auto apply_incompatible(V1 const& /*v1*/, V2 const& /*v2*/) const -> result_type
  109. {
  110. throw std::bad_cast();
  111. }
  112. };
  113. }} // namespace boost::gil
  114. //////////////////////////////////////////////////////////////////////////////////////
  115. // std::copy and gil::copy_pixels
  116. //////////////////////////////////////////////////////////////////////////////////////
  117. /// \defgroup ImageViewSTLAlgorithmsCopyPixels copy_pixels
  118. /// \ingroup ImageViewSTLAlgorithms
  119. /// \brief std::copy for image views
  120. namespace std {
  121. /// \ingroup STLOptimizations
  122. /// \brief Copy when both src and dst are interleaved and of the same type can be just memmove
  123. template<typename T, typename CS>
  124. BOOST_FORCEINLINE
  125. auto copy(
  126. boost::gil::pixel<T, CS>* first,
  127. boost::gil::pixel<T, CS>* last,
  128. boost::gil::pixel<T, CS>* dst)
  129. -> boost::gil::pixel<T, CS>*
  130. {
  131. auto p = std::copy((unsigned char*)first, (unsigned char*)last, (unsigned char*)dst);
  132. return reinterpret_cast<boost::gil::pixel<T, CS>*>(p);
  133. }
  134. /// \ingroup STLOptimizations
  135. /// \brief Copy when both src and dst are interleaved and of the same type can be just memmove
  136. template<typename T, typename CS>
  137. BOOST_FORCEINLINE
  138. auto copy(const boost::gil::pixel<T,CS>* first, const boost::gil::pixel<T,CS>* last,
  139. boost::gil::pixel<T,CS>* dst) -> boost::gil::pixel<T,CS>*
  140. {
  141. return (boost::gil::pixel<T,CS>*)std::copy((unsigned char*)first,(unsigned char*)last, (unsigned char*)dst);
  142. }
  143. } // namespace std
  144. namespace boost { namespace gil {
  145. namespace detail {
  146. template <typename I, typename O> struct copy_fn {
  147. BOOST_FORCEINLINE I operator()(I first, I last, O dst) const { return std::copy(first,last,dst); }
  148. };
  149. } // namespace detail
  150. } } // namespace boost::gil
  151. namespace std {
  152. /// \ingroup STLOptimizations
  153. /// \brief Copy when both src and dst are planar pointers is copy for each channel
  154. template<typename CS, typename IC1, typename IC2> BOOST_FORCEINLINE
  155. auto 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) -> boost::gil::planar_pixel_iterator<IC2,CS>
  156. {
  157. boost::gil::gil_function_requires<boost::gil::ChannelsCompatibleConcept<typename std::iterator_traits<IC1>::value_type,typename std::iterator_traits<IC2>::value_type>>();
  158. static_for_each(first,last,dst,boost::gil::detail::copy_fn<IC1,IC2>());
  159. return dst+(last-first);
  160. }
  161. } // namespace std
  162. namespace boost { namespace gil {
  163. namespace detail {
  164. /// Does a copy-n. If the inputs contain image iterators, performs a copy at each row using the row iterators
  165. /// \ingroup CopyPixels
  166. template <typename I, typename O>
  167. struct copier_n {
  168. BOOST_FORCEINLINE void operator()(I src, typename std::iterator_traits<I>::difference_type n, O dst) const { std::copy(src,src+n, dst); }
  169. };
  170. /// Source range is delimited by image iterators
  171. template <typename IL, typename O> // IL Models ConstPixelLocatorConcept, O Models PixelIteratorConcept
  172. struct copier_n<iterator_from_2d<IL>,O> {
  173. using diff_t = typename std::iterator_traits<iterator_from_2d<IL>>::difference_type;
  174. BOOST_FORCEINLINE void operator()(iterator_from_2d<IL> src, diff_t n, O dst) const {
  175. gil_function_requires<PixelLocatorConcept<IL>>();
  176. gil_function_requires<MutablePixelIteratorConcept<O>>();
  177. while (n>0) {
  178. diff_t l=src.width()-src.x_pos();
  179. diff_t numToCopy=(n<l ? n:l);
  180. detail::copy_n(src.x(), numToCopy, dst);
  181. dst+=numToCopy;
  182. src+=numToCopy;
  183. n-=numToCopy;
  184. }
  185. }
  186. };
  187. /// Destination range is delimited by image iterators
  188. template <typename I, typename OL> // I Models ConstPixelIteratorConcept, OL Models PixelLocatorConcept
  189. struct copier_n<I,iterator_from_2d<OL>> {
  190. using diff_t = typename std::iterator_traits<I>::difference_type;
  191. BOOST_FORCEINLINE void operator()(I src, diff_t n, iterator_from_2d<OL> dst) const {
  192. gil_function_requires<PixelIteratorConcept<I>>();
  193. gil_function_requires<MutablePixelLocatorConcept<OL>>();
  194. while (n>0) {
  195. diff_t l=dst.width()-dst.x_pos();
  196. diff_t numToCopy=(n<l ? n:l);
  197. detail::copy_n(src, numToCopy, dst.x());
  198. dst+=numToCopy;
  199. src+=numToCopy;
  200. n-=numToCopy;
  201. }
  202. }
  203. };
  204. /// Both source and destination ranges are delimited by image iterators
  205. template <typename IL, typename OL>
  206. struct copier_n<iterator_from_2d<IL>,iterator_from_2d<OL>> {
  207. using diff_t = typename iterator_from_2d<IL>::difference_type;
  208. BOOST_FORCEINLINE void operator()(iterator_from_2d<IL> src, diff_t n, iterator_from_2d<OL> dst) const {
  209. gil_function_requires<PixelLocatorConcept<IL>>();
  210. gil_function_requires<MutablePixelLocatorConcept<OL>>();
  211. if (src.x_pos()!=dst.x_pos() || src.width()!=dst.width()) {
  212. while(n-->0) {
  213. *dst++=*src++;
  214. }
  215. }
  216. while (n>0) {
  217. diff_t l=dst.width()-dst.x_pos();
  218. diff_t numToCopy=(n<l ? n : l);
  219. detail::copy_n(src.x(), numToCopy, dst.x());
  220. dst+=numToCopy;
  221. src+=numToCopy;
  222. n-=numToCopy;
  223. }
  224. }
  225. };
  226. template <typename SrcIterator, typename DstIterator>
  227. BOOST_FORCEINLINE auto copy_with_2d_iterators(SrcIterator first, SrcIterator last, DstIterator dst) -> DstIterator {
  228. using src_x_iterator = typename SrcIterator::x_iterator;
  229. using dst_x_iterator = typename DstIterator::x_iterator;
  230. typename SrcIterator::difference_type n = last - first;
  231. if (first.is_1d_traversable()) {
  232. if (dst.is_1d_traversable())
  233. copier_n<src_x_iterator,dst_x_iterator>()(first.x(),n, dst.x());
  234. else
  235. copier_n<src_x_iterator,DstIterator >()(first.x(),n, dst);
  236. } else {
  237. if (dst.is_1d_traversable())
  238. copier_n<SrcIterator,dst_x_iterator>()(first,n, dst.x());
  239. else
  240. copier_n<SrcIterator,DstIterator>()(first,n,dst);
  241. }
  242. return dst+n;
  243. }
  244. } // namespace detail
  245. } } // namespace boost::gil
  246. namespace std {
  247. /// \ingroup STLOptimizations
  248. /// \brief std::copy(I1,I1,I2) with I1 and I2 being a iterator_from_2d
  249. template <typename IL, typename OL>
  250. BOOST_FORCEINLINE auto copy1(boost::gil::iterator_from_2d<IL> first, boost::gil::iterator_from_2d<IL> last, boost::gil::iterator_from_2d<OL> dst) -> boost::gil::iterator_from_2d<OL>
  251. {
  252. return boost::gil::detail::copy_with_2d_iterators(first,last,dst);
  253. }
  254. } // namespace std
  255. namespace boost { namespace gil {
  256. /// \ingroup ImageViewSTLAlgorithmsCopyPixels
  257. /// \brief std::copy for image views
  258. template <typename View1, typename View2> BOOST_FORCEINLINE
  259. void copy_pixels(const View1& src, const View2& dst)
  260. {
  261. BOOST_ASSERT(src.dimensions() == dst.dimensions());
  262. detail::copy_with_2d_iterators(src.begin(),src.end(),dst.begin());
  263. }
  264. //////////////////////////////////////////////////////////////////////////////////////
  265. // copy_and_convert_pixels
  266. //////////////////////////////////////////////////////////////////////////////////////
  267. /// \defgroup ImageViewSTLAlgorithmsCopyAndConvertPixels copy_and_convert_pixels
  268. /// \ingroup ImageViewSTLAlgorithms
  269. /// \brief copies src view into dst view, color converting if necessary.
  270. ///
  271. /// Versions taking static and runtime views are provided. Versions taking user-defined color convered are provided.
  272. namespace detail {
  273. template <typename CC>
  274. class copy_and_convert_pixels_fn : public binary_operation_obj<copy_and_convert_pixels_fn<CC>>
  275. {
  276. private:
  277. CC _cc;
  278. public:
  279. using result_type = typename binary_operation_obj<copy_and_convert_pixels_fn<default_color_converter>>::result_type;
  280. copy_and_convert_pixels_fn() {}
  281. copy_and_convert_pixels_fn(CC cc_in) : _cc(cc_in) {}
  282. // when the two color spaces are incompatible, a color conversion is performed
  283. template <typename V1, typename V2> BOOST_FORCEINLINE
  284. auto apply_incompatible(const V1& src, const V2& dst) const -> result_type {
  285. copy_pixels(color_converted_view<typename V2::value_type>(src,_cc),dst);
  286. }
  287. // If the two color spaces are compatible, copy_and_convert is just copy
  288. template <typename V1, typename V2> BOOST_FORCEINLINE
  289. auto apply_compatible(const V1& src, const V2& dst) const -> result_type {
  290. copy_pixels(src,dst);
  291. }
  292. };
  293. } // namespace detail
  294. /// \ingroup ImageViewSTLAlgorithmsCopyAndConvertPixels
  295. template <typename V1, typename V2,typename CC>
  296. BOOST_FORCEINLINE
  297. void copy_and_convert_pixels(const V1& src, const V2& dst,CC cc) {
  298. detail::copy_and_convert_pixels_fn<CC> ccp(cc);
  299. ccp(src,dst);
  300. }
  301. struct default_color_converter;
  302. /// \ingroup ImageViewSTLAlgorithmsCopyAndConvertPixels
  303. template <typename View1, typename View2>
  304. BOOST_FORCEINLINE
  305. void copy_and_convert_pixels(const View1& src, const View2& dst) {
  306. detail::copy_and_convert_pixels_fn<default_color_converter> ccp;
  307. ccp(src,dst);
  308. }
  309. } } // namespace boost::gil
  310. //////////////////////////////////////////////////////////////////////////////////////
  311. // std::fill and gil::fill_pixels
  312. //////////////////////////////////////////////////////////////////////////////////////
  313. /// \defgroup ImageViewSTLAlgorithmsFillPixels fill_pixels
  314. /// \ingroup ImageViewSTLAlgorithms
  315. /// \brief std::fill for image views
  316. namespace std {
  317. /// \ingroup STLOptimizations
  318. /// \brief std::fill(I,I,V) with I being a iterator_from_2d
  319. ///
  320. /// Invoked when one calls std::fill(I,I,V) with I being a iterator_from_2d (which is
  321. /// a 1D iterator over the pixels in an image). For contiguous images (i.e. images that have
  322. /// no alignment gap at the end of each row) it is more efficient to use the underlying
  323. /// pixel iterator that does not check for the end of rows. For non-contiguous images fill
  324. /// resolves to fill of each row using the underlying pixel iterator, which is still faster
  325. template <typename IL, typename V>
  326. void fill(boost::gil::iterator_from_2d<IL> first, boost::gil::iterator_from_2d<IL> last, const V& val) {
  327. boost::gil::gil_function_requires<boost::gil::MutablePixelLocatorConcept<IL>>();
  328. if (first.is_1d_traversable()) {
  329. std::fill(first.x(), last.x(), val);
  330. } else {
  331. // fill row by row
  332. std::ptrdiff_t n=last-first;
  333. while (n>0) {
  334. std::ptrdiff_t numToDo=std::min<const std::ptrdiff_t>(n,(std::ptrdiff_t)(first.width()-first.x_pos()));
  335. std::fill_n(first.x(), numToDo, val);
  336. first+=numToDo;
  337. n-=numToDo;
  338. }
  339. }
  340. }
  341. } // namespace std
  342. namespace boost { namespace gil {
  343. namespace detail {
  344. /// struct to do std::fill
  345. struct std_fill_t {
  346. template <typename It, typename P>
  347. void operator()(It first, It last, const P& p_in) {
  348. std::fill(first,last,p_in);
  349. }
  350. };
  351. /// std::fill for planar iterators
  352. template <typename It, typename P>
  353. BOOST_FORCEINLINE
  354. void fill_aux(It first, It last, P const& p, std::true_type)
  355. {
  356. static_for_each(first, last, p, std_fill_t());
  357. }
  358. /// std::fill for interleaved iterators
  359. template <typename It, typename P>
  360. BOOST_FORCEINLINE
  361. void fill_aux(It first, It last, P const& p, std::false_type)
  362. {
  363. std::fill(first, last, p);
  364. }
  365. } // namespace detail
  366. /// \ingroup ImageViewSTLAlgorithmsFillPixels
  367. /// \brief std::fill for image views
  368. template <typename View, typename Value>
  369. BOOST_FORCEINLINE
  370. void fill_pixels(View const& view, Value const& value)
  371. {
  372. if (view.is_1d_traversable())
  373. {
  374. detail::fill_aux(
  375. view.begin().x(), view.end().x(), value, is_planar<View>());
  376. }
  377. else
  378. {
  379. for (std::ptrdiff_t y = 0; y < view.height(); ++y)
  380. detail::fill_aux(
  381. view.row_begin(y), view.row_end(y), value, is_planar<View>());
  382. }
  383. }
  384. //////////////////////////////////////////////////////////////////////////////////////
  385. // destruct_pixels
  386. //////////////////////////////////////////////////////////////////////////////////////
  387. /// \defgroup ImageViewSTLAlgorithmsDestructPixels destruct_pixels
  388. /// \ingroup ImageViewSTLAlgorithms
  389. /// \brief invokes the destructor on every pixel of an image view
  390. namespace detail {
  391. template <typename Iterator>
  392. BOOST_FORCEINLINE
  393. void destruct_range_impl(Iterator first, Iterator last,
  394. typename std::enable_if
  395. <
  396. mp11::mp_and
  397. <
  398. std::is_pointer<Iterator>,
  399. mp11::mp_not
  400. <
  401. detail::is_trivially_destructible<typename std::iterator_traits<Iterator>::value_type>
  402. >
  403. >::value
  404. >::type* /*ptr*/ = 0)
  405. {
  406. while (first != last)
  407. {
  408. first->~value_t();
  409. ++first;
  410. }
  411. }
  412. template <typename Iterator>
  413. BOOST_FORCEINLINE
  414. void destruct_range_impl(Iterator /*first*/, Iterator /*last*/,
  415. typename std::enable_if
  416. <
  417. mp11::mp_or
  418. <
  419. mp11::mp_not<std::is_pointer<Iterator>>,
  420. detail::is_trivially_destructible<typename std::iterator_traits<Iterator>::value_type>
  421. >::value
  422. >::type* /* ptr */ = nullptr)
  423. {
  424. }
  425. template <typename Iterator>
  426. BOOST_FORCEINLINE
  427. void destruct_range(Iterator first, Iterator last)
  428. {
  429. destruct_range_impl(first, last);
  430. }
  431. struct std_destruct_t
  432. {
  433. template <typename Iterator>
  434. void operator()(Iterator first, Iterator last) const
  435. {
  436. destruct_range(first,last);
  437. }
  438. };
  439. /// destruct for planar iterators
  440. template <typename It>
  441. BOOST_FORCEINLINE
  442. void destruct_aux(It first, It last, std::true_type)
  443. {
  444. static_for_each(first,last,std_destruct_t());
  445. }
  446. /// destruct for interleaved iterators
  447. template <typename It>
  448. BOOST_FORCEINLINE
  449. void destruct_aux(It first, It last, std::false_type)
  450. {
  451. destruct_range(first,last);
  452. }
  453. } // namespace detail
  454. /// \ingroup ImageViewSTLAlgorithmsDestructPixels
  455. /// \brief Invokes the in-place destructor on every pixel of the view
  456. template <typename View>
  457. BOOST_FORCEINLINE
  458. void destruct_pixels(View const& view)
  459. {
  460. if (view.is_1d_traversable())
  461. {
  462. detail::destruct_aux(
  463. view.begin().x(), view.end().x(), is_planar<View>());
  464. }
  465. else
  466. {
  467. for (std::ptrdiff_t y = 0; y < view.height(); ++y)
  468. detail::destruct_aux(
  469. view.row_begin(y), view.row_end(y), is_planar<View>());
  470. }
  471. }
  472. //////////////////////////////////////////////////////////////////////////////////////
  473. // uninitialized_fill_pixels
  474. //////////////////////////////////////////////////////////////////////////////////////
  475. /// \defgroup ImageViewSTLAlgorithmsUninitializedFillPixels uninitialized_fill_pixels
  476. /// \ingroup ImageViewSTLAlgorithms
  477. /// \brief std::uninitialized_fill for image views
  478. namespace detail {
  479. /// std::uninitialized_fill for planar iterators
  480. /// If an exception is thrown destructs any in-place copy-constructed objects
  481. template <typename It, typename P>
  482. BOOST_FORCEINLINE
  483. void uninitialized_fill_aux(It first, It last, P const& p, std::true_type)
  484. {
  485. std::size_t channel = 0;
  486. try
  487. {
  488. using pixel_t = typename std::iterator_traits<It>::value_type;
  489. while (channel < num_channels<pixel_t>::value)
  490. {
  491. std::uninitialized_fill(
  492. dynamic_at_c(first,channel),
  493. dynamic_at_c(last,channel),
  494. dynamic_at_c(p,channel));
  495. ++channel;
  496. }
  497. }
  498. catch (...)
  499. {
  500. for (std::size_t c = 0; c < channel; ++c)
  501. destruct_range(dynamic_at_c(first, c), dynamic_at_c(last, c));
  502. throw;
  503. }
  504. }
  505. /// std::uninitialized_fill for interleaved iterators
  506. /// If an exception is thrown destructs any in-place copy-constructed objects
  507. template <typename It, typename P>
  508. BOOST_FORCEINLINE
  509. void uninitialized_fill_aux(It first, It last, P const& p, std::false_type)
  510. {
  511. std::uninitialized_fill(first,last,p);
  512. }
  513. } // namespace detail
  514. /// \ingroup ImageViewSTLAlgorithmsUninitializedFillPixels
  515. /// \brief std::uninitialized_fill for image views.
  516. /// Does not support planar heterogeneous views.
  517. /// If an exception is thrown destructs any in-place copy-constructed pixels
  518. template <typename View, typename Value>
  519. void uninitialized_fill_pixels(const View& view, const Value& val) {
  520. if (view.is_1d_traversable())
  521. detail::uninitialized_fill_aux(view.begin().x(), view.end().x(),
  522. val,is_planar<View>());
  523. else {
  524. typename View::y_coord_t y = 0;
  525. try {
  526. for (y=0; y<view.height(); ++y)
  527. detail::uninitialized_fill_aux(view.row_begin(y),view.row_end(y),
  528. val,is_planar<View>());
  529. } catch(...) {
  530. for (typename View::y_coord_t y0=0; y0<y; ++y0)
  531. detail::destruct_aux(view.row_begin(y0),view.row_end(y0), is_planar<View>());
  532. throw;
  533. }
  534. }
  535. }
  536. //////////////////////////////////////////////////////////////////////////////////////
  537. // default_construct_pixels
  538. //////////////////////////////////////////////////////////////////////////////////////
  539. /// \defgroup ImageViewSTLAlgorithmsDefaultConstructPixels default_construct_pixels
  540. /// \ingroup ImageViewSTLAlgorithms
  541. /// \brief invokes the default constructor on every pixel of an image view
  542. namespace detail {
  543. template <typename It> BOOST_FORCEINLINE
  544. void default_construct_range_impl(It first, It last, std::true_type)
  545. {
  546. It first1 = first;
  547. try
  548. {
  549. using value_t = typename std::iterator_traits<It>::value_type;
  550. while (first != last)
  551. {
  552. new (first) value_t();
  553. ++first;
  554. }
  555. }
  556. catch (...)
  557. {
  558. destruct_range(first1, first);
  559. throw;
  560. }
  561. }
  562. template <typename It>
  563. BOOST_FORCEINLINE
  564. void default_construct_range_impl(It, It, std::false_type) {}
  565. template <typename It>
  566. BOOST_FORCEINLINE
  567. void default_construct_range(It first, It last)
  568. {
  569. default_construct_range_impl(first, last, typename std::is_pointer<It>::type());
  570. }
  571. /// uninitialized_default_construct for planar iterators
  572. template <typename It>
  573. BOOST_FORCEINLINE
  574. void default_construct_aux(It first, It last, std::true_type)
  575. {
  576. std::size_t channel = 0;
  577. try
  578. {
  579. using pixel_t = typename std::iterator_traits<It>::value_type;
  580. while (channel < num_channels<pixel_t>::value)
  581. {
  582. default_construct_range(dynamic_at_c(first, channel), dynamic_at_c(last, channel));
  583. ++channel;
  584. }
  585. }
  586. catch (...)
  587. {
  588. for (std::size_t c = 0; c < channel; ++c)
  589. destruct_range(dynamic_at_c(first, c), dynamic_at_c(last, c));
  590. throw;
  591. }
  592. }
  593. /// uninitialized_default_construct for interleaved iterators
  594. template <typename It>
  595. BOOST_FORCEINLINE
  596. void default_construct_aux(It first, It last, std::false_type)
  597. {
  598. default_construct_range(first, last);
  599. }
  600. template <typename View, bool IsPlanar>
  601. struct has_trivial_pixel_constructor
  602. : detail::is_trivially_default_constructible<typename View::value_type>
  603. {};
  604. template <typename View>
  605. struct has_trivial_pixel_constructor<View, true>
  606. : detail::is_trivially_default_constructible<typename channel_type<View>::type>
  607. {};
  608. template<typename View, bool IsTriviallyConstructible>
  609. BOOST_FORCEINLINE
  610. void default_construct_pixels_impl(
  611. View const& view,
  612. std::enable_if<!IsTriviallyConstructible>* /*ptr*/ = nullptr)
  613. {
  614. if (view.is_1d_traversable())
  615. {
  616. detail::default_construct_aux(
  617. view.begin().x(), view.end().x(), is_planar<View>());
  618. }
  619. else
  620. {
  621. typename View::y_coord_t y = 0;
  622. try
  623. {
  624. for( y = 0; y < view.height(); ++y )
  625. detail::default_construct_aux(
  626. view.row_begin(y), view.row_end(y), is_planar<View>());
  627. }
  628. catch(...)
  629. {
  630. for (typename View::y_coord_t y0 = 0; y0 < y; ++y0 )
  631. detail::destruct_aux(
  632. view.row_begin(y0), view.row_end(y0), is_planar<View>());
  633. throw;
  634. }
  635. }
  636. }
  637. } // namespace detail
  638. /// \ingroup ImageViewSTLAlgorithmsDefaultConstructPixels
  639. /// \brief Invokes the in-place default constructor on every pixel of the (uninitialized) view.
  640. /// Does not support planar heterogeneous views.
  641. /// If an exception is thrown destructs any in-place default-constructed pixels
  642. template <typename View>
  643. void default_construct_pixels(View const& view)
  644. {
  645. detail::default_construct_pixels_impl
  646. <
  647. View,
  648. detail::has_trivial_pixel_constructor
  649. <
  650. View,
  651. is_planar<View>::value
  652. >::value
  653. >(view);
  654. }
  655. //////////////////////////////////////////////////////////////////////////////////////
  656. // uninitialized_copy_pixels
  657. //////////////////////////////////////////////////////////////////////////////////////
  658. /// \defgroup ImageViewSTLAlgorithmsUninitializedCopyPixels uninitialized_copy_pixels
  659. /// \ingroup ImageViewSTLAlgorithms
  660. /// \brief std::uninitialized_copy for image views
  661. namespace detail {
  662. enum class copy_planarity_condition
  663. {
  664. planar_to_planar,
  665. interleaved_to_planar,
  666. mixed_to_interleaved
  667. };
  668. using planar_to_planar_type =
  669. std::integral_constant
  670. <
  671. copy_planarity_condition, copy_planarity_condition::planar_to_planar
  672. >;
  673. using interleaved_to_planar_type =
  674. std::integral_constant
  675. <
  676. copy_planarity_condition, copy_planarity_condition::interleaved_to_planar
  677. >;
  678. using mixed_to_interleaved_type =
  679. std::integral_constant
  680. <
  681. copy_planarity_condition, copy_planarity_condition::mixed_to_interleaved
  682. >;
  683. /// std::uninitialized_copy for pairs of planar iterators
  684. template <typename It1, typename It2>
  685. BOOST_FORCEINLINE
  686. void uninitialized_copy_aux(It1 first1, It1 last1, It2 first2, It2 last2, planar_to_planar_type)
  687. {
  688. std::size_t channel=0;
  689. try {
  690. using pixel_t = typename std::iterator_traits<It1>::value_type;
  691. while (channel < num_channels<pixel_t>::value)
  692. {
  693. std::uninitialized_copy(
  694. dynamic_at_c(first1, channel),
  695. dynamic_at_c(last1, channel),
  696. dynamic_at_c(first2, channel));
  697. ++channel;
  698. }
  699. }
  700. catch (...)
  701. {
  702. It2 last2 = first2;
  703. std::advance(last2, std::distance(first1, last1));
  704. for (std::size_t c = 0; c < channel; ++c)
  705. destruct_range(dynamic_at_c(first2, c), dynamic_at_c(last2, c));
  706. throw;
  707. }
  708. }
  709. /// std::uninitialized_copy for interleaved or mixed(planar into interleaved) iterators
  710. template <typename It1, typename It2>
  711. BOOST_FORCEINLINE
  712. void uninitialized_copy_aux(It1 first1, It1 last1, It2 first2, It2, mixed_to_interleaved_type)
  713. {
  714. std::uninitialized_copy(first1, last1, first2);
  715. }
  716. /// std::uninitialized_copy for interleaved to planar iterators
  717. template <typename It1, typename It2>
  718. BOOST_FORCEINLINE
  719. void uninitialized_copy_aux(It1 first1, It1, It2 first2, It2 last2,
  720. interleaved_to_planar_type)
  721. {
  722. default_construct_aux(first2, last2, std::true_type());
  723. typename It2::difference_type n = last2 - first2;
  724. copier_n<It1,It2>()(first1, n, first2);
  725. }
  726. } // namespace detail
  727. /// \ingroup ImageViewSTLAlgorithmsUninitializedCopyPixels
  728. /// \brief std::uninitialized_copy for image views.
  729. /// Does not support planar heterogeneous views.
  730. /// If an exception is thrown destructs any in-place copy-constructed objects
  731. template <typename View1, typename View2>
  732. void uninitialized_copy_pixels(View1 const& view1, View2 const& view2)
  733. {
  734. using copy_planarity_condition = detail::copy_planarity_condition;
  735. using copy_planarity_condition_type =
  736. std::integral_constant
  737. <
  738. copy_planarity_condition,
  739. !is_planar<View2>::value
  740. ? copy_planarity_condition::mixed_to_interleaved
  741. : (is_planar<View1>::value
  742. ? copy_planarity_condition::planar_to_planar
  743. : copy_planarity_condition::interleaved_to_planar)
  744. >;
  745. BOOST_ASSERT(view1.dimensions() == view2.dimensions());
  746. if (view1.is_1d_traversable() && view2.is_1d_traversable())
  747. {
  748. detail::uninitialized_copy_aux(
  749. view1.begin().x(), view1.end().x(), view2.begin().x(), view2.end().x(),
  750. copy_planarity_condition_type());
  751. }
  752. else
  753. {
  754. typename View1::y_coord_t y = 0;
  755. try
  756. {
  757. for (y = 0; y < view1.height(); ++y)
  758. detail::uninitialized_copy_aux(
  759. view1.row_begin(y), view1.row_end(y), view2.row_begin(y), view2.row_end(y),
  760. copy_planarity_condition_type());
  761. }
  762. catch(...)
  763. {
  764. for (typename View1::y_coord_t y0 = 0; y0 < y; ++y0)
  765. detail::destruct_aux(view2.row_begin(y0), view2.row_end(y0), is_planar<View2>());
  766. throw;
  767. }
  768. }
  769. }
  770. //////////////////////////////////////////////////////////////////////////////////////
  771. // for_each_pixel
  772. //////////////////////////////////////////////////////////////////////////////////////
  773. /// \defgroup ImageViewSTLAlgorithmsForEachPixel for_each_pixel
  774. /// \ingroup ImageViewSTLAlgorithms
  775. /// \brief std::for_each for image views
  776. ///
  777. /// For contiguous images (i.e. images that have no alignment gap at the end of each row) it is
  778. /// more efficient to use the underlying pixel iterator that does not check for the end of rows.
  779. /// For non-contiguous images for_each_pixel resolves to for_each of each row using the underlying
  780. /// pixel iterator, which is still faster
  781. /// \ingroup ImageViewSTLAlgorithmsForEachPixel
  782. template <typename View, typename F>
  783. F for_each_pixel(View const& view, F fun)
  784. {
  785. if (view.is_1d_traversable())
  786. {
  787. return std::for_each(view.begin().x(), view.end().x(), fun);
  788. }
  789. else
  790. {
  791. for (std::ptrdiff_t y = 0; y < view.height(); ++y)
  792. for (auto begin = view.row_begin(y), end = view.row_end(y); begin != end; ++begin)
  793. fun(*begin);
  794. return fun;
  795. }
  796. }
  797. /// \defgroup ImageViewSTLAlgorithmsForEachPixelPosition for_each_pixel_position
  798. /// \ingroup ImageViewSTLAlgorithms
  799. /// \brief adobe::for_each_position for image views (passes locators, instead of pixel references, to the function object)
  800. /// \ingroup ImageViewSTLAlgorithmsForEachPixelPosition
  801. template <typename View, typename F>
  802. F for_each_pixel_position(View const& view, F fun)
  803. {
  804. typename View::xy_locator loc = view.xy_at(0, 0);
  805. for (std::ptrdiff_t y = 0; y < view.height(); ++y)
  806. {
  807. for (std::ptrdiff_t x = 0; x < view.width(); ++x, ++loc.x())
  808. fun(loc);
  809. loc.x() -= view.width(); ++loc.y();
  810. }
  811. return fun;
  812. }
  813. //////////////////////////////////////////////////////////////////////////////////////
  814. // generate_pixels
  815. //////////////////////////////////////////////////////////////////////////////////////
  816. /// \defgroup ImageViewSTLAlgorithmsGeneratePixels generate_pixels
  817. /// \ingroup ImageViewSTLAlgorithms
  818. /// \brief std::generate for image views
  819. /// \ingroup ImageViewSTLAlgorithmsGeneratePixels
  820. /// \brief std::generate for image views
  821. template <typename View, typename F>
  822. void generate_pixels(View const& view, F fun)
  823. {
  824. if (view.is_1d_traversable())
  825. {
  826. std::generate(view.begin().x(), view.end().x(), fun);
  827. }
  828. else
  829. {
  830. for (std::ptrdiff_t y = 0; y < view.height(); ++y)
  831. std::generate(view.row_begin(y), view.row_end(y), fun);
  832. }
  833. }
  834. //////////////////////////////////////////////////////////////////////////////////////
  835. // std::equal and gil::equal_pixels for GIL constructs
  836. //////////////////////////////////////////////////////////////////////////////////////
  837. /// \defgroup ImageViewSTLAlgorithmsEqualPixels equal_pixels
  838. /// \ingroup ImageViewSTLAlgorithms
  839. /// \brief std::equal for image views
  840. template <typename I1, typename I2>
  841. BOOST_FORCEINLINE
  842. bool equal_n(I1 i1, std::ptrdiff_t n, I2 i2);
  843. namespace detail {
  844. template <typename I1, typename I2>
  845. struct equal_n_fn
  846. {
  847. BOOST_FORCEINLINE
  848. bool operator()(I1 i1, std::ptrdiff_t n, I2 i2) const
  849. {
  850. return std::equal(i1, i1 + n, i2);
  851. }
  852. };
  853. /// Equal when both ranges are interleaved and of the same type.
  854. /// GIL pixels are bitwise comparable, so memcmp is used. User-defined pixels that are not bitwise comparable need to provide an overload
  855. template<typename T, typename CS>
  856. struct equal_n_fn<pixel<T, CS> const*, pixel<T, CS> const*>
  857. {
  858. BOOST_FORCEINLINE
  859. bool operator()(pixel<T, CS> const* i1, std::ptrdiff_t n, pixel<T, CS> const* i2) const
  860. {
  861. return memcmp(i1, i2, n * sizeof(pixel<T, CS>)) == 0;
  862. }
  863. };
  864. template<typename T, typename CS>
  865. struct equal_n_fn<pixel<T, CS>*, pixel<T, CS>*>
  866. : equal_n_fn<pixel<T, CS> const*, pixel<T, CS> const*>
  867. {};
  868. /// EqualPixels
  869. /// Equal when both ranges are planar pointers of the same type. memcmp is invoked for each channel plane
  870. /// User-defined channels that are not bitwise comparable need to provide an overload
  871. template<typename IC, typename CS>
  872. struct equal_n_fn<planar_pixel_iterator<IC, CS>, planar_pixel_iterator<IC, CS>>
  873. {
  874. BOOST_FORCEINLINE
  875. bool operator()(planar_pixel_iterator<IC, CS> const i1, std::ptrdiff_t n, planar_pixel_iterator<IC, CS> const i2) const
  876. {
  877. // FIXME: ptrdiff_t vs size_t
  878. constexpr std::ptrdiff_t byte_size = n * sizeof(typename std::iterator_traits<IC>::value_type);
  879. for (std::ptrdiff_t i = 0; i < mp11::mp_size<CS>::value; ++i)
  880. {
  881. if (memcmp(dynamic_at_c(i1, i), dynamic_at_c(i2, i), byte_size) != 0)
  882. return false;
  883. }
  884. return true;
  885. }
  886. };
  887. /// Source range is delimited by image iterators
  888. /// \tparam Loc Models ConstPixelLocatorConcept
  889. /// \tparam It Models PixelIteratorConcept
  890. template <typename Loc, typename It>
  891. struct equal_n_fn<boost::gil::iterator_from_2d<Loc>, It>
  892. {
  893. BOOST_FORCEINLINE
  894. bool operator()(boost::gil::iterator_from_2d<Loc> i1, std::ptrdiff_t n, It i2) const
  895. {
  896. gil_function_requires<boost::gil::PixelLocatorConcept<Loc>>();
  897. gil_function_requires<boost::gil::PixelIteratorConcept<It>>();
  898. while (n > 0)
  899. {
  900. std::ptrdiff_t const num = std::min<std::ptrdiff_t>(n, i1.width() - i1.x_pos());
  901. if (!equal_n(i1.x(), num, i2))
  902. return false;
  903. i1 += num;
  904. i2 += num;
  905. n -= num;
  906. }
  907. return true;
  908. }
  909. };
  910. /// Destination range is delimited by image iterators
  911. /// \tparam It Models PixelIteratorConcept
  912. /// \tparam Loc Models PixelLocatorConcept
  913. template <typename It, typename Loc>
  914. struct equal_n_fn<It, boost::gil::iterator_from_2d<Loc>>
  915. {
  916. BOOST_FORCEINLINE
  917. bool operator()(It i1, std::ptrdiff_t n, boost::gil::iterator_from_2d<Loc> i2) const
  918. {
  919. gil_function_requires<boost::gil::PixelIteratorConcept<It>>();
  920. gil_function_requires<boost::gil::PixelLocatorConcept<Loc>>();
  921. while (n > 0)
  922. {
  923. std::ptrdiff_t const num = std::min<std::ptrdiff_t>(n, i2.width() - i2.x_pos());
  924. if (!equal_n(i1, num, i2.x()))
  925. return false;
  926. i1 += num;
  927. i2 += num;
  928. n -= num;
  929. }
  930. return true;
  931. }
  932. };
  933. /// Both source and destination ranges are delimited by image iterators
  934. template <typename Loc1, typename Loc2>
  935. struct equal_n_fn<boost::gil::iterator_from_2d<Loc1>,boost::gil::iterator_from_2d<Loc2>> {
  936. BOOST_FORCEINLINE bool operator()(boost::gil::iterator_from_2d<Loc1> i1, std::ptrdiff_t n, boost::gil::iterator_from_2d<Loc2> i2) const {
  937. gil_function_requires<boost::gil::PixelLocatorConcept<Loc1>>();
  938. gil_function_requires<boost::gil::PixelLocatorConcept<Loc2>>();
  939. if (i1.x_pos()!=i2.x_pos() || i1.width()!=i2.width()) {
  940. while(n-->0) {
  941. if (*i1++!=*i2++) return false;
  942. }
  943. }
  944. while (n>0) {
  945. std::ptrdiff_t num=std::min<const std::ptrdiff_t>(n,i2.width()-i2.x_pos());
  946. if (!equal_n(i1.x(), num, i2.x()))
  947. return false;
  948. i1+=num;
  949. i2+=num;
  950. n-=num;
  951. }
  952. return true;
  953. }
  954. };
  955. } // namespace detail
  956. template <typename I1, typename I2> BOOST_FORCEINLINE
  957. bool equal_n(I1 i1, std::ptrdiff_t n, I2 i2) {
  958. return detail::equal_n_fn<I1,I2>()(i1,n,i2);
  959. }
  960. } } // namespace boost::gil
  961. namespace std {
  962. /// \ingroup STLOptimizations
  963. /// \brief std::equal(I1,I1,I2) with I1 and I2 being a iterator_from_2d
  964. ///
  965. /// Invoked when one calls std::equal(I1,I1,I2) with I1 and I2 being a iterator_from_2d (which is
  966. /// a 1D iterator over the pixels in an image). Attempts to demote the source and destination
  967. /// iterators to simpler/faster types if the corresponding range is contiguous.
  968. /// For contiguous images (i.e. images that have
  969. /// no alignment gap at the end of each row) it is more efficient to use the underlying
  970. /// pixel iterator that does not check for the end of rows. If the underlying pixel iterator
  971. /// happens to be a fundamental planar/interleaved pointer, the call may further resolve
  972. /// to memcmp. Otherwise it resolves to copying each row using the underlying pixel iterator
  973. template <typename Loc1, typename Loc2> BOOST_FORCEINLINE
  974. bool equal(boost::gil::iterator_from_2d<Loc1> first, boost::gil::iterator_from_2d<Loc1> last, boost::gil::iterator_from_2d<Loc2> first2) {
  975. boost::gil::gil_function_requires<boost::gil::PixelLocatorConcept<Loc1>>();
  976. boost::gil::gil_function_requires<boost::gil::PixelLocatorConcept<Loc2>>();
  977. std::ptrdiff_t n=last-first;
  978. if (first.is_1d_traversable()) {
  979. if (first2.is_1d_traversable())
  980. return boost::gil::detail::equal_n_fn<typename Loc1::x_iterator,typename Loc2::x_iterator>()(first.x(),n, first2.x());
  981. else
  982. return boost::gil::detail::equal_n_fn<typename Loc1::x_iterator,boost::gil::iterator_from_2d<Loc2>>()(first.x(),n, first2);
  983. } else {
  984. if (first2.is_1d_traversable())
  985. return boost::gil::detail::equal_n_fn<boost::gil::iterator_from_2d<Loc1>,typename Loc2::x_iterator>()(first,n, first2.x());
  986. else
  987. return boost::gil::detail::equal_n_fn<boost::gil::iterator_from_2d<Loc1>,boost::gil::iterator_from_2d<Loc2>>()(first,n,first2);
  988. }
  989. }
  990. } // namespace std
  991. namespace boost { namespace gil {
  992. /// \ingroup ImageViewSTLAlgorithmsEqualPixels
  993. /// \brief std::equal for image views
  994. template <typename View1, typename View2> BOOST_FORCEINLINE
  995. bool equal_pixels(const View1& v1, const View2& v2) {
  996. BOOST_ASSERT(v1.dimensions() == v2.dimensions());
  997. return std::equal(v1.begin(),v1.end(),v2.begin()); // std::equal has overloads with GIL iterators for optimal performance
  998. }
  999. //////////////////////////////////////////////////////////////////////////////////////
  1000. ///
  1001. /// transform_pixels
  1002. ///
  1003. //////////////////////////////////////////////////////////////////////////////////////
  1004. /// \defgroup ImageViewSTLAlgorithmsTransformPixels transform_pixels
  1005. /// \ingroup ImageViewSTLAlgorithms
  1006. /// \brief std::transform for image views
  1007. /// \ingroup ImageViewSTLAlgorithmsTransformPixels
  1008. /// \brief std::transform for image views
  1009. template <typename View1, typename View2, typename F> BOOST_FORCEINLINE
  1010. F transform_pixels(const View1& src,const View2& dst, F fun) {
  1011. BOOST_ASSERT(src.dimensions() == dst.dimensions());
  1012. for (std::ptrdiff_t y=0; y<src.height(); ++y) {
  1013. typename View1::x_iterator srcIt=src.row_begin(y);
  1014. typename View2::x_iterator dstIt=dst.row_begin(y);
  1015. for (std::ptrdiff_t x=0; x<src.width(); ++x)
  1016. dstIt[x]=fun(srcIt[x]);
  1017. }
  1018. return fun;
  1019. }
  1020. /// \ingroup ImageViewSTLAlgorithmsTransformPixels
  1021. /// \brief transform_pixels with two sources
  1022. template <typename View1, typename View2, typename View3, typename F> BOOST_FORCEINLINE
  1023. F transform_pixels(const View1& src1, const View2& src2,const View3& dst, F fun) {
  1024. for (std::ptrdiff_t y=0; y<dst.height(); ++y) {
  1025. typename View1::x_iterator srcIt1=src1.row_begin(y);
  1026. typename View2::x_iterator srcIt2=src2.row_begin(y);
  1027. typename View3::x_iterator dstIt=dst.row_begin(y);
  1028. for (std::ptrdiff_t x=0; x<dst.width(); ++x)
  1029. dstIt[x]=fun(srcIt1[x],srcIt2[x]);
  1030. }
  1031. return fun;
  1032. }
  1033. /// \defgroup ImageViewSTLAlgorithmsTransformPixelPositions transform_pixel_positions
  1034. /// \ingroup ImageViewSTLAlgorithms
  1035. /// \brief adobe::transform_positions for image views (passes locators, instead of pixel references, to the function object)
  1036. /// \ingroup ImageViewSTLAlgorithmsTransformPixelPositions
  1037. /// \brief Like transform_pixels but passes to the function object pixel locators instead of pixel references
  1038. template <typename View1, typename View2, typename F> BOOST_FORCEINLINE
  1039. F transform_pixel_positions(const View1& src,const View2& dst, F fun) {
  1040. BOOST_ASSERT(src.dimensions() == dst.dimensions());
  1041. typename View1::xy_locator loc=src.xy_at(0,0);
  1042. for (std::ptrdiff_t y=0; y<src.height(); ++y) {
  1043. typename View2::x_iterator dstIt=dst.row_begin(y);
  1044. for (std::ptrdiff_t x=0; x<src.width(); ++x, ++loc.x())
  1045. dstIt[x]=fun(loc);
  1046. loc.x()-=src.width(); ++loc.y();
  1047. }
  1048. return fun;
  1049. }
  1050. /// \ingroup ImageViewSTLAlgorithmsTransformPixelPositions
  1051. /// \brief transform_pixel_positions with two sources
  1052. template <typename View1, typename View2, typename View3, typename F> BOOST_FORCEINLINE
  1053. F transform_pixel_positions(const View1& src1,const View2& src2,const View3& dst, F fun) {
  1054. BOOST_ASSERT(src1.dimensions() == dst.dimensions());
  1055. BOOST_ASSERT(src2.dimensions() == dst.dimensions());
  1056. typename View1::xy_locator loc1=src1.xy_at(0,0);
  1057. typename View2::xy_locator loc2=src2.xy_at(0,0);
  1058. for (std::ptrdiff_t y=0; y<src1.height(); ++y) {
  1059. typename View3::x_iterator dstIt=dst.row_begin(y);
  1060. for (std::ptrdiff_t x=0; x<src1.width(); ++x, ++loc1.x(), ++loc2.x())
  1061. dstIt[x]=fun(loc1,loc2);
  1062. loc1.x()-=src1.width(); ++loc1.y();
  1063. loc2.x()-=src2.width(); ++loc2.y();
  1064. }
  1065. return fun;
  1066. }
  1067. // Code below this line is moved here from <boost/gil/extension/numeric/algorithm.hpp>
  1068. /// \brief Reference proxy associated with a type that has a \p "reference" member type alias.
  1069. ///
  1070. /// The reference proxy is the reference type, but with stripped-out C++ reference.
  1071. /// Models PixelConcept.
  1072. template <typename T>
  1073. struct pixel_proxy : std::remove_reference<typename T::reference> {};
  1074. /// \brief std::for_each for a pair of iterators
  1075. template <typename Iterator1, typename Iterator2, typename BinaryFunction>
  1076. BinaryFunction for_each(Iterator1 first1, Iterator1 last1, Iterator2 first2, BinaryFunction f)
  1077. {
  1078. while (first1 != last1)
  1079. f(*first1++, *first2++);
  1080. return f;
  1081. }
  1082. template <typename SrcIterator, typename DstIterator>
  1083. inline
  1084. auto assign_pixels(SrcIterator src, SrcIterator src_end, DstIterator dst) -> DstIterator
  1085. {
  1086. for_each(src, src_end, dst,
  1087. pixel_assigns_t
  1088. <
  1089. typename pixel_proxy<typename std::iterator_traits<SrcIterator>::value_type>::type,
  1090. typename pixel_proxy<typename std::iterator_traits<DstIterator>::value_type>::type
  1091. >());
  1092. return dst + (src_end - src);
  1093. }
  1094. namespace detail {
  1095. template <std::size_t Size>
  1096. struct inner_product_k_t
  1097. {
  1098. template
  1099. <
  1100. class InputIterator1,
  1101. class InputIterator2,
  1102. class T,
  1103. class BinaryOperation1,
  1104. class BinaryOperation2
  1105. >
  1106. static T apply(
  1107. InputIterator1 first1,
  1108. InputIterator2 first2, T init,
  1109. BinaryOperation1 binary_op1,
  1110. BinaryOperation2 binary_op2)
  1111. {
  1112. init = binary_op1(init, binary_op2(*first1, *first2));
  1113. return inner_product_k_t<Size - 1>::template apply(
  1114. first1 + 1, first2 + 1, init, binary_op1, binary_op2);
  1115. }
  1116. };
  1117. template <>
  1118. struct inner_product_k_t<0>
  1119. {
  1120. template
  1121. <
  1122. class InputIterator1,
  1123. class InputIterator2,
  1124. class T,
  1125. class BinaryOperation1,
  1126. class BinaryOperation2
  1127. >
  1128. static T apply(
  1129. InputIterator1 first1,
  1130. InputIterator2 first2,
  1131. T init,
  1132. BinaryOperation1 binary_op1,
  1133. BinaryOperation2 binary_op2)
  1134. {
  1135. return init;
  1136. }
  1137. };
  1138. } // namespace detail
  1139. /// static version of std::inner_product
  1140. template
  1141. <
  1142. std::size_t Size,
  1143. class InputIterator1,
  1144. class InputIterator2,
  1145. class T,
  1146. class BinaryOperation1,
  1147. class BinaryOperation2
  1148. >
  1149. BOOST_FORCEINLINE
  1150. T inner_product_k(
  1151. InputIterator1 first1,
  1152. InputIterator2 first2,
  1153. T init,
  1154. BinaryOperation1 binary_op1,
  1155. BinaryOperation2 binary_op2)
  1156. {
  1157. return detail::inner_product_k_t<Size>::template apply(
  1158. first1, first2, init, binary_op1, binary_op2);
  1159. }
  1160. /// \brief 1D un-guarded cross-correlation with a variable-size kernel
  1161. template
  1162. <
  1163. typename PixelAccum,
  1164. typename SrcIterator,
  1165. typename KernelIterator,
  1166. typename Size,
  1167. typename DstIterator
  1168. >
  1169. inline
  1170. auto correlate_pixels_n(
  1171. SrcIterator src_begin,
  1172. SrcIterator src_end,
  1173. KernelIterator kernel_begin,
  1174. Size kernel_size,
  1175. DstIterator dst_begin)
  1176. -> DstIterator
  1177. {
  1178. using src_pixel_ref_t = typename pixel_proxy
  1179. <
  1180. typename std::iterator_traits<SrcIterator>::value_type
  1181. >::type;
  1182. using dst_pixel_ref_t = typename pixel_proxy
  1183. <
  1184. typename std::iterator_traits<DstIterator>::value_type
  1185. >::type;
  1186. using kernel_value_t = typename std::iterator_traits<KernelIterator>::value_type;
  1187. PixelAccum accum_zero;
  1188. pixel_zeros_t<PixelAccum>()(accum_zero);
  1189. while (src_begin != src_end)
  1190. {
  1191. pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
  1192. std::inner_product(
  1193. src_begin,
  1194. src_begin + kernel_size,
  1195. kernel_begin,
  1196. accum_zero,
  1197. pixel_plus_t<PixelAccum, PixelAccum, PixelAccum>(),
  1198. pixel_multiplies_scalar_t<src_pixel_ref_t, kernel_value_t, PixelAccum>()),
  1199. *dst_begin);
  1200. ++src_begin;
  1201. ++dst_begin;
  1202. }
  1203. return dst_begin;
  1204. }
  1205. /// \brief 1D un-guarded cross-correlation with a fixed-size kernel
  1206. template
  1207. <
  1208. std::size_t Size,
  1209. typename PixelAccum,
  1210. typename SrcIterator,
  1211. typename KernelIterator,
  1212. typename DstIterator
  1213. >
  1214. inline
  1215. auto correlate_pixels_k(
  1216. SrcIterator src_begin,
  1217. SrcIterator src_end,
  1218. KernelIterator kernel_begin,
  1219. DstIterator dst_begin)
  1220. -> DstIterator
  1221. {
  1222. using src_pixel_ref_t = typename pixel_proxy
  1223. <
  1224. typename std::iterator_traits<SrcIterator>::value_type
  1225. >::type;
  1226. using dst_pixel_ref_t = typename pixel_proxy
  1227. <
  1228. typename std::iterator_traits<DstIterator>::value_type
  1229. >::type;
  1230. using kernel_type = typename std::iterator_traits<KernelIterator>::value_type;
  1231. PixelAccum accum_zero;
  1232. pixel_zeros_t<PixelAccum>()(accum_zero);
  1233. while (src_begin != src_end)
  1234. {
  1235. pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
  1236. inner_product_k<Size>(
  1237. src_begin,
  1238. kernel_begin,
  1239. accum_zero,
  1240. pixel_plus_t<PixelAccum, PixelAccum, PixelAccum>(),
  1241. pixel_multiplies_scalar_t<src_pixel_ref_t, kernel_type, PixelAccum>()),
  1242. *dst_begin);
  1243. ++src_begin;
  1244. ++dst_begin;
  1245. }
  1246. return dst_begin;
  1247. }
  1248. /// \brief destination is set to be product of the source and a scalar
  1249. /// \tparam PixelAccum - TODO
  1250. /// \tparam SrcView Models ImageViewConcept
  1251. /// \tparam DstView Models MutableImageViewConcept
  1252. template <typename PixelAccum, typename SrcView, typename Scalar, typename DstView>
  1253. inline
  1254. void view_multiplies_scalar(SrcView const& src_view, Scalar const& scalar, DstView const& dst_view)
  1255. {
  1256. static_assert(std::is_scalar<Scalar>::value, "Scalar is not scalar");
  1257. BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions());
  1258. using src_pixel_ref_t = typename pixel_proxy<typename SrcView::value_type>::type;
  1259. using dst_pixel_ref_t = typename pixel_proxy<typename DstView::value_type>::type;
  1260. using y_coord_t = typename SrcView::y_coord_t;
  1261. y_coord_t const height = src_view.height();
  1262. for (y_coord_t y = 0; y < height; ++y)
  1263. {
  1264. typename SrcView::x_iterator it_src = src_view.row_begin(y);
  1265. typename DstView::x_iterator it_dst = dst_view.row_begin(y);
  1266. typename SrcView::x_iterator it_src_end = src_view.row_end(y);
  1267. while (it_src != it_src_end)
  1268. {
  1269. pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
  1270. pixel_multiplies_scalar_t<src_pixel_ref_t, Scalar, PixelAccum>()(*it_src, scalar),
  1271. *it_dst);
  1272. ++it_src;
  1273. ++it_dst;
  1274. }
  1275. }
  1276. }
  1277. /// \ingroup ImageAlgorithms
  1278. /// \brief Boundary options for image boundary extension
  1279. enum class boundary_option
  1280. {
  1281. output_ignore, /// do nothing to the output
  1282. output_zero, /// set the output to zero
  1283. extend_padded, /// assume the source boundaries to be padded already
  1284. extend_zero, /// assume the source boundaries to be zero
  1285. extend_constant /// assume the source boundaries to be the boundary value
  1286. };
  1287. namespace detail
  1288. {
  1289. template <typename SrcView, typename RltView>
  1290. void extend_row_impl(
  1291. SrcView const& src_view,
  1292. RltView result_view,
  1293. std::size_t extend_count,
  1294. boundary_option option)
  1295. {
  1296. std::ptrdiff_t extend_count_ = static_cast<std::ptrdiff_t>(extend_count);
  1297. if (option == boundary_option::extend_constant)
  1298. {
  1299. for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
  1300. {
  1301. if(i >= extend_count_ && i < extend_count_ + src_view.height())
  1302. {
  1303. assign_pixels(
  1304. src_view.row_begin(i - extend_count_),
  1305. src_view.row_end(i - extend_count_),
  1306. result_view.row_begin(i)
  1307. );
  1308. }
  1309. else if(i < extend_count_)
  1310. {
  1311. assign_pixels(src_view.row_begin(0), src_view.row_end(0), result_view.row_begin(i));
  1312. }
  1313. else
  1314. {
  1315. assign_pixels(
  1316. src_view.row_begin(src_view.height() - 1),
  1317. src_view.row_end(src_view.height() - 1),
  1318. result_view.row_begin(i)
  1319. );
  1320. }
  1321. }
  1322. }
  1323. else if (option == boundary_option::extend_zero)
  1324. {
  1325. typename SrcView::value_type acc_zero;
  1326. pixel_zeros_t<typename SrcView::value_type>()(acc_zero);
  1327. for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
  1328. {
  1329. if (i >= extend_count_ && i < extend_count_ + src_view.height())
  1330. {
  1331. assign_pixels(
  1332. src_view.row_begin(i - extend_count_),
  1333. src_view.row_end(i - extend_count_),
  1334. result_view.row_begin(i)
  1335. );
  1336. }
  1337. else
  1338. {
  1339. std::fill_n(result_view.row_begin(i), result_view.width(), acc_zero);
  1340. }
  1341. }
  1342. }
  1343. else if (option == boundary_option::extend_padded)
  1344. {
  1345. auto original_view = subimage_view(
  1346. src_view,
  1347. 0,
  1348. -extend_count,
  1349. src_view.width(),
  1350. src_view.height() + (2 * extend_count)
  1351. );
  1352. for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
  1353. {
  1354. assign_pixels(
  1355. original_view.row_begin(i),
  1356. original_view.row_end(i),
  1357. result_view.row_begin(i)
  1358. );
  1359. }
  1360. }
  1361. else
  1362. {
  1363. BOOST_ASSERT_MSG(false, "Invalid boundary option");
  1364. }
  1365. }
  1366. } //namespace detail
  1367. /// \brief adds new row at top and bottom.
  1368. /// Image padding introduces new pixels around the edges of an image.
  1369. /// The border provides space for annotations or acts as a boundary when using advanced filtering techniques.
  1370. /// \tparam SrcView Models ImageViewConcept
  1371. /// \tparam extend_count number of rows to be added each side
  1372. /// \tparam option - TODO
  1373. template <typename SrcView>
  1374. auto extend_row(
  1375. SrcView const& src_view,
  1376. std::size_t extend_count,
  1377. boundary_option option
  1378. ) -> typename gil::image<typename SrcView::value_type>
  1379. {
  1380. typename gil::image<typename SrcView::value_type>
  1381. result_img(src_view.width(), src_view.height() + (2 * extend_count));
  1382. auto result_view = view(result_img);
  1383. detail::extend_row_impl(src_view, result_view, extend_count, option);
  1384. return result_img;
  1385. }
  1386. /// \brief adds new column at left and right.
  1387. /// Image padding introduces new pixels around the edges of an image.
  1388. /// The border provides space for annotations or acts as a boundary when using advanced filtering techniques.
  1389. /// \tparam SrcView Models ImageViewConcept
  1390. /// \tparam extend_count number of columns to be added each side
  1391. /// \tparam option - TODO
  1392. template <typename SrcView>
  1393. auto extend_col(
  1394. SrcView const& src_view,
  1395. std::size_t extend_count,
  1396. boundary_option option
  1397. ) -> typename gil::image<typename SrcView::value_type>
  1398. {
  1399. auto src_view_rotate = rotated90cw_view(src_view);
  1400. typename gil::image<typename SrcView::value_type>
  1401. result_img(src_view.width() + (2 * extend_count), src_view.height());
  1402. auto result_view = rotated90cw_view(view(result_img));
  1403. detail::extend_row_impl(src_view_rotate, result_view, extend_count, option);
  1404. return result_img;
  1405. }
  1406. /// \brief adds new row and column at all sides.
  1407. /// Image padding introduces new pixels around the edges of an image.
  1408. /// The border provides space for annotations or acts as a boundary when using advanced filtering techniques.
  1409. /// \tparam SrcView Models ImageViewConcept
  1410. /// \tparam extend_count number of rows/column to be added each side
  1411. /// \tparam option - TODO
  1412. template <typename SrcView>
  1413. auto extend_boundary(
  1414. SrcView const& src_view,
  1415. std::size_t extend_count,
  1416. boundary_option option
  1417. ) -> typename gil::image<typename SrcView::value_type>
  1418. {
  1419. if (option == boundary_option::extend_padded)
  1420. {
  1421. typename gil::image<typename SrcView::value_type>
  1422. result_img(src_view.width()+(2 * extend_count), src_view.height()+(2 * extend_count));
  1423. typename gil::image<typename SrcView::value_type>::view_t result_view = view(result_img);
  1424. auto original_view = subimage_view(
  1425. src_view,
  1426. -extend_count,
  1427. -extend_count,
  1428. src_view.width() + (2 * extend_count),
  1429. src_view.height() + (2 * extend_count)
  1430. );
  1431. for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
  1432. {
  1433. assign_pixels(
  1434. original_view.row_begin(i),
  1435. original_view.row_end(i),
  1436. result_view.row_begin(i)
  1437. );
  1438. }
  1439. return result_img;
  1440. }
  1441. auto auxilary_img = extend_col(src_view, extend_count, option);
  1442. return extend_row(view(auxilary_img), extend_count, option);
  1443. }
  1444. } } // namespace boost::gil
  1445. #endif