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