]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/gil/doc/doxygen/design_guide.dox
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / gil / doc / doxygen / design_guide.dox
CommitLineData
7c673cae
FG
1////////////////////////////////////////////////////////////////////////////////////////
2/// \file
3/// \brief Doxygen documentation
4/// \author Lubomir Bourdev and Hailin Jin \n
5/// Adobe Systems Incorporated
6///
7///
8////////////////////////////////////////////////////////////////////////////////////////
9
10/**
11\page GILDesignGuide Generic Image Library Design Guide
12
13\author Lubomir Bourdev (lbourdev@adobe.com) and Hailin Jin (hljin@adobe.com) \n
14 Adobe Systems Incorporated
15\version 2.1
16\date September 15, 2007
17
18
19<p>This document describes the design of the Generic Image Library, a C++ image-processing library that abstracts image representation from algorithms on images.
20It covers more than you need to know for a causal use of GIL. You can find a quick, jump-start GIL tutorial on the main GIL page at http://stlab.adobe.com/gil
21
22- \ref OverviewSectionDG
23- \ref ConceptsSectionDG
24- \ref PointSectionDG
25- \ref ChannelSectionDG
26- \ref ColorSpaceSectionDG
27- \ref ColorBaseSectionDG
28- \ref PixelSectionDG
29- \ref PixelIteratorSectionDG
30 - \ref FundamentalIteratorDG
31 - \ref IteratorAdaptorDG
32 - \ref PixelDereferenceAdaptorAG
33 - \ref StepIteratorDG
34 - \ref LocatorDG
35 - \ref IteratorFrom2DDG
36- \ref ImageViewSectionDG
37 - \ref ImageViewFrowRawDG
38 - \ref ImageViewFrowImageViewDG
39- \ref ImageSectionDG
40- \ref VariantSecDG
41- \ref MetafunctionsDG
42- \ref IO_DG
43- \ref SampleImgCodeDG
44 - \ref PixelLevelExampleDG
45 - \ref SafeAreaExampleDG
46 - \ref HistogramExampleDG
47 - \ref ImageViewsExampleDG
48- \ref ExtendingGIL_DG
49 - \ref NewColorSpacesDG
50 - \ref NewColorConversionDG
51 - \ref NewChannelsDG
52 - \ref NewImagesDG
53- \ref TechnicalitiesDG
54- \ref ConclusionDG
55
56<br>
57<hr>
58\section OverviewSectionDG 1. Overview
59
60Images are essential in any image processing, vision and video project, and yet the variability in image representations makes it difficult
61to write imaging algorithms that are both generic and efficient. In this section we will describe some of the challenges that we would like to address.
62
63In the following discussion an <i>image</i> is a 2D array of pixels. A <i>pixel</i> is a set of color channels that represents the color at a given point in an image. Each
64<i>channel</i> represents the value of a color component.
65There are two common memory structures for an image. <i>Interleaved</i> images are represented by grouping the pixels together in memory and
66interleaving all channels together, whereas <i>planar</i> images keep the channels in separate color planes. Here is a 4x3 RGB image in
67which the second pixel of the first row is marked in red, in interleaved form:
68
69\image html interleaved.jpg
70and in planar form:
71
72\image html planar.jpg
73
74Note also that rows may optionally be aligned resulting in a potential padding at the end of rows.
75<p>
76The Generic Image Library (GIL) provides models for images that vary in:
77- Structure (planar vs. interleaved)
78- Color space and presence of alpha (RGB, RGBA, CMYK, etc.)
79- Channel depth (8-bit, 16-bit, etc.)
80- Order of channels (RGB vs. BGR, etc.)
81- Row alignment policy (no alignment, word-alignment, etc.)
82
83It also supports user-defined models of images, and images whose parameters are specified at run-time.
84GIL abstracts image representation from algorithms applied on images and allows us to write the algorithm once and have it work
85on any of the above image variations while generating code that is comparable in speed to that of hand-writing the algorithm for a specific image type.
86
87This document follows bottom-up design. Each section defines concepts that build on top of concepts defined in previous sections.
88It is recommended to read the sections in order.
89
90<hr>
91\section ConceptsSectionDG 2. About Concepts
92
93All constructs in GIL are models of GIL concepts. A \em concept is a set of requirements that a type (or a set of related types) must fulfill to
94be used correctly in generic algorithms. The requirements include syntactic and algorithming guarantees.
95For example, GIL's class \p pixel is a model of GIL's \p PixelConcept. The user may substitute the pixel class with one of their own, and, as long as
96it satisfies the requirements of \p PixelConcept, all other GIL classes and algorithms can be used with it. See more about concepts here:
97http://www.generic-programming.org/languages/conceptcpp/
98
99In this document we will use a syntax for defining concepts that is described in a proposal for a Concepts extension to C++0x specified here:
100http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2081.pdf
101
102Here are some common concepts that will be used in GIL. Most of them are defined here:
103http://www.generic-programming.org/languages/conceptcpp/concept_web.php
104
105\code
106auto concept DefaultConstructible<typename T> {
107 T::T();
108};
109
110auto concept CopyConstructible<typename T> {
111 T::T(T);
112 T::~T();
113};
114
115auto concept Assignable<typename T, typename U = T> {
116 typename result_type;
117 result_type operator=(T&, U);
118};
119
120auto concept EqualityComparable<typename T, typename U = T> {
121 bool operator==(T x, T y);
122 bool operator!=(T x, T y) { return !(x==y); }
123};
124
125concept SameType<typename T, typename U> { /* unspecified */ };
126template<typename T> concept_map SameType<T, T> { /* unspecified */ };
127
128auto concept Swappable<typename T> {
129 void swap(T& t, T& u);
130};
131\endcode
132
133Here are some additional basic concepts that GIL needs:
134
135\code
136
137auto concept Regular<typename T> : DefaultConstructible<T>, CopyConstructible<T>, EqualityComparable<T>, Assignable<T>, Swappable<T> {};
138
139auto concept Metafunction<typename T> {
140 typename type;
141};
142
143\endcode
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161\section PointSectionDG 3. Point
162
163A point defines the location of a pixel inside an image. It can also be used to describe the dimensions of an image.
164In most general terms, points are N-dimensional and model the following concept:
165
166\code
167concept PointNDConcept<typename T> : Regular<T> {
168 // the type of a coordinate along each axis
169 template <size_t K> struct axis; where Metafunction<axis>;
170
171 const size_t num_dimensions;
172
173 // accessor/modifier of the value of each axis.
174 template <size_t K> const typename axis<K>::type& T::axis_value() const;
175 template <size_t K> typename axis<K>::type& T::axis_value();
176};
177\endcode
178
179GIL uses a two-dimensional point, which is a refinement of \p PointNDConcept in which both dimensions are of the same type:
180
181\code
182concept Point2DConcept<typename T> : PointNDConcept<T> {
183 where num_dimensions == 2;
184 where SameType<axis<0>::type, axis<1>::type>;
185
186 typename value_type = axis<0>::type;
187
188 const value_type& operator[](const T&, size_t i);
189 value_type& operator[]( T&, size_t i);
190
191 value_type x,y;
192};
193\endcode
194
195<b>Related Concepts:</b>
196
197- PointNDConcept\<T>
198- Point2DConcept\<T>
199
200<b>Models:</b>
201
202GIL provides a model of \p Point2DConcept, \p point2<T> where \p T is the coordinate type.
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223<hr>
224\section ChannelSectionDG 4. Channel
225
226A channel indicates the intensity of a color component (for example, the red channel in an RGB pixel).
227Typical channel operations are getting, comparing and setting the channel values. Channels have associated
228minimum and maximum value. GIL channels model the following concept:
229
230\code
231
232concept ChannelConcept<typename T> : EqualityComparable<T> {
233 typename value_type = T; // use channel_traits<T>::value_type to access it
234 where ChannelValueConcept<value_type>;
235 typename reference = T&; // use channel_traits<T>::reference to access it
236 typename pointer = T*; // use channel_traits<T>::pointer to access it
237 typename const_reference = const T&; // use channel_traits<T>::const_reference to access it
238 typename const_pointer = const T*; // use channel_traits<T>::const_pointer to access it
239 static const bool is_mutable; // use channel_traits<T>::is_mutable to access it
240
241 static T min_value(); // use channel_traits<T>::min_value to access it
242 static T max_value(); // use channel_traits<T>::min_value to access it
243};
244
245concept MutableChannelConcept<ChannelConcept T> : Swappable<T>, Assignable<T> {};
246
247concept ChannelValueConcept<ChannelConcept T> : Regular<T> {};
248\endcode
249
250GIL allows built-in integral and floating point types to be channels. Therefore the associated types and range information
251are defined in \p channel_traits with the following default implementation:
252
253\code
254template <typename T>
255struct channel_traits {
256 typedef T value_type;
257 typedef T& reference;
258 typedef T* pointer;
259 typedef T& const const_reference;
260 typedef T* const const_pointer;
261
262 static value_type min_value() { return std::numeric_limits<T>::min(); }
263 static value_type max_value() { return std::numeric_limits<T>::max(); }
264};
265\endcode
266
267Two channel types are <i>compatible</i> if they have the same value type:
268
269\code
270concept ChannelsCompatibleConcept<ChannelConcept T1, ChannelConcept T2> {
271 where SameType<T1::value_type, T2::value_type>;
272};
273\endcode
274
275A channel may be <i>convertible</i> to another channel:
276
277\code
278template <ChannelConcept Src, ChannelValueConcept Dst>
279concept ChannelConvertibleConcept {
280 Dst channel_convert(Src);
281};
282\endcode
283
284Note that \p ChannelConcept and \p MutableChannelConcept do not require a default constructor. Channels that also
285support default construction (and thus are regular types) model \p ChannelValueConcept. To understand the motivation
286for this distinction, consider a 16-bit RGB pixel in a "565" bit pattern. Its channels correspond to bit ranges. To support
287such channels, we need to create a custom proxy class corresponding to a reference to a subbyte channel.
288Such a proxy reference class models only \p ChannelConcept, because, similar to native C++ references, it
289may not have a default constructor.
290
291Note also that algorithms may impose additional requirements on channels, such as support for arithmentic operations.
292
293<b>Related Concepts:</b>
294
295- ChannelConcept\<T>
296- ChannelValueConcept\<T>
297- MutableChannelConcept\<T>
298- ChannelsCompatibleConcept\<T1,T2>
299- ChannelConvertibleConcept\<SrcChannel,DstChannel>
300
301<b>Models:</b>
302
303All built-in integral and floating point types are valid channels. GIL provides standard typedefs for some integral channels:
304
305\code
306typedef boost::uint8_t bits8;
307typedef boost::uint16_t bits16;
308typedef boost::uint32_t bits32;
309typedef boost::int8_t bits8s;
310typedef boost::int16_t bits16s;
311typedef boost::int32_t bits32s;
312\endcode
313
314The minimum and maximum values of a channel modeled by a built-in type correspond to the minimum and maximum physical range of the built-in type,
315as specified by its \p std::numeric_limits. Sometimes the physical range is not appropriate. GIL provides \p scoped_channel_value, a model for a
316channel adapter that allows for specifying a custom range. We use it to define a [0..1] floating point channel type as follows:
317
318\code
319struct float_zero { static float apply() { return 0.0f; } };
320struct float_one { static float apply() { return 1.0f; } };
321typedef scoped_channel_value<float,float_zero,float_one> bits32f;
322\endcode
323
324GIL also provides models for channels corresponding to ranges of bits:
325
326\code
327// Value of a channel defined over NumBits bits. Models ChannelValueConcept
328template <int NumBits> class packed_channel_value;
329
330// Reference to a channel defined over NumBits bits. Models ChannelConcept
331template <int FirstBit,
332 int NumBits, // Defines the sequence of bits in the data value that contain the channel
333 bool Mutable> // true if the reference is mutable
334class packed_channel_reference;
335
336// Reference to a channel defined over NumBits bits. Its FirstBit is a run-time parameter. Models ChannelConcept
337template <int NumBits, // Defines the sequence of bits in the data value that contain the channel
338 bool Mutable> // true if the reference is mutable
339class packed_dynamic_channel_reference;
340\endcode
341
342Note that there are two models of a reference proxy which differ based on whether the offset of the channel range is
343specified as a template or a run-time parameter. The first model is faster and more compact while the second model is more
344flexible. For example, the second model allows us to construct an iterator over bitrange channels.
345
346<b>Algorithms:</b>
347
348Here is how to construct the three channels of a 16-bit "565" pixel and set them to their maximum value:
349
350\code
351typedef packed_channel_reference<0,5,true> channel16_0_5_reference_t;
352typedef packed_channel_reference<5,6,true> channel16_5_6_reference_t;
353typedef packed_channel_reference<11,5,true> channel16_11_5_reference_t;
354
355boost::uint16_t data=0;
356channel16_0_5_reference_t channel1(&data);
357channel16_5_6_reference_t channel2(&data);
358channel16_11_5_reference_t channel3(&data);
359
360channel1=channel_traits<channel16_0_5_reference_t>::max_value();
361channel2=channel_traits<channel16_5_6_reference_t>::max_value();
362channel3=channel_traits<channel16_11_5_reference_t>::max_value();
363assert(data==65535);
364\endcode
365
366Assignment, equality comparison and copy construction are defined only between compatible channels:
367
368\code
369packed_channel_value<5> channel_6bit = channel1;
370channel_6bit = channel3;
371
372//channel_6bit = channel2; // compile error: Assignment between incompatible channels.
373\endcode
374
375All channel models provided by GIL are pairwise convertible:
376
377\code
378channel1 = channel_traits<channel16_0_5_reference_t>::max_value();
379assert(channel1 == 31);
380
381bits16 chan16 = channel_convert<bits16>(channel1);
382assert(chan16 == 65535);
383\endcode
384
385Channel conversion is a lossy operation. GIL's channel conversion is a linear transformation between the ranges of the source and destination channel.
386It maps precisely the minimum to the minimum and the maximum to the maximum. (For example, to convert from uint8_t to uint16_t GIL does not do a bit shift
387because it will not properly match the maximum values. Instead GIL multiplies the source by 257).
388
389All channel models that GIL provides are convertible from/to an integral or floating point type. Thus they support arithmetic operations.
390Here are the channel-level algorithms that GIL provides:
391
392\code
393// Converts a source channel value into a destrination channel. Linearly maps the value of the source
394// into the range of the destination
395template <typename DstChannel, typename SrcChannel>
396typename channel_traits<DstChannel>::value_type channel_convert(SrcChannel src);
397
398// returns max_value - x + min_value
399template <typename Channel>
400typename channel_traits<Channel>::value_type channel_invert(Channel x);
401
402// returns a * b / max_value
403template <typename Channel>
404typename channel_traits<Channel>::value_type channel_multiply(Channel a, Channel b);
405\endcode
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422<hr>
423\section ColorSpaceSectionDG 5. Color Space and Layout
424
425A color space captures the set and interpretation of channels comprising a pixel. It is an MPL random access sequence containing the types
426of all elements in the color space. Two color spaces are considered <i>compatible</i> if they are equal (i.e. have the same set of colors in the same order).
427
428<b>Related Concepts:</b>
429
430- ColorSpaceConcept\<ColorSpace>
431- ColorSpacesCompatibleConcept\<ColorSpace1,ColorSpace2>
432- ChannelMappingConcept\<Mapping>
433
434<b>Models:</b>
435
436GIL currently provides the following color spaces: \p gray_t, \p rgb_t, \p rgba_t, and \p cmyk_t. It also provides unnamed
437N-channel color spaces of two to five channels, \p devicen_t<2>,
438\p devicen_t<3>, \p devicen_t<4>, \p devicen_t<5>. Besides the standard layouts, it provides \p bgr_layout_t, \p bgra_layout_t, \p abgr_layout_t
439and \p argb_layout_t.
440
441As an example, here is how GIL defines the RGBA color space:
442
443\code
444struct red_t{};
445struct green_t{};
446struct blue_t{};
447struct alpha_t{};
448typedef mpl::vector4<red_t,green_t,blue_t,alpha_t> rgba_t;
449\endcode
450
451The ordering of the channels in the color space definition specifies their semantic order. For example, \p red_t is the first semantic channel of \p rgba_t.
452While there is a unique semantic ordering of the channels in a color space, channels may vary in their physical ordering in memory. The mapping of channels is
453specified by \p ChannelMappingConcept, which is an MPL random access sequence of integral types. A color space and its associated mapping are often used together.
454Thus they are grouped in GIL's layout:
455
456\code
457template <typename ColorSpace,
458 typename ChannelMapping = mpl::range_c<int,0,mpl::size<ColorSpace>::value> >
459struct layout {
460 typedef ColorSpace color_space_t;
461 typedef ChannelMapping channel_mapping_t;
462};
463\endcode
464
465Here is how to create layouts for the RGBA color space:
466
467\code
468typedef layout<rgba_t> rgba_layout_t; // default ordering is 0,1,2,3...
469typedef layout<rgba_t, mpl::vector4_c<int,2,1,0,3> > bgra_layout_t;
470typedef layout<rgba_t, mpl::vector4_c<int,1,2,3,0> > argb_layout_t;
471typedef layout<rgba_t, mpl::vector4_c<int,3,2,1,0> > abgr_layout_t;
472\endcode
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500<hr>
501\section ColorBaseSectionDG 6. Color Base
502
503A color base is a container of color elements. The most common use of color base is in the implementation of a pixel, in which case the color
504elements are channel values. The color base concept, however, can be used in other scenarios. For example, a planar pixel has channels that are not
505contiguous in memory. Its reference is a proxy class that uses a color base whose elements are channel references. Its iterator uses a color base
506whose elements are channel iterators.
507
508Color base models must satisfy the following concepts:
509
510\code
511concept ColorBaseConcept<typename T> : CopyConstructible<T>, EqualityComparable<T> {
512 // a GIL layout (the color space and element permutation)
513 typename layout_t;
514
515 // The type of K-th element
516 template <int K> struct kth_element_type;
517 where Metafunction<kth_element_type>;
518
519 // The result of at_c
520 template <int K> struct kth_element_const_reference_type;
521 where Metafunction<kth_element_const_reference_type>;
522
523 template <int K> kth_element_const_reference_type<T,K>::type at_c(T);
524
525 template <ColorBaseConcept T2> where { ColorBasesCompatibleConcept<T,T2> }
526 T::T(T2);
527 template <ColorBaseConcept T2> where { ColorBasesCompatibleConcept<T,T2> }
528 bool operator==(const T&, const T2&);
529 template <ColorBaseConcept T2> where { ColorBasesCompatibleConcept<T,T2> }
530 bool operator!=(const T&, const T2&);
531
532};
533
534concept MutableColorBaseConcept<ColorBaseConcept T> : Assignable<T>, Swappable<T> {
535 template <int K> struct kth_element_reference_type;
536 where Metafunction<kth_element_reference_type>;
537
538 template <int K> kth_element_reference_type<T,K>::type at_c(T);
539
540 template <ColorBaseConcept T2> where { ColorBasesCompatibleConcept<T,T2> }
541 T& operator=(T&, const T2&);
542};
543
544concept ColorBaseValueConcept<typename T> : MutableColorBaseConcept<T>, Regular<T> {
545};
546
547concept HomogeneousColorBaseConcept<ColorBaseConcept CB> {
548 // For all K in [0 ... size<C1>::value-1):
549 // where SameType<kth_element_type<K>::type, kth_element_type<K+1>::type>;
550 kth_element_const_reference_type<0>::type dynamic_at_c(const CB&, std::size_t n) const;
551};
552
553concept MutableHomogeneousColorBaseConcept<MutableColorBaseConcept CB> : HomogeneousColorBaseConcept<CB> {
554 kth_element_reference_type<0>::type dynamic_at_c(const CB&, std::size_t n);
555};
556
557concept HomogeneousColorBaseValueConcept<typename T> : MutableHomogeneousColorBaseConcept<T>, Regular<T> {
558};
559
560concept ColorBasesCompatibleConcept<ColorBaseConcept C1, ColorBaseConcept C2> {
561 where SameType<C1::layout_t::color_space_t, C2::layout_t::color_space_t>;
562 // also, for all K in [0 ... size<C1>::value):
563 // where Convertible<kth_semantic_element_type<C1,K>::type, kth_semantic_element_type<C2,K>::type>;
564 // where Convertible<kth_semantic_element_type<C2,K>::type, kth_semantic_element_type<C1,K>::type>;
565};
566\endcode
567
568A color base must have an associated layout (which consists of a color space, as well as an ordering of the channels).
569There are two ways to index the elements of a color base: A physical index corresponds to the way they are ordered in memory, and
570a semantic index corresponds to the way the elements are ordered in their color space.
571For example, in the RGB color space the elements are ordered as {red_t, green_t, blue_t}. For a color base with a BGR layout, the first element
572in physical ordering is the blue element, whereas the first semantic element is the red one.
573Models of \p ColorBaseConcept are required to provide the \p at_c<K>(ColorBase) function, which allows for accessing the elements based on their
574physical order. GIL provides a \p semantic_at_c<K>(ColorBase) function (described later) which can operate on any model of ColorBaseConcept and returns
575the corresponding semantic element.
576
577Two color bases are <i>compatible</i> if they have the same color space and their elements (paired semantically) are convertible to each other.
578
579
580<b>Models:</b>
581
582GIL provides a model for a homogeneous color base (a color base whose elements all have the same type).
583
584\code
585namespace detail {
586 template <typename Element, typename Layout, int K> struct homogeneous_color_base;
587}
588\endcode
589
590It is used in the implementation of GIL's pixel, planar pixel reference and planar pixel iterator.
591Another model of \p ColorBaseConcept is \p packed_pixel - it is a pixel whose channels are bit ranges. See the \ref PixelSectionDG
592section for more.
593
594<b>Algorithms:</b>
595
596GIL provides the following functions and metafunctions operating on color bases:
597
598\code
599// Metafunction returning an mpl::int_ equal to the number of elements in the color base
600template <class ColorBase> struct size;
601
602// Returns the type of the return value of semantic_at_c<K>(color_base)
603template <class ColorBase, int K> struct kth_semantic_element_reference_type;
604template <class ColorBase, int K> struct kth_semantic_element_const_reference_type;
605
606// Returns a reference to the element with K-th semantic index.
607template <class ColorBase, int K>
608typename kth_semantic_element_reference_type<ColorBase,K>::type semantic_at_c(ColorBase& p)
609template <class ColorBase, int K>
610typename kth_semantic_element_const_reference_type<ColorBase,K>::type semantic_at_c(const ColorBase& p)
611
612// Returns the type of the return value of get_color<Color>(color_base)
613template <typename Color, typename ColorBase> struct color_reference_t;
614template <typename Color, typename ColorBase> struct color_const_reference_t;
615
616// Returns a reference to the element corresponding to the given color
617template <typename ColorBase, typename Color>
618typename color_reference_t<Color,ColorBase>::type get_color(ColorBase& cb, Color=Color());
619template <typename ColorBase, typename Color>
620typename color_const_reference_t<Color,ColorBase>::type get_color(const ColorBase& cb, Color=Color());
621
622// Returns the element type of the color base. Defined for homogeneous color bases only
623template <typename ColorBase> struct element_type;
624template <typename ColorBase> struct element_reference_type;
625template <typename ColorBase> struct element_const_reference_type;
626\endcode
627
628GIL also provides the following algorithms which operate on color bases. Note that they all pair the elements semantically:
629
630\code
631// Equivalents to std::equal, std::copy, std::fill, std::generate
632template <typename CB1,typename CB2> bool static_equal(const CB1& p1, const CB2& p2);
633template <typename Src,typename Dst> void static_copy(const Src& src, Dst& dst);
634template <typename CB, typename Op> void static_generate(CB& dst,Op op);
635
636// Equivalents to std::transform
637template <typename CB , typename Dst,typename Op> Op static_transform( CB&,Dst&,Op);
638template <typename CB , typename Dst,typename Op> Op static_transform(const CB&,Dst&,Op);
639template <typename CB1,typename CB2,typename Dst,typename Op> Op static_transform( CB1&, CB2&,Dst&,Op);
640template <typename CB1,typename CB2,typename Dst,typename Op> Op static_transform(const CB1&, CB2&,Dst&,Op);
641template <typename CB1,typename CB2,typename Dst,typename Op> Op static_transform( CB1&,const CB2&,Dst&,Op);
642template <typename CB1,typename CB2,typename Dst,typename Op> Op static_transform(const CB1&,const CB2&,Dst&,Op);
643
644// Equivalents to std::for_each
645template <typename CB1, typename Op> Op static_for_each( CB1&,Op);
646template <typename CB1, typename Op> Op static_for_each(const CB1&,Op);
647template <typename CB1,typename CB2, typename Op> Op static_for_each( CB1&, CB2&,Op);
648template <typename CB1,typename CB2, typename Op> Op static_for_each( CB1&,const CB2&,Op);
649template <typename CB1,typename CB2, typename Op> Op static_for_each(const CB1&, CB2&,Op);
650template <typename CB1,typename CB2, typename Op> Op static_for_each(const CB1&,const CB2&,Op);
651template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each( CB1&, CB2&, CB3&,Op);
652template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each( CB1&, CB2&,const CB3&,Op);
653template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each( CB1&,const CB2&, CB3&,Op);
654template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each( CB1&,const CB2&,const CB3&,Op);
655template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each(const CB1&, CB2&, CB3&,Op);
656template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each(const CB1&, CB2&,const CB3&,Op);
657template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each(const CB1&,const CB2&, CB3&,Op);
658template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each(const CB1&,const CB2&,const CB3&,Op);
659
660// The following algorithms are only defined for homogeneous color bases:
661// Equivalent to std::fill
662template <typename HCB, typename Element> void static_fill(HCB& p, const Element& v);
663
664// Equivalents to std::min_element and std::max_element
665template <typename HCB> typename element_const_reference_type<HCB>::type static_min(const HCB&);
666template <typename HCB> typename element_reference_type<HCB>::type static_min( HCB&);
667template <typename HCB> typename element_const_reference_type<HCB>::type static_max(const HCB&);
668template <typename HCB> typename element_reference_type<HCB>::type static_max( HCB&);
669\endcode
670
671These algorithms are designed after the corresponding STL algorithms, except that instead of ranges they take color bases and operate on their elements.
672In addition, they are implemented with a compile-time recursion (thus the prefix "static_"). Finally, they pair the elements semantically instead of based
673on their physical order in memory. For example, here is the implementation of \p static_equal:
674
675\code
676namespace detail {
677template <int K> struct element_recursion {
678 template <typename P1,typename P2>
679 static bool static_equal(const P1& p1, const P2& p2) {
680 return element_recursion<K-1>::static_equal(p1,p2) &&
681 semantic_at_c<K-1>(p1)==semantic_at_c<N-1>(p2);
682 }
683};
684template <> struct element_recursion<0> {
685 template <typename P1,typename P2>
686 static bool static_equal(const P1&, const P2&) { return true; }
687};
688}
689
690template <typename P1,typename P2>
691bool static_equal(const P1& p1, const P2& p2) {
692 gil_function_requires<ColorSpacesCompatibleConcept<P1::layout_t::color_space_t,P2::layout_t::color_space_t> >();
693 return detail::element_recursion<size<P1>::value>::static_equal(p1,p2);
694}
695\endcode
696
697This algorithm is used when invoking \p operator== on two pixels, for example. By using semantic accessors we are properly comparing an RGB pixel
698to a BGR pixel. Notice also that all of the above algorithms taking more than one color base require that they all have the same color space.
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739<hr>
740\section PixelSectionDG 7. Pixel
741
742A pixel is a set of channels defining the color at a given point in an image. Conceptually, a pixel is little more than a color base whose elements
743model \p ChannelConcept.
744All properties of pixels inherit from color bases: pixels may be <i>homogeneous</i> if all of their channels have the same type; otherwise they are
745called <i>heterogeneous</i>. The channels of a pixel may be addressed using semantic or physical indexing, or by color; all color-base algorithms
746work on pixels as well. Two pixels are <i>compatible</i> if their color spaces are the same and their channels, paired semantically, are compatible.
747Note that constness, memory organization and reference/value are ignored. For example, an 8-bit RGB planar reference is compatible to a constant 8-bit
748BGR interleaved pixel value. Most pairwise pixel operations (copy construction, assignment, equality, etc.) are only defined for compatible pixels.
749
750Pixels (as well as other GIL constructs built on pixels, such as iterators, locators, views and images) must provide metafunctions to access
751their color space, channel mapping, number of channels, and (for homogeneous pixels) the channel type:
752
753\code
754concept PixelBasedConcept<typename T> {
755 typename color_space_type<T>;
756 where Metafunction<color_space_type<T> >;
757 where ColorSpaceConcept<color_space_type<T>::type>;
758 typename channel_mapping_type<T>;
759 where Metafunction<channel_mapping_type<T> >;
760 where ChannelMappingConcept<channel_mapping_type<T>::type>;
761 typename is_planar<T>;
762 where Metafunction<is_planar<T> >;
763 where SameType<is_planar<T>::type, bool>;
764};
765
766concept HomogeneousPixelBasedConcept<PixelBasedConcept T> {
767 typename channel_type<T>;
768 where Metafunction<channel_type<T> >;
769 where ChannelConcept<channel_type<T>::type>;
770};
771\endcode
772
773Pixels model the following concepts:
774
775\code
776concept PixelConcept<typename P> : ColorBaseConcept<P>, PixelBasedConcept<P> {
777 where is_pixel<P>::type::value==true;
778 // where for each K [0..size<P>::value-1]:
779 // ChannelConcept<kth_element_type<K> >;
780
781 typename value_type; where PixelValueConcept<value_type>;
782 typename reference; where PixelConcept<reference>;
783 typename const_reference; where PixelConcept<const_reference>;
784 static const bool P::is_mutable;
785
786 template <PixelConcept P2> where { PixelConcept<P,P2> }
787 P::P(P2);
788 template <PixelConcept P2> where { PixelConcept<P,P2> }
789 bool operator==(const P&, const P2&);
790 template <PixelConcept P2> where { PixelConcept<P,P2> }
791 bool operator!=(const P&, const P2&);
792};
793
794concept MutablePixelConcept<typename P> : PixelConcept<P>, MutableColorBaseConcept<P> {
795 where is_mutable==true;
796};
797
798concept HomogeneousPixelConcept<PixelConcept P> : HomogeneousColorBaseConcept<P>, HomogeneousPixelBasedConcept<P> {
799 P::template element_const_reference_type<P>::type operator[](P p, std::size_t i) const { return dynamic_at_c(P,i); }
800};
801
802concept MutableHomogeneousPixelConcept<MutablePixelConcept P> : MutableHomogeneousColorBaseConcept<P> {
803 P::template element_reference_type<P>::type operator[](P p, std::size_t i) { return dynamic_at_c(p,i); }
804};
805
806concept PixelValueConcept<typename P> : PixelConcept<P>, Regular<P> {
807 where SameType<value_type,P>;
808};
809
810concept PixelsCompatibleConcept<PixelConcept P1, PixelConcept P2> : ColorBasesCompatibleConcept<P1,P2> {
811 // where for each K [0..size<P1>::value):
812 // ChannelsCompatibleConcept<kth_semantic_element_type<P1,K>::type, kth_semantic_element_type<P2,K>::type>;
813};
814\endcode
815
816A pixel is <i>convertible</i> to a second pixel if it is possible to approximate its color in the form of the second pixel. Conversion is an explicit,
817non-symmetric and often lossy operation (due to both channel and color space approximation). Convertability requires modeling the following concept:
818
819\code
820template <PixelConcept SrcPixel, MutablePixelConcept DstPixel>
821concept PixelConvertibleConcept {
822 void color_convert(const SrcPixel&, DstPixel&);
823};
824\endcode
825
826The distinction between \p PixelConcept and \p PixelValueConcept is analogous to that for channels and color bases - pixel reference proxies model both,
827but only pixel values model the latter.
828
829<b>Related Concepts:</b>
830
831- PixelBasedConcept\<P>
832- PixelConcept\<Pixel>
833- MutablePixelConcept\<Pixel>
834- PixelValueConcept\<Pixel>
835- HomogeneousPixelConcept\<Pixel>
836- MutableHomogeneousPixelConcept\<Pixel>
837- HomogeneousPixelValueConcept\<Pixel>
838- PixelsCompatibleConcept\<Pixel1,Pixel2>
839- PixelConvertibleConcept\<SrcPixel,DstPixel>
840
841<b>Models:</b>
842
843The most commonly used pixel is a homogeneous pixel whose values are together in memory.
844For this purpose GIL provides the struct \p pixel, templated over the channel value and layout:
845
846\code
847// models HomogeneousPixelValueConcept
848template <typename ChannelValue, typename Layout> struct pixel;
849
850// Those typedefs are already provided by GIL
851typedef pixel<bits8, rgb_layout_t> rgb8_pixel_t;
852typedef pixel<bits8, bgr_layout_t> bgr8_pixel_t;
853
854bgr8_pixel_t bgr8(255,0,0); // pixels can be initialized with the channels directly
855rgb8_pixel_t rgb8(bgr8); // compatible pixels can also be copy-constructed
856
857rgb8 = bgr8; // assignment and equality is defined between compatible pixels
858assert(rgb8 == bgr8); // assignment and equality operate on the semantic channels
859
860// The first physical channels of the two pixels are different
861assert(at_c<0>(rgb8) != at_c<0>(bgr8));
862assert(dynamic_at_c(bgr8,0) != dynamic_at_c(rgb8,0));
863assert(rgb8[0] != bgr8[0]); // same as above (but operator[] is defined for pixels only)
864\endcode
865
866Planar pixels have their channels distributed in memory. While they share the same value type (\p pixel) with interleaved pixels, their
867reference type is a proxy class containing references to each of the channels. This is implemented with the struct \p planar_pixel_reference:
868
869\code
870// models HomogeneousPixel
871template <typename ChannelReference, typename ColorSpace> struct planar_pixel_reference;
872
873// Define the type of a mutable and read-only reference. (These typedefs are already provided by GIL)
874typedef planar_pixel_reference< bits8&,rgb_t> rgb8_planar_ref_t;
875typedef planar_pixel_reference<const bits8&,rgb_t> rgb8c_planar_ref_t;
876\endcode
877
878Note that, unlike the \p pixel struct, planar pixel references are templated over the color space, not over the pixel layout. They always
879use a cannonical channel ordering. Ordering of their elements is unnecessary because their elements are references to the channels.
880
881Sometimes the channels of a pixel may not be byte-aligned. For example an RGB pixel in '5-5-6' format is a 16-bit pixel whose red, green and blue
882channels occupy bits [0..4],[5..9] and [10..15] respectively. GIL provides a model for such packed pixel formats:
883
884\code
885// define an rgb565 pixel
886typedef packed_pixel_type<uint16_t, mpl::vector3_c<unsigned,5,6,5>, rgb_layout_t>::type rgb565_pixel_t;
887
888function_requires<PixelValueConcept<rgb565_pixel_t> >();
889BOOST_STATIC_ASSERT((sizeof(rgb565_pixel_t)==2));
890
891// define a bgr556 pixel
892typedef packed_pixel_type<uint16_t, mpl::vector3_c<unsigned,5,6,5>, bgr_layout_t>::type bgr556_pixel_t;
893
894function_requires<PixelValueConcept<bgr556_pixel_t> >();
895
896// rgb565 is compatible with bgr556.
897function_requires<PixelsCompatibleConcept<rgb565_pixel_t,bgr556_pixel_t> >();
898\endcode
899
900In some cases, the pixel itself may not be byte aligned. For example, consider an RGB pixel in '2-3-2' format. Its size is 7 bits.
901GIL refers to such pixels, pixel iterators and images as "bit-aligned". Bit-aligned pixels (and images) are more complex than packed ones.
902Since packed pixels are byte-aligned, we can use a C++ reference as the reference type to a packed pixel, and a C pointer as an x_iterator
903over a row of packed pixels. For bit-aligned constructs we need a special reference proxy class (bit_aligned_pixel_reference) and iterator
904class (bit_aligned_pixel_iterator). The value type of bit-aligned pixels is a packed_pixel. Here is how to use bit_aligned pixels and pixel iterators:
905
906\code
907// Mutable reference to a BGR232 pixel
908typedef const bit_aligned_pixel_reference<unsigned char, mpl::vector3_c<unsigned,2,3,2>, bgr_layout_t, true> bgr232_ref_t;
909
910// A mutable iterator over BGR232 pixels
911typedef bit_aligned_pixel_iterator<bgr232_ref_t> bgr232_ptr_t;
912
913// BGR232 pixel value. It is a packed_pixel of size 1 byte. (The last bit is unused)
914typedef std::iterator_traits<bgr232_ptr_t>::value_type bgr232_pixel_t;
915BOOST_STATIC_ASSERT((sizeof(bgr232_pixel_t)==1));
916
917bgr232_pixel_t red(0,0,3); // = 0RRGGGBB, = 01100000 = 0x60
918
919// a buffer of 7 bytes fits exactly 8 BGR232 pixels.
920unsigned char pix_buffer[7];
921std::fill(pix_buffer,pix_buffer+7,0);
922
923// Fill the 8 pixels with red
924bgr232_ptr_t pix_it(&pix_buffer[0],0); // start at bit 0 of the first pixel
925for (int i=0; i<8; ++i) {
926 *pix_it++ = red;
927}
928// Result: 0x60 0x30 0x11 0x0C 0x06 0x83 0xC1
929\endcode
930
931
932<b>Algorithms:</b>
933
934Since pixels model \p ColorBaseConcept and \p PixelBasedConcept all algorithms and metafunctions of color bases can work with them as well:
935
936\code
937// This is how to access the first semantic channel (red)
938assert(semantic_at_c<0>(rgb8) == semantic_at_c<0>(bgr8));
939
940// This is how to access the red channel by name
941assert(get_color<red_t>(rgb8) == get_color<red_t>(bgr8));
942
943// This is another way of doing it (some compilers don't like the first one)
944assert(get_color(rgb8,red_t()) == get_color(bgr8,red_t()));
945
946// This is how to use the PixelBasedConcept metafunctions
947BOOST_MPL_ASSERT(num_channels<rgb8_pixel_t>::value == 3);
948BOOST_MPL_ASSERT((is_same<channel_type<rgb8_pixel_t>::type, bits8>));
949BOOST_MPL_ASSERT((is_same<color_space_type<bgr8_pixel_t>::type, rgb_t> ));
950BOOST_MPL_ASSERT((is_same<channel_mapping_type<bgr8_pixel_t>::type, mpl::vector3_c<int,2,1,0> > ));
951
952// Pixels contain just the three channels and nothing extra
953BOOST_MPL_ASSERT(sizeof(rgb8_pixel_t)==3);
954
955rgb8_planar_ref_t ref(bgr8); // copy construction is allowed from a compatible mutable pixel type
956
957get_color<red_t>(ref) = 10; // assignment is ok because the reference is mutable
958assert(get_color<red_t>(bgr8)==10); // references modify the value they are bound to
959
960// Create a zero packed pixel and a full regular unpacked pixel.
961rgb565_pixel_t r565;
962rgb8_pixel_t rgb_full(255,255,255);
963
964// Convert all channels of the unpacked pixel to the packed one & assert the packed one is full
965get_color(r565,red_t()) = channel_convert<rgb565_channel0_t>(get_color(rgb_full,red_t()));
966get_color(r565,green_t()) = channel_convert<rgb565_channel1_t>(get_color(rgb_full,green_t()));
967get_color(r565,blue_t()) = channel_convert<rgb565_channel2_t>(get_color(rgb_full,blue_t()));
968assert(r565 == rgb565_pixel_t((uint16_t)65535));
969\endcode
970
971GIL also provides the \p color_convert algorithm to convert between pixels of different color spaces and channel types:
972
973\code
974rgb8_pixel_t red_in_rgb8(255,0,0);
975cmyk16_pixel_t red_in_cmyk16;
976color_convert(red_in_rgb8,red_in_cmyk16);
977\endcode
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016<hr>
1017\section PixelIteratorSectionDG 8. Pixel Iterator
1018
1019\section FundamentalIteratorDG Fundamental Iterator
1020
1021Pixel iterators are random traversal iterators whose \p value_type models \p PixelValueConcept.
1022Pixel iterators provide metafunctions to determine whether they are mutable (i.e. whether they allow for modifying the pixel they refer to),
1023to get the immutable (read-only) type of the iterator, and to determine whether they are plain iterators or adaptors over another pixel iterator:
1024
1025\code
1026concept PixelIteratorConcept<RandomAccessTraversalIteratorConcept Iterator> : PixelBasedConcept<Iterator> {
1027 where PixelValueConcept<value_type>;
1028 typename const_iterator_type<It>::type;
1029 where PixelIteratorConcept<const_iterator_type<It>::type>;
1030 static const bool iterator_is_mutable<It>::type::value;
1031 static const bool is_iterator_adaptor<It>::type::value; // is it an iterator adaptor
1032};
1033
1034template <typename Iterator>
1035concept MutablePixelIteratorConcept : PixelIteratorConcept<Iterator>, MutableRandomAccessIteratorConcept<Iterator> {};
1036\endcode
1037
1038<b>Related Concepts:</b>
1039
1040- PixelIteratorConcept\<Iterator>
1041- MutablePixelIteratorConcept\<Iterator>
1042
1043<b>Models:</b>
1044
1045A built-in pointer to pixel, \p pixel<ChannelValue,Layout>*, is GIL's model for pixel iterator over interleaved homogeneous pixels.
1046Similarly, \p packed_pixel<PixelData,ChannelRefVec,Layout>* is GIL's model for an iterator over interleaved packed pixels.
1047
1048For planar homogeneous pixels, GIL provides the class \p planar_pixel_iterator, templated over a channel iterator and color space. Here is
1049how the standard mutable and read-only planar RGB iterators over unsigned char are defined:
1050
1051\code
1052template <typename ChannelPtr, typename ColorSpace> struct planar_pixel_iterator;
1053
1054// GIL provided typedefs
1055typedef planar_pixel_iterator<const bits8*, rgb_t> rgb8c_planar_ptr_t;
1056typedef planar_pixel_iterator< bits8*, rgb_t> rgb8_planar_ptr_t;
1057\endcode
1058
1059\p planar_pixel_iterator also models \p HomogeneousColorBaseConcept (it subclasses from \p homogeneous_color_base) and, as a result, all color base
1060algorithms apply to it. The element type of its color base is a channel iterator. For example, GIL implements \p operator++ of planar iterators approximately
1061like this:
1062
1063\code
1064template <typename T>
1065struct inc : public std::unary_function<T,T> {
1066 T operator()(T x) const { return ++x; }
1067};
1068
1069template <typename ChannelPtr, typename ColorSpace>
1070planar_pixel_iterator<ChannelPtr,ColorSpace>&
1071planar_pixel_iterator<ChannelPtr,ColorSpace>::operator++() {
1072 static_transform(*this,*this,inc<ChannelPtr>());
1073 return *this;
1074}
1075\endcode
1076
1077Since \p static_transform uses compile-time recursion, incrementing an instance of \p rgb8_planar_ptr_t amounts to three pointer increments.
1078GIL also uses the class bit_aligned_pixel_iterator as a model for a pixel iterator over bit-aligned pixels. Internally it keeps track of the current byte and
1079the bit offset.
1080
1081\section IteratorAdaptorDG Iterator Adaptor
1082
1083Iterator adaptor is an iterator that wraps around another iterator. Its \p is_iterator_adaptor metafunction must evaluate to true, and it
1084needs to provide a member method to return the base iterator, a metafunction to get its type, and a metafunction to rebind to another base iterator:
1085
1086\code
1087concept IteratorAdaptorConcept<RandomAccessTraversalIteratorConcept Iterator> {
1088 where SameType<is_iterator_adaptor<Iterator>::type, mpl::true_>;
1089
1090 typename iterator_adaptor_get_base<Iterator>;
1091 where Metafunction<iterator_adaptor_get_base<Iterator> >;
1092 where boost_concepts::ForwardTraversalConcept<iterator_adaptor_get_base<Iterator>::type>;
1093
1094 typename another_iterator;
1095 typename iterator_adaptor_rebind<Iterator,another_iterator>::type;
1096 where boost_concepts::ForwardTraversalConcept<another_iterator>;
1097 where IteratorAdaptorConcept<iterator_adaptor_rebind<Iterator,another_iterator>::type>;
1098
1099 const iterator_adaptor_get_base<Iterator>::type& Iterator::base() const;
1100};
1101
1102template <boost_concepts::Mutable_ForwardIteratorConcept Iterator>
1103concept MutableIteratorAdaptorConcept : IteratorAdaptorConcept<Iterator> {};
1104\endcode
1105
1106<b>Related Concepts:</b>
1107
1108- IteratorAdaptorConcept\<Iterator>
1109- MutableIteratorAdaptorConcept\<Iterator>
1110
1111<b>Models:</b>
1112
1113GIL provides several models of IteratorAdaptorConcept:
1114- \p memory_based_step_iterator\<Iterator>: An iterator adaptor that changes the fundamental step of the base iterator (see \ref StepIteratorDG)
1115- \p dereference_iterator_adaptor\<Iterator,Fn>: An iterator that applies a unary function \p Fn upon dereferencing. It is used, for example,
1116for on-the-fly color conversion. It can be used to construct a shallow image "view" that pretends to have a different color space or
1117channel depth. See \ref ImageViewFrowImageViewDG for more. The unary function \p Fn must model \p PixelDereferenceAdaptorConcept (see below).
1118
1119\section PixelDereferenceAdaptorAG Pixel Dereference Adaptor
1120
1121Pixel dereference adaptor is a unary function that can be applied upon dereferencing a pixel iterator. Its argument type could be anything
1122(usually a \p PixelConcept) and the result type must be convertible to \p PixelConcept
1123
1124\code
1125template <boost::UnaryFunctionConcept D>
1126concept PixelDereferenceAdaptorConcept : DefaultConstructibleConcept<D>, CopyConstructibleConcept<D>, AssignableConcept<D> {
1127 typename const_t; where PixelDereferenceAdaptorConcept<const_t>;
1128 typename value_type; where PixelValueConcept<value_type>;
1129 typename reference; where PixelConcept<remove_reference<reference>::type>; // may be mutable
1130 typename const_reference; // must not be mutable
1131 static const bool D::is_mutable;
1132
1133 where Convertible<value_type, result_type>;
1134};
1135\endcode
1136
1137<b>Models:</b>
1138
1139GIL provides several models of \p PixelDereferenceAdaptorConcept
1140 - \p color_convert_deref_fn: a function object that performs color conversion
1141 - \p detail::nth_channel_deref_fn: a function object that returns a grayscale pixel corresponding to the n-th channel of a given pixel
1142 - \p deref_compose: a function object that composes two models of \p PixelDereferenceAdaptorConcept. Similar to \p std::unary_compose, except
1143 it needs to pull the additional typedefs required by \p PixelDereferenceAdaptorConcept
1144
1145GIL uses pixel dereference adaptors to implement image views that perform color conversion upon dereferencing, or that return the N-th channel of the
1146underlying pixel. They can be used to model virtual image views that perform an arbitrary function upon dereferencing, for example a view of
1147the Mandelbrot set. \p dereference_iterator_adaptor<Iterator,Fn> is an iterator wrapper over a pixel iterator \p Iterator that invokes the given dereference
1148iterator adaptor \p Fn upon dereferencing.
1149
1150\section StepIteratorDG Step Iterator
1151
1152Sometimes we want to traverse pixels with a unit step other than the one provided by the fundamental pixel iterators.
1153Examples where this would be useful:
1154- a single-channel view of the red channel of an RGB interleaved image
1155- left-to-right flipped image (step = -fundamental_step)
1156- subsampled view, taking every N-th pixel (step = N*fundamental_step)
1157- traversal in vertical direction (step = number of bytes per row)
1158- any combination of the above (steps are multiplied)
1159
1160Step iterators are forward traversal iterators that allow changing the step between adjacent values:
1161
1162\code
1163concept StepIteratorConcept<boost_concepts::ForwardTraversalConcept Iterator> {
1164 template <Integral D> void Iterator::set_step(D step);
1165};
1166
1167concept MutableStepIteratorConcept<boost_concepts::Mutable_ForwardIteratorConcept Iterator> : StepIteratorConcept<Iterator> {};
1168\endcode
1169
1170GIL currently provides a step iterator whose \p value_type models \p PixelValueConcept. In addition, the step is specified in memory units (which are bytes or bits).
1171This is necessary, for example, when implementing an iterator navigating along a column of pixels - the size of a row of pixels
1172may sometimes not be divisible by the size of a pixel; for example rows may be word-aligned.
1173
1174To advance in bytes/bits, the base iterator must model MemoryBasedIteratorConcept. A memory-based iterator has an inherent memory unit, which is either a bit or a byte.
1175It must supply functions returning the number of bits per memory unit (1 or 8), the current step in memory units,
1176the memory-unit distance between two iterators, and a reference a given distance in memunits away. It must also supply a function that advances an iterator
1177a given distance in memory units.
1178 \p memunit_advanced and \p memunit_advanced_ref have a default implementation but some iterators may supply a more efficient version:
1179
1180\code
1181concept MemoryBasedIteratorConcept<boost_concepts::RandomAccessTraversalConcept Iterator> {
1182 typename byte_to_memunit<Iterator>; where metafunction<byte_to_memunit<Iterator> >;
1183 std::ptrdiff_t memunit_step(const Iterator&);
1184 std::ptrdiff_t memunit_distance(const Iterator& , const Iterator&);
1185 void memunit_advance(Iterator&, std::ptrdiff_t diff);
1186 Iterator memunit_advanced(const Iterator& p, std::ptrdiff_t diff) { Iterator tmp; memunit_advance(tmp,diff); return tmp; }
1187 Iterator::reference memunit_advanced_ref(const Iterator& p, std::ptrdiff_t diff) { return *memunit_advanced(p,diff); }
1188};
1189
1190\endcode
1191
1192It is useful to be able to construct a step iterator over another iterator. More generally, given a type, we want to be able to construct an equivalent
1193type that allows for dynamically specified horizontal step:
1194
1195\code
1196concept HasDynamicXStepTypeConcept<typename T> {
1197 typename dynamic_x_step_type<T>;
1198 where Metafunction<dynamic_x_step_type<T> >;
1199};
1200\endcode
1201
1202All models of pixel iterators, locators and image views that GIL provides support \p HasDynamicXStepTypeConcept.
1203
1204<b>Related Concepts:</b>
1205
1206- StepIteratorConcept\<Iterator>
1207- MutableStepIteratorConcept\<Iterator>
1208- MemoryBasedIteratorConcept\<Iterator>
1209- HasDynamicXStepTypeConcept\<T>
1210
1211<b>Models:</b>
1212
1213All standard memory-based iterators GIL currently provides model \p MemoryBasedIteratorConcept.
1214GIL provides the class \p memory_based_step_iterator which models \p PixelIteratorConcept, \p StepIteratorConcept, and \p MemoryBasedIteratorConcept.
1215It takes the base iterator as a template parameter (which must model \p PixelIteratorConcept and \p MemoryBasedIteratorConcept)
1216and allows changing the step dynamically. GIL's implementation contains the base iterator and a \p ptrdiff_t denoting the number of memory units (bytes or bits)
1217to skip for a unit step. It may also be used with a negative number. GIL provides a function to create a step iterator from a base iterator and a step:
1218
1219\code
1220template <typename I> // Models MemoryBasedIteratorConcept, HasDynamicXStepTypeConcept
1221typename dynamic_x_step_type<I>::type make_step_iterator(const I& it, std::ptrdiff_t step);
1222\endcode
1223
1224GIL also provides a model of an iterator over a virtual array of pixels, \p position_iterator. It is a step iterator that keeps track of the pixel position
1225and invokes a function object to get the value of the pixel upon dereferencing. It models \p PixelIteratorConcept and \p StepIteratorConcept but
1226not \p MemoryBasedIteratorConcept.
1227
1228\section LocatorDG Pixel Locator
1229
1230A Locator allows for navigation in two or more dimensions. Locators are N-dimensional iterators in spirit, but we use a different
1231name because they don't satisfy all the requirements of iterators. For example, they don't supply increment and decrement operators because it is unclear
1232which dimension the operators should advance along.
1233N-dimensional locators model the following concept:
1234
1235\code
1236concept RandomAccessNDLocatorConcept<Regular Loc> {
1237 typename value_type; // value over which the locator navigates
1238 typename reference; // result of dereferencing
1239 typename difference_type; where PointNDConcept<difference_type>; // return value of operator-.
1240 typename const_t; // same as Loc, but operating over immutable values
1241 typename cached_location_t; // type to store relative location (for efficient repeated access)
1242 typename point_t = difference_type;
1243
1244 static const size_t num_dimensions; // dimensionality of the locator
1245 where num_dimensions = point_t::num_dimensions;
1246
1247 // The difference_type and iterator type along each dimension. The iterators may only differ in
1248 // difference_type. Their value_type must be the same as Loc::value_type
1249 template <size_t D> struct axis {
1250 typename coord_t = point_t::axis<D>::coord_t;
1251 typename iterator; where RandomAccessTraversalConcept<iterator>; // iterator along D-th axis.
1252 where iterator::value_type == value_type;
1253 };
1254
1255 // Defines the type of a locator similar to this type, except it invokes Deref upon dereferencing
1256 template <PixelDereferenceAdaptorConcept Deref> struct add_deref {
1257 typename type; where RandomAccessNDLocatorConcept<type>;
1258 static type make(const Loc& loc, const Deref& deref);
1259 };
1260
1261 Loc& operator+=(Loc&, const difference_type&);
1262 Loc& operator-=(Loc&, const difference_type&);
1263 Loc operator+(const Loc&, const difference_type&);
1264 Loc operator-(const Loc&, const difference_type&);
1265
1266 reference operator*(const Loc&);
1267 reference operator[](const Loc&, const difference_type&);
1268
1269 // Storing relative location for faster repeated access and accessing it
1270 cached_location_t Loc::cache_location(const difference_type&) const;
1271 reference operator[](const Loc&,const cached_location_t&);
1272
1273 // Accessing iterators along a given dimension at the current location or at a given offset
1274 template <size_t D> axis<D>::iterator& Loc::axis_iterator();
1275 template <size_t D> axis<D>::iterator const& Loc::axis_iterator() const;
1276 template <size_t D> axis<D>::iterator Loc::axis_iterator(const difference_type&) const;
1277};
1278
1279template <typename Loc>
1280concept MutableRandomAccessNDLocatorConcept : RandomAccessNDLocatorConcept<Loc> {
1281 where Mutable<reference>;
1282};
1283\endcode
1284
1285Two-dimensional locators have additional requirements:
1286
1287\code
1288concept RandomAccess2DLocatorConcept<RandomAccessNDLocatorConcept Loc> {
1289 where num_dimensions==2;
1290 where Point2DConcept<point_t>;
1291
1292 typename x_iterator = axis<0>::iterator;
1293 typename y_iterator = axis<1>::iterator;
1294 typename x_coord_t = axis<0>::coord_t;
1295 typename y_coord_t = axis<1>::coord_t;
1296
1297 // Only available to locators that have dynamic step in Y
1298 //Loc::Loc(const Loc& loc, y_coord_t);
1299
1300 // Only available to locators that have dynamic step in X and Y
1301 //Loc::Loc(const Loc& loc, x_coord_t, y_coord_t, bool transposed=false);
1302
1303 x_iterator& Loc::x();
1304 x_iterator const& Loc::x() const;
1305 y_iterator& Loc::y();
1306 y_iterator const& Loc::y() const;
1307
1308 x_iterator Loc::x_at(const difference_type&) const;
1309 y_iterator Loc::y_at(const difference_type&) const;
1310 Loc Loc::xy_at(const difference_type&) const;
1311
1312 // x/y versions of all methods that can take difference type
1313 x_iterator Loc::x_at(x_coord_t, y_coord_t) const;
1314 y_iterator Loc::y_at(x_coord_t, y_coord_t) const;
1315 Loc Loc::xy_at(x_coord_t, y_coord_t) const;
1316 reference operator()(const Loc&, x_coord_t, y_coord_t);
1317 cached_location_t Loc::cache_location(x_coord_t, y_coord_t) const;
1318
1319 bool Loc::is_1d_traversable(x_coord_t width) const;
1320 y_coord_t Loc::y_distance_to(const Loc& loc2, x_coord_t x_diff) const;
1321};
1322
1323concept MutableRandomAccess2DLocatorConcept<RandomAccess2DLocatorConcept Loc> : MutableRandomAccessNDLocatorConcept<Loc> {};
1324\endcode
1325
13262D locators can have a dynamic step not just horizontally, but also vertically. This gives rise to the Y equivalent of \p HasDynamicXStepTypeConcept:
1327
1328\code
1329concept HasDynamicYStepTypeConcept<typename T> {
1330 typename dynamic_y_step_type<T>;
1331 where Metafunction<dynamic_y_step_type<T> >;
1332};
1333\endcode
1334
1335All locators and image views that GIL provides model \p HasDynamicYStepTypeConcept.
1336
1337Sometimes it is necessary to swap the meaning of X and Y for a given locator or image view type (for example, GIL provides a function to transpose an image view).
1338Such locators and views must be transposable:
1339
1340\code
1341concept HasTransposedTypeConcept<typename T> {
1342 typename transposed_type<T>;
1343 where Metafunction<transposed_type<T> >;
1344};
1345\endcode
1346
1347All GIL provided locators and views model \p HasTransposedTypeConcept.
1348
1349The locators GIL uses operate over models of \p PixelConcept and their x and y dimension types are the same. They model the following concept:
1350
1351\code
1352concept PixelLocatorConcept<RandomAccess2DLocatorConcept Loc> {
1353 where PixelValueConcept<value_type>;
1354 where PixelIteratorConcept<x_iterator>;
1355 where PixelIteratorConcept<y_iterator>;
1356 where x_coord_t == y_coord_t;
1357
1358 typename coord_t = x_coord_t;
1359};
1360
1361concept MutablePixelLocatorConcept<PixelLocatorConcept Loc> : MutableRandomAccess2DLocatorConcept<Loc> {};
1362\endcode
1363
1364<b>Related Concepts:</b>
1365
1366- HasDynamicYStepTypeConcept\<T>
1367- HasTransposedTypeConcept\<T>
1368- RandomAccessNDLocatorConcept\<Locator>
1369- MutableRandomAccessNDLocatorConcept\<Locator>
1370- RandomAccess2DLocatorConcept\<Locator>
1371- MutableRandomAccess2DLocatorConcept\<Locator>
1372- PixelLocatorConcept\<Locator>
1373- MutablePixelLocatorConcept\<Locator>
1374
1375<b>Models:</b>
1376
1377GIL provides two models of \p PixelLocatorConcept - a memory-based locator, \p memory_based_2d_locator and a virtual locator \p virtual_2d_locator.
1378
1379\p memory_based_2d_locator is a locator over planar or interleaved images that have their pixels in memory.
1380It takes a model of \p StepIteratorConcept over pixels as a template parameter. (When instantiated with a model of \p MutableStepIteratorConcept,
1381it models \p MutablePixelLocatorConcept).
1382
1383\code
1384template <typename StepIterator> // Models StepIteratorConcept, MemoryBasedIteratorConcept
1385class memory_based_2d_locator;
1386\endcode
1387
1388The step of \p StepIterator must be the number of memory units (bytes or bits) per row (thus it must be memunit advanceable). The class \p memory_based_2d_locator is a
1389wrapper around \p StepIterator and uses it to navigate vertically, while its base iterator is used to navigate horizontally.
1390
1391Combining fundamental and step iterators allows us to create locators that describe complex
1392pixel memory organizations. First, we have a choice of iterator to use for horizontal direction, i.e. for iterating over the pixels on the same row.
1393Using the fundamental and step iterators gives us four choices:
1394- \p pixel<T,C>* (for interleaved images)
1395- \p planar_pixel_iterator<T*,C> (for planar images)
1396- \p memory_based_step_iterator<pixel<T,C>*> (for interleaved images with non-standard step)
1397- <tt> memory_based_step_iterator<planar_pixel_iterator<T*,C> > </tt> (for planar images with non-standard step)
1398
1399Of course, one could provide their own custom x-iterator. One such example described later is an iterator adaptor that performs color
1400conversion when dereferenced.
1401
1402Given a horizontal iterator \p XIterator, we could choose the \e y-iterator, the iterator that moves along a column, as
1403\p memory_based_step_iterator<XIterator> with a step equal to the number of memory units (bytes or bits) per row. Again, one is free to provide their own y-iterator.
1404
1405Then we can instantiate \p memory_based_2d_locator<memory_based_step_iterator<XIterator> > to obtain a 2D pixel locator, as the diagram indicates:
1406\image html step_iterator.gif
1407
1408\p virtual_2d_locator is a locator that is instantiated with a function object invoked upon dereferencing a pixel. It returns the value of a pixel
1409given its X,Y coordiantes. Virtual locators can be used to implement virtual image views that can model any user-defined function. See the GIL
1410tutorial for an example of using virtual locators to create a view of the Mandelbrot set.
1411
1412Both the virtual and the memory-based locators subclass from \p pixel_2d_locator_base, a base class that provides most of the interface required
1413by \p PixelLocatorConcept. Users may find this base class useful if they need to provide other models of \p PixelLocatorConcept.
1414
1415Here is some sample code using locators:
1416
1417\code
1418loc=img.xy_at(10,10); // start at pixel (x=10,y=10)
1419above=loc.cache_location(0,-1); // remember relative locations of neighbors above and below
1420below=loc.cache_location(0, 1);
1421++loc.x(); // move to (11,10)
1422loc.y()+=15; // move to (11,25)
1423loc-=point2<std::ptrdiff_t>(1,1);// move to (10,24)
1424*loc=(loc(0,-1)+loc(0,1))/2; // set pixel (10,24) to the average of (10,23) and (10,25) (grayscale pixels only)
1425*loc=(loc[above]+loc[below])/2; // the same, but faster using cached relative neighbor locations
1426\endcode
1427
1428The standard GIL locators are fast and lightweight objects. For example, the locator for a simple interleaved image consists of
1429one raw pointer to the pixel location plus one integer for the row size in bytes, for a total of 8 bytes. <tt> ++loc.x() </tt> amounts to
1430incrementing a raw pointer (or N pointers for planar images). Computing 2D offsets is slower as it requires multiplication and addition.
1431Filters, for example, need to access the same neighbors for every pixel in the image, in which case the relative positions can be cached
1432into a raw byte difference using \p cache_location. In the above example <tt> loc[above]</tt> for simple interleaved images amounts to a raw array
1433index operator.
1434
1435\section IteratorFrom2DDG Iterator over 2D image
1436
1437Sometimes we want to perform the same, location-independent operation over all pixels of an image. In such a case it is useful to represent the pixels
1438as a one-dimensional array. GIL's \p iterator_from_2d is a random access traversal iterator that visits all pixels in an image in the natural
1439memory-friendly order left-to-right inside top-to-bottom. It takes a locator, the width of the image and the current X position. This is sufficient
1440information for it to determine when to do a "carriage return". Synopsis:
1441
1442\code
1443template <typename Locator> // Models PixelLocatorConcept
1444class iterator_from_2d {
1445public:
1446 iterator_from_2d(const Locator& loc, int x, int width);
1447
1448 iterator_from_2d& operator++(); // if (++_x<_width) ++_p.x(); else _p+=point_t(-_width,1);
1449
1450 ...
1451private:
1452 int _x, _width;
1453 Locator _p;
1454};
1455\endcode
1456
1457Iterating through the pixels in an image using \p iterator_from_2d is slower than going through all rows and using the x-iterator at each row.
1458This is because two comparisons are done per iteration step - one for the end condition of the loop using the iterators, and one inside
1459\p iterator_from_2d::operator++ to determine whether we are at the end of a row. For fast operations, such as pixel copy, this second check
1460adds about 15% performance delay (measured for interleaved images on Intel platform). GIL overrides some STL algorithms, such as \p std::copy and
1461\p std::fill, when invoked with \p iterator_from_2d-s, to go through each row using their base x-iterators, and, if the image has no padding
1462(i.e. \p iterator_from_2d::is_1d_traversable() returns true) to simply iterate using the x-iterators directly.
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488<hr>
1489\section ImageViewSectionDG 9. Image View
1490
1491An image view is a generalization of STL's range concept to multiple dimensions. Similar to ranges (and iterators), image views are shallow, don't
1492own the underlying data and don't propagate their constness over the data. For example, a constant image view cannot be resized, but may allow
1493modifying the pixels. For pixel-immutable operations, use constant-value image view (also called non-mutable image view).
1494Most general N-dimensional views satisfy the following concept:
1495
1496\code
1497concept RandomAccessNDImageViewConcept<Regular View> {
1498 typename value_type; // for pixel-based views, the pixel type
1499 typename reference; // result of dereferencing
1500 typename difference_type; // result of operator-(iterator,iterator) (1-dimensional!)
1501 typename const_t; where RandomAccessNDImageViewConcept<View>; // same as View, but over immutable values
1502 typename point_t; where PointNDConcept<point_t>; // N-dimensional point
1503 typename locator; where RandomAccessNDLocatorConcept<locator>; // N-dimensional locator.
1504 typename iterator; where RandomAccessTraversalConcept<iterator>; // 1-dimensional iterator over all values
1505 typename reverse_iterator; where RandomAccessTraversalConcept<reverse_iterator>;
1506 typename size_type; // the return value of size()
1507
1508 // Equivalent to RandomAccessNDLocatorConcept::axis
1509 template <size_t D> struct axis {
1510 typename coord_t = point_t::axis<D>::coord_t;
1511 typename iterator; where RandomAccessTraversalConcept<iterator>; // iterator along D-th axis.
1512 where SameType<coord_t, iterator::difference_type>;
1513 where SameType<iterator::value_type,value_type>;
1514 };
1515
1516 // Defines the type of a view similar to this type, except it invokes Deref upon dereferencing
1517 template <PixelDereferenceAdaptorConcept Deref> struct add_deref {
1518 typename type; where RandomAccessNDImageViewConcept<type>;
1519 static type make(const View& v, const Deref& deref);
1520 };
1521
1522 static const size_t num_dimensions = point_t::num_dimensions;
1523
1524 // Create from a locator at the top-left corner and dimensions
1525 View::View(const locator&, const point_type&);
1526
1527 size_type View::size() const; // total number of elements
1528 reference operator[](View, const difference_type&) const; // 1-dimensional reference
1529 iterator View::begin() const;
1530 iterator View::end() const;
1531 reverse_iterator View::rbegin() const;
1532 reverse_iterator View::rend() const;
1533 iterator View::at(const point_t&);
1534 point_t View::dimensions() const; // number of elements along each dimension
1535 bool View::is_1d_traversable() const; // Does an iterator over the first dimension visit each value?
1536
1537 // iterator along a given dimension starting at a given point
1538 template <size_t D> View::axis<D>::iterator View::axis_iterator(const point_t&) const;
1539
1540 reference operator()(View,const point_t&) const;
1541};
1542
1543concept MutableRandomAccessNDImageViewConcept<RandomAccessNDImageViewConcept View> {
1544 where Mutable<reference>;
1545};
1546\endcode
1547
1548Two-dimensional image views have the following extra requirements:
1549
1550\code
1551concept RandomAccess2DImageViewConcept<RandomAccessNDImageViewConcept View> {
1552 where num_dimensions==2;
1553
1554 typename x_iterator = axis<0>::iterator;
1555 typename y_iterator = axis<1>::iterator;
1556 typename x_coord_t = axis<0>::coord_t;
1557 typename y_coord_t = axis<1>::coord_t;
1558 typename xy_locator = locator;
1559
1560 x_coord_t View::width() const;
1561 y_coord_t View::height() const;
1562
1563 // X-navigation
1564 x_iterator View::x_at(const point_t&) const;
1565 x_iterator View::row_begin(y_coord_t) const;
1566 x_iterator View::row_end (y_coord_t) const;
1567
1568 // Y-navigation
1569 y_iterator View::y_at(const point_t&) const;
1570 y_iterator View::col_begin(x_coord_t) const;
1571 y_iterator View::col_end (x_coord_t) const;
1572
1573 // navigating in 2D
1574 xy_locator View::xy_at(const point_t&) const;
1575
1576 // (x,y) versions of all methods taking point_t
1577 View::View(x_coord_t,y_coord_t,const locator&);
1578 iterator View::at(x_coord_t,y_coord_t) const;
1579 reference operator()(View,x_coord_t,y_coord_t) const;
1580 xy_locator View::xy_at(x_coord_t,y_coord_t) const;
1581 x_iterator View::x_at(x_coord_t,y_coord_t) const;
1582 y_iterator View::y_at(x_coord_t,y_coord_t) const;
1583};
1584
1585concept MutableRandomAccess2DImageViewConcept<RandomAccess2DImageViewConcept View>
1586 : MutableRandomAccessNDImageViewConcept<View> {};
1587\endcode
1588
1589Image views that GIL typically uses operate on value types that model \p PixelValueConcept and have some additional requirements:
1590
1591\code
1592concept ImageViewConcept<RandomAccess2DImageViewConcept View> {
1593 where PixelValueConcept<value_type>;
1594 where PixelIteratorConcept<x_iterator>;
1595 where PixelIteratorConcept<y_iterator>;
1596 where x_coord_t == y_coord_t;
1597
1598 typename coord_t = x_coord_t;
1599
1600 std::size_t View::num_channels() const;
1601};
1602
1603
1604concept MutableImageViewConcept<ImageViewConcept View> : MutableRandomAccess2DImageViewConcept<View> {};
1605\endcode
1606
1607Two image views are compatible if they have compatible pixels and the same number of dimensions:
1608\code
1609concept ViewsCompatibleConcept<ImageViewConcept V1, ImageViewConcept V2> {
1610 where PixelsCompatibleConcept<V1::value_type, V2::value_type>;
1611 where V1::num_dimensions == V2::num_dimensions;
1612};
1613\endcode
1614
1615Compatible views must also have the same dimensions (i.e. the same width and height). Many algorithms taking multiple views require that they be pairwise compatible.
1616
1617<b>Related Concepts:</b>
1618
1619- RandomAccessNDImageViewConcept\<View>
1620- MutableRandomAccessNDImageViewConcept\<View>
1621- RandomAccess2DImageViewConcept\<View>
1622- MutableRandomAccess2DImageViewConcept\<View>
1623- ImageViewConcept\<View>
1624- MutableImageViewConcept\<View>
1625- ViewsCompatibleConcept\<View1,View2>
1626
1627<b>Models:</b>
1628
1629GIL provides a model for \p ImageViewConcept called \p image_view. It is templated over a model of \p PixelLocatorConcept.
1630(If instantiated with a model of \p MutablePixelLocatorConcept, it models \p MutableImageViewConcept). Synopsis:
1631
1632\code
1633template <typename Locator> // Models PixelLocatorConcept (could be MutablePixelLocatorConcept)
1634class image_view {
1635public:
1636 typedef Locator xy_locator;
1637 typedef iterator_from_2d<Locator> iterator;
1638 ...
1639private:
1640 xy_locator _pixels; // 2D pixel locator at the top left corner of the image view range
1641 point_t _dimensions; // width and height
1642};
1643\endcode
1644
1645Image views are lightweight objects. A regular interleaved view is typically 16 bytes long - two integers for the width and height (inside dimensions)
1646one for the number of bytes between adjacent rows (inside the locator) and one pointer to the beginning of the pixel block.
1647
1648<b>Algorithms:</b>
1649
1650\subsection ImageViewFrowRawDG Creating Views from Raw Pixels
1651
1652Standard image views can be constructed from raw data of any supported color space, bit depth, channel ordering or planar vs. interleaved structure.
1653Interleaved views are constructed using \p interleaved_view, supplying the image dimensions, number of bytes per row, and a
1654pointer to the first pixel:
1655
1656\code
1657template <typename Iterator> // Models pixel iterator (like rgb8_ptr_t or rgb8c_ptr_t)
1658image_view<...> interleaved_view(ptrdiff_t width, ptrdiff_t height, Iterator pixels, ptrdiff_t rowsize)
1659\endcode
1660
1661Planar views are defined for every color space and take each plane separately. Here is the RGB one:
1662
1663\code
1664template <typename IC> // Models channel iterator (like bits8* or const bits8*)
1665image_view<...> planar_rgb_view(ptrdiff_t width, ptrdiff_t height,
1666 IC r, IC g, IC b, ptrdiff_t rowsize);
1667\endcode
1668
1669Note that the supplied pixel/channel iterators could be constant (read-only), in which case the returned view is a constant-value (immutable) view.
1670
1671\subsection ImageViewFrowImageViewDG Creating Image Views from Other Image Views
1672
1673It is possible to construct one image view from another by changing some policy of how image data is interpreted. The result could be a view whose type is
1674derived from the type of the source. GIL uses the following metafunctions to get the derived types:
1675
1676\code
1677
1678// Some result view types
1679template <typename View>
1680struct dynamic_xy_step_type : public dynamic_y_step_type<typename dynamic_x_step_type<View>::type> {};
1681
1682template <typename View>
1683struct dynamic_xy_step_transposed_type : public dynamic_xy_step_type<typename transposed_type<View>::type> {};
1684
1685// color and bit depth converted view to match pixel type P
1686template <typename SrcView, // Models ImageViewConcept
1687 typename DstP, // Models PixelConcept
1688 typename ColorConverter=gil::default_color_converter>
1689struct color_converted_view_type {
1690 typedef ... type; // image view adaptor with value type DstP, over SrcView
1691};
1692
1693// single-channel view of the N-th channel of a given view
1694template <typename SrcView>
1695struct nth_channel_view_type {
1696 typedef ... type;
1697};
1698\endcode
1699
1700GIL Provides the following view transformations:
1701
1702\code
1703// flipped upside-down, left-to-right, transposed view
1704template <typename View> typename dynamic_y_step_type<View>::type flipped_up_down_view(const View& src);
1705template <typename View> typename dynamic_x_step_type<View>::type flipped_left_right_view(const View& src);
1706template <typename View> typename dynamic_xy_step_transposed_type<View>::type transposed_view(const View& src);
1707
1708// rotations
1709template <typename View> typename dynamic_xy_step_type<View>::type rotated180_view(const View& src);
1710template <typename View> typename dynamic_xy_step_transposed_type<View>::type rotated90cw_view(const View& src);
1711template <typename View> typename dynamic_xy_step_transposed_type<View>::type rotated90ccw_view(const View& src);
1712
1713// view of an axis-aligned rectangular area within an image
1714template <typename View> View subimage_view(const View& src,
1715 const View::point_t& top_left, const View::point_t& dimensions);
1716
1717// subsampled view (skipping pixels in X and Y)
1718template <typename View> typename dynamic_xy_step_type<View>::type subsampled_view(const View& src,
1719 const View::point_t& step);
1720
1721template <typename View, typename P>
1722color_converted_view_type<View,P>::type color_converted_view(const View& src);
1723template <typename View, typename P, typename CCV> // with a custom color converter
1724color_converted_view_type<View,P,CCV>::type color_converted_view(const View& src);
1725
1726template <typename View>
1727nth_channel_view_type<View>::view_t nth_channel_view(const View& view, int n);
1728\endcode
1729
1730The implementations of most of these view factory methods are straightforward. Here is, for example, how the flip views are implemented.
1731The flip upside-down view creates a view whose first pixel is the bottom left pixel of the original view and whose y-step is the negated
1732step of the source.
1733
1734\code
1735template <typename View>
1736typename dynamic_y_step_type<View>::type flipped_up_down_view(const View& src) {
1737 gil_function_requires<ImageViewConcept<View> >();
1738 typedef typename dynamic_y_step_type<View>::type RView;
1739 return RView(src.dimensions(),typename RView::xy_locator(src.xy_at(0,src.height()-1),-1));
1740}
1741\endcode
1742
1743The call to \p gil_function_requires ensures (at compile time) that the template parameter is a valid model of \p ImageViewConcept. Using it
1744generates easier to track compile errors, creates no extra code and has no run-time performance impact.
1745We are using the \p boost::concept_check library, but wrapping it in \p gil_function_requires, which performs the check if the \p BOOST_GIL_USE_CONCEPT_CHECK
1746is set. It is unset by default, because there is a significant increase in compile time when using concept checks. We will skip \p gil_function_requires
1747in the code examples in this guide for the sake of succinctness.
1748
1749Image views can be freely composed (see section \ref MetafunctionsDG for the typedefs \p rgb16_image_t and \p gray16_step_view_t):
1750
1751\code
1752rgb16_image_t img(100,100); // an RGB interleaved image
1753
1754// grayscale view over the green (index 1) channel of img
1755gray16_step_view_t green=nth_channel_view(view(img),1);
1756
1757// 50x50 view of the green channel of img, upside down and taking every other pixel in X and in Y
1758gray16_step_view_t ud_fud=flipped_up_down_view(subsampled_view(green,2,2));
1759\endcode
1760
1761As previously stated, image views are fast, constant-time, shallow views over the pixel data. The above code does not copy any pixels; it operates
1762on the pixel data allocated when \p img was created.
1763
1764\subsection ImageViewAlgorithmsDG STL-Style Algorithms on Image Views
1765
1766<p>Image views provide 1D iteration of their pixels via begin() and end() methods, which makes it possible to use STL
1767algorithms with them. However, using nested loops over X and Y is in many cases more efficient. The algorithms in this
1768section resemble STL algorithms, but they abstract away the nested loops and take views (as opposed to ranges) as input.
1769
1770\code
1771// Equivalents of std::copy and std::uninitialized_copy
1772// where ImageViewConcept<V1>, MutableImageViewConcept<V2>, ViewsCompatibleConcept<V1,V2>
1773template <typename V1, typename V2>
1774void copy_pixels(const V1& src, const V2& dst);
1775template <typename V1, typename V2>
1776void uninitialized_copy_pixels(const V1& src, const V2& dst);
1777
1778// Equivalents of std::fill and std::uninitialized_fill
1779// where MutableImageViewConcept<V>, PixelConcept<Value>, PixelsCompatibleConcept<Value,V::value_type>
1780template <typename V, typename Value>
1781void fill_pixels(const V& dst, const Value& val);
1782template <typename V, typename Value>
1783void uninitialized_fill_pixels(const V& dst, const Value& val);
1784
1785// Equivalent of std::for_each
1786// where ImageViewConcept<V>, boost::UnaryFunctionConcept<F>
1787// where PixelsCompatibleConcept<V::reference, F::argument_type>
1788template <typename V, typename F>
1789F for_each_pixel(const V& view, F fun);
1790template <typename V, typename F>
1791F for_each_pixel_position(const V& view, F fun);
1792
1793// Equivalent of std::generate
1794// where MutableImageViewConcept<V>, boost::UnaryFunctionConcept<F>
1795// where PixelsCompatibleConcept<V::reference, F::argument_type>
1796template <typename V, typename F>
1797void generate_pixels(const V& dst, F fun);
1798
1799// Equivalent of std::transform with one source
1800// where ImageViewConcept<V1>, MutableImageViewConcept<V2>
1801// where boost::UnaryFunctionConcept<F>
1802// where PixelsCompatibleConcept<V1::const_reference, F::argument_type>
1803// where PixelsCompatibleConcept<F::result_type, V2::reference>
1804template <typename V1, typename V2, typename F>
1805F transform_pixels(const V1& src, const V2& dst, F fun);
1806template <typename V1, typename V2, typename F>
1807F transform_pixel_positions(const V1& src, const V2& dst, F fun);
1808
1809// Equivalent of std::transform with two sources
1810// where ImageViewConcept<V1>, ImageViewConcept<V2>, MutableImageViewConcept<V3>
1811// where boost::BinaryFunctionConcept<F>
1812// where PixelsCompatibleConcept<V1::const_reference, F::first_argument_type>
1813// where PixelsCompatibleConcept<V2::const_reference, F::second_argument_type>
1814// where PixelsCompatibleConcept<F::result_type, V3::reference>
1815template <typename V1, typename V2, typename V3, typename F>
1816F transform_pixels(const V1& src1, const V2& src2, const V3& dst, F fun);
1817template <typename V1, typename V2, typename V3, typename F>
1818F transform_pixel_positions(const V1& src1, const V2& src2, const V3& dst, F fun);
1819
1820// Copies a view into another, color converting the pixels if needed, with the default or user-defined color converter
1821// where ImageViewConcept<V1>, MutableImageViewConcept<V2>
1822// V1::value_type must be convertible to V2::value_type.
1823template <typename V1, typename V2>
1824void copy_and_convert_pixels(const V1& src, const V2& dst);
1825template <typename V1, typename V2, typename ColorConverter>
1826void copy_and_convert_pixels(const V1& src, const V2& dst, ColorConverter ccv);
1827
1828// Equivalent of std::equal
1829// where ImageViewConcept<V1>, ImageViewConcept<V2>, ViewsCompatibleConcept<V1,V2>
1830template <typename V1, typename V2>
1831bool equal_pixels(const V1& view1, const V2& view2);
1832\endcode
1833
1834Algorithms that take multiple views require that they have the same dimensions.
1835\p for_each_pixel_position and \p transform_pixel_positions pass pixel locators, as opposed to pixel references, to their function objects.
1836This allows for writing algorithms that use pixel neighbors, as the tutorial demonstrates.
1837
1838Most of these algorithms check whether the image views are 1D-traversable. A 1D-traversable image view has no gaps at the end of the rows.
1839In other words, if an x_iterator of that view is advanced past the last pixel in a row it will move to the first pixel of the next row.
1840When image views are 1D-traversable, the algorithms use a single loop and run more efficiently. If one or more of the input views are not
18411D-traversable, the algorithms fall-back to an X-loop nested inside a Y-loop.
1842
1843The algorithms typically delegate the work to their corresponding STL algorithms. For example, \p copy_pixels calls \p std::copy either for each
1844row, or, when the images are 1D-traversable, once for all pixels.
1845
1846In addition, overloads are sometimes provided for the STL algorithms. For example, \p std::copy for planar iterators is overloaded to perform
1847\p std::copy for each of the planes. \p std::copy over bitwise-copiable pixels results in \p std::copy over unsigned char, which STL typically
1848implements via \p memmove.
1849
1850As a result \p copy_pixels may result in a single call to \p memmove for interleaved 1D-traversable views, or one per each plane of planar
18511D-traversable views, or one per each row of interleaved non-1D-traversable images, etc.
1852
1853GIL also provides some beta-versions of image processing algorithms, such as resampling and convolution in a numerics extension available on
1854http://stlab.adobe.com/gil/download.html. This code is in early stage of development and is not optimized for speed
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875<hr>
1876\section ImageSectionDG 10. Image
1877
1878An image is a container that owns the pixels of a given image view. It allocates them in its constructor and deletes
1879them in the destructor. It has a deep assignment operator and copy constructor. Images are used rarely, just when
1880data ownership is important. Most STL algorithms operate on ranges, not containers. Similarly most GIL algorithms operate on image
1881views (which images provide).
1882
1883In the most general form images are N-dimensional and satisfy the following concept:
1884
1885\code
1886concept RandomAccessNDImageConcept<typename Img> : Regular<Img> {
1887 typename view_t; where MutableRandomAccessNDImageViewConcept<view_t>;
1888 typename const_view_t = view_t::const_t;
1889 typename point_t = view_t::point_t;
1890 typename value_type = view_t::value_type;
1891 typename allocator_type;
1892
1893 Img::Img(point_t dims, std::size_t alignment=0);
1894 Img::Img(point_t dims, value_type fill_value, std::size_t alignment);
1895
1896 void Img::recreate(point_t new_dims, std::size_t alignment=0);
1897 void Img::recreate(point_t new_dims, value_type fill_value, std::size_t alignment);
1898
1899 const point_t& Img::dimensions() const;
1900 const const_view_t& const_view(const Img&);
1901 const view_t& view(Img&);
1902};
1903\endcode
1904
1905Two-dimensional images have additional requirements:
1906
1907\code
1908concept RandomAccess2DImageConcept<RandomAccessNDImageConcept Img> {
1909 typename x_coord_t = const_view_t::x_coord_t;
1910 typename y_coord_t = const_view_t::y_coord_t;
1911
1912 Img::Img(x_coord_t width, y_coord_t height, std::size_t alignment=0);
1913 Img::Img(x_coord_t width, y_coord_t height, value_type fill_value, std::size_t alignment);
1914
1915 x_coord_t Img::width() const;
1916 y_coord_t Img::height() const;
1917
1918 void Img::recreate(x_coord_t width, y_coord_t height, std::size_t alignment=1);
1919 void Img::recreate(x_coord_t width, y_coord_t height, value_type fill_value, std::size_t alignment);
1920};
1921\endcode
1922
1923GIL's images have views that model \p ImageViewConcept and operate on pixels.
1924
1925\code
1926concept ImageConcept<RandomAccess2DImageConcept Img> {
1927 where MutableImageViewConcept<view_t>;
1928 typename coord_t = view_t::coord_t;
1929};
1930\endcode
1931
1932Images, unlike locators and image views, don't have 'mutable' set of concepts because immutable images are not very useful.
1933
1934<b>Related Concepts:</b>
1935
1936- RandomAccessNDImageConcept\<Image>
1937- RandomAccess2DImageConcept\<Image>
1938- ImageConcept\<Image>
1939
1940<b>Models:</b>
1941
1942GIL provides a class, \p image, which is templated over the value type (the pixel) and models \p ImageConcept.
1943
1944\code
1945template <typename Pixel, \\ Models PixelValueConcept
1946 bool IsPlanar, \\ planar or interleaved image
1947 typename A=std::allocator<unsigned char> >
1948class image;
1949\endcode
1950
1951The image constructor takes an alignment parameter which allows for constructing images that are word-aligned or 8-byte aligned. The alignment is specified in
1952bytes. The default value for alignment is 0, which means there is no padding at the end of rows. Many operations are
1953faster using such 1D-traversable images, because \p image_view::x_iterator can be used to traverse the pixels, instead of the more complicated
1954\p image_view::iterator. Note that when alignment is 0, packed images are aligned to the bit - i.e. there are no padding bits at the end of rows of packed images.
1955<hr>
1956\section VariantSecDG 11. Run-time specified images and image views
1957
1958The color space, channel depth, channel ordering, and interleaved/planar structure of an image are defined by the type of its template argument, which
1959makes them compile-time bound. Often some of these parameters are available only at run time.
1960Consider, for example, writing a module that opens the image at a given file path, rotates it and saves it back in its original color space and channel
1961depth. How can we possibly write this using our generic image? What type is the image loading code supposed to return?
1962
1963<p>GIL's dynamic_image extension allows for images, image views or any GIL constructs to have their parameters defined at run time. Here is an example:
1964\code
1965#include <boost/gil/extension/dynamic_image/dynamic_image_all.hpp>
1966using namespace boost;
1967
1968#define ASSERT_SAME(A,B) BOOST_STATIC_ASSERT((is_same< A,B >::value))
1969
1970// Define the set of allowed images
1971typedef mpl::vector<rgb8_image_t, cmyk16_planar_image_t> my_images_t;
1972
1973// Create any_image class (or any_image_view) class
1974typedef any_image<my_images_t> my_any_image_t;
1975
1976// Associated view types are available (equivalent to the ones in image_t)
1977typedef any_image_view<mpl::vector2<rgb8_view_t, cmyk16_planar_view_t > > AV;
1978ASSERT_SAME(my_any_image_t::view_t, AV);
1979
1980typedef any_image_view<mpl::vector2<rgb8c_view_t, cmyk16c_planar_view_t> > CAV;
1981ASSERT_SAME(my_any_image_t::const_view_t, CAV);
1982ASSERT_SAME(my_any_image_t::const_view_t, my_any_image_t::view_t::const_t);
1983
1984typedef any_image_view<mpl::vector2<rgb8_step_view_t, cmyk16_planar_step_view_t> > SAV;
1985ASSERT_SAME(typename dynamic_x_step_type<my_any_image_t::view_t>::type, SAV);
1986
1987// Assign it a concrete image at run time:
1988my_any_image_t myImg = my_any_image_t(rgb8_image_t(100,100));
1989
1990// Change it to another at run time. The previous image gets destroyed
1991myImg = cmyk16_planar_image_t(200,100);
1992
1993// Assigning to an image not in the allowed set throws an exception
1994myImg = gray8_image_t(); // will throw std::bad_cast
1995\endcode
1996
1997\p any_image and \p any_image_view subclass from GIL's \p variant class, which breaks down the instantiated type
1998into a non-templated underlying base type and a unique instantiation type identifier. The underlying base instance is represented
1999as a block of bytes. The block is large enough to hold the largest of the specified types.
2000
2001GIL's variant is similar to \p boost::variant in spirit (hence we borrow the name from there) but it differs in several ways from
2002the current boost implementation. Perhaps the biggest difference is that GIL's variant always takes a single argument, which is a model
2003of MPL Random Access Sequence enumerating the allowed types. Having a single interface allows GIL's variant to be used easier in generic code. Synopsis:
2004
2005\code
2006template <typename Types> // models MPL Random Access Container
2007class variant {
2008 ... _bits;
2009 std::size_t _index;
2010public:
2011 typedef Types types_t;
2012
2013 variant();
2014 variant(const variant& v);
2015 virtual ~variant();
2016
2017 variant& operator=(const variant& v);
2018 template <typename TS> friend bool operator==(const variant<TS>& x, const variant<TS>& y);
2019 template <typename TS> friend bool operator!=(const variant<TS>& x, const variant<TS>& y);
2020
2021 // Construct/assign to type T. Throws std::bad_cast if T is not in Types
2022 template <typename T> explicit variant(const T& obj);
2023 template <typename T> variant& operator=(const T& obj);
2024
2025 // Construct/assign by swapping T with its current instance. Only possible if they are swappable
2026 template <typename T> explicit variant(T& obj, bool do_swap);
2027 template <typename T> void move_in(T& obj);
2028
2029 template <typename T> static bool has_type();
2030
2031 template <typename T> const T& _dynamic_cast() const;
2032 template <typename T> T& _dynamic_cast();
2033
2034 template <typename T> bool current_type_is() const;
2035};
2036
2037template <typename UOP, typename Types>
2038 UOP::result_type apply_operation(variant<Types>& v, UOP op);
2039template <typename UOP, typename Types>
2040 UOP::result_type apply_operation(const variant<Types>& v, UOP op);
2041
2042template <typename BOP, typename Types1, typename Types2>
2043 BOP::result_type apply_operation( variant<Types1>& v1, variant<Types2>& v2, UOP op);
2044
2045template <typename BOP, typename Types1, typename Types2>
2046 BOP::result_type apply_operation(const variant<Types1>& v1, variant<Types2>& v2, UOP op);
2047
2048template <typename BOP, typename Types1, typename Types2>
2049 BOP::result_type apply_operation(const variant<Types1>& v1, const variant<Types2>& v2, UOP op);
2050\endcode
2051
2052GIL's \p any_image_view and \p any_image are subclasses of \p variant:
2053
2054\code
2055template <typename ImageViewTypes>
2056class any_image_view : public variant<ImageViewTypes> {
2057public:
2058 typedef ... const_t; // immutable equivalent of this
2059 typedef std::ptrdiff_t x_coord_t;
2060 typedef std::ptrdiff_t y_coord_t;
2061 typedef point2<std::ptrdiff_t> point_t;
2062
2063 any_image_view();
2064 template <typename T> explicit any_image_view(const T& obj);
2065 any_image_view(const any_image_view& v);
2066
2067 template <typename T> any_image_view& operator=(const T& obj);
2068 any_image_view& operator=(const any_image_view& v);
2069
2070 // parameters of the currently instantiated view
2071 std::size_t num_channels() const;
2072 point_t dimensions() const;
2073 x_coord_t width() const;
2074 y_coord_t height() const;
2075};
2076
2077template <typename ImageTypes>
2078class any_image : public variant<ImageTypes> {
2079 typedef variant<ImageTypes> parent_t;
2080public:
2081 typedef ... const_view_t;
2082 typedef ... view_t;
2083 typedef std::ptrdiff_t x_coord_t;
2084 typedef std::ptrdiff_t y_coord_t;
2085 typedef point2<std::ptrdiff_t> point_t;
2086
2087 any_image();
2088 template <typename T> explicit any_image(const T& obj);
2089 template <typename T> explicit any_image(T& obj, bool do_swap);
2090 any_image(const any_image& v);
2091
2092 template <typename T> any_image& operator=(const T& obj);
2093 any_image& operator=(const any_image& v);
2094
2095 void recreate(const point_t& dims, unsigned alignment=1);
2096 void recreate(x_coord_t width, y_coord_t height, unsigned alignment=1);
2097
2098 std::size_t num_channels() const;
2099 point_t dimensions() const;
2100 x_coord_t width() const;
2101 y_coord_t height() const;
2102};
2103\endcode
2104
2105Operations are invoked on variants via \p apply_operation passing a function object to perform the operation. The code for every allowed type in the
2106variant is instantiated and the appropriate instantiation is selected via a switch statement. Since image view algorithms typically have time complexity
2107at least linear on the number of pixels, the single switch statement of image view variant adds practically no measurable performance overhead compared
2108to templated image views.
2109
2110Variants behave like the underlying type. Their copy constructor will invoke the copy constructor of the underlying instance. Equality operator will
2111check if the two instances are of the same type and then invoke their operator==, etc. The default constructor of a variant will default-construct the
2112first type. That means that \p any_image_view has shallow default-constructor, copy-constructor, assigment and equaty comparison, whereas \p any_image
2113has deep ones.
2114
2115It is important to note that even though \p any_image_view and \p any_image resemble the static \p image_view and \p image, they do not model the full
2116requirements of \p ImageViewConcept and \p ImageConcept. In particular they don't provide access to the pixels. There is no "any_pixel" or
2117"any_pixel_iterator" in GIL. Such constructs could be provided via the \p variant mechanism, but doing so would result in inefficient algorithms, since
2118the type resolution would have to be performed per pixel. Image-level algorithms should be implemented via \p apply_operation. That said,
2119many common operations are shared between the static and dynamic types. In addition, all of the image view transformations and many STL-like image view
2120algorithms have overloads operating on \p any_image_view, as illustrated with \p copy_pixels:
2121
2122\code
2123rgb8_view_t v1(...); // concrete image view
2124bgr8_view_t v2(...); // concrete image view compatible with v1 and of the same size
2125any_image_view<Types> av(...); // run-time specified image view
2126
2127// Copies the pixels from v1 into v2.
2128// If the pixels are incompatible triggers compile error
2129copy_pixels(v1,v2);
2130
2131// The source or destination (or both) may be run-time instantiated.
2132// If they happen to be incompatible, throws std::bad_cast
2133copy_pixels(v1, av);
2134copy_pixels(av, v2);
2135copy_pixels(av, av);
2136\endcode
2137
2138By having algorithm overloads supporting dynamic constructs, we create a base upon which it is possible to write algorithms that can work with
2139either compile-time or runtime images or views. The following code, for example, uses the GIL I/O extension to turn an image on disk upside down:
2140
2141\code
2142#include <boost\gil\extension\io\jpeg_dynamic_io.hpp>
2143
2144template <typename Image> // Could be rgb8_image_t or any_image<...>
2145void save_180rot(const std::string& file_name) {
2146 Image img;
2147 jpeg_read_image(file_name, img);
2148 jpeg_write_view(file_name, rotated180_view(view(img)));
2149}
2150\endcode
2151
2152It can be instantiated with either a compile-time or a runtime image because all functions it uses have overloads taking runtime constructs.
2153For example, here is how \p rotated180_view is implemented:
2154
2155\code
2156// implementation using templated view
2157template <typename View>
2158typename dynamic_xy_step_type<View>::type rotated180_view(const View& src) { ... }
2159
2160namespace detail {
2161 // the function, wrapped inside a function object
2162 template <typename Result> struct rotated180_view_fn {
2163 typedef Result result_type;
2164 template <typename View> result_type operator()(const View& src) const {
2165 return result_type(rotated180_view(src));
2166 }
2167 };
2168}
2169
2170// overloading of the function using variant. Takes and returns run-time bound view.
2171// The returned view has a dynamic step
2172template <typename ViewTypes> inline // Models MPL Random Access Container of models of ImageViewConcept
2173typename dynamic_xy_step_type<any_image_view<ViewTypes> >::type rotated180_view(const any_image_view<ViewTypes>& src) {
2174 return apply_operation(src,detail::rotated180_view_fn<typename dynamic_xy_step_type<any_image_view<ViewTypes> >::type>());
2175}
2176\endcode
2177
2178Variants should be used with caution (especially algorithms that take more than one variant) because they instantiate the algorithm
2179for every possible model that the variant can take. This can take a toll on compile time and executable size.
2180Despite these limitations, \p variant is a powerful technique that allows us to combine the speed of compile-time resolution with
2181the flexibility of run-time resolution. It allows us to treat images of different parameters uniformly as a collection and store
2182them in the same container.
2183
2184
2185<hr>
2186\section MetafunctionsDG 12. Useful Metafunctions and Typedefs
2187
2188Flexibility comes at a price. GIL types can be very long and hard to read.
2189To address this problem, GIL provides typedefs to refer to any standard image, pixel iterator, pixel locator, pixel reference or pixel value.
2190They follow this pattern:
2191<p>
2192\e ColorSpace + \e BitDepth + ["s|f"] + ["c"] + ["_planar"] + ["_step"] + \e ClassType + "_t"
2193<p>
2194Where \e ColorSpace also indicates the ordering of components. Examples are \p rgb, \p bgr, \p cmyk, \p rgba. \e BitDepth can be, for example,
2195 \p 8,\p 16,\p 32. By default the bits are unsigned integral type. Append \p s to the bit depth to indicate signed integral, or \p f to indicate
2196 floating point. \p c indicates object whose associated pixel reference is immutable. \p _planar indicates planar organization (as opposed to interleaved).
2197\p _step indicates the type has a dynamic step and \e ClassType is \p _image (image, using a standard allocator), \p _view (image view), \p _loc
2198(pixel locator), \p _ptr (pixel iterator), \p _ref (pixel reference), \p _pixel (pixel value). Here are examples:
2199
2200\code
2201bgr8_image_t i; // 8-bit unsigned (unsigned char) interleaved BGR image
2202cmyk16_pixel_t; x; // 16-bit unsigned (unsigned short) CMYK pixel value;
2203cmyk16sc_planar_ref_t p(x); // const reference to a 16-bit signed integral (signed short) planar CMYK pixel x.
2204rgb32f_planar_step_ptr_t ii; // step iterator to a floating point 32-bit (float) planar RGB pixel.
2205\endcode
2206
2207GIL provides the metafunctions that return the types of standard homogeneous memory-based GIL constructs given a channel type, a layout, and whether
2208the construct is planar, has a step along the X direction, and is mutable:
2209
2210\code
2211template <typename ChannelValue, typename Layout, bool IsPlanar=false, bool IsMutable=true>
2212struct pixel_reference_type { typedef ... type; };
2213
2214template <typename Channel, typename Layout>
2215struct pixel_value_type { typedef ... type; };
2216
2217template <typename ChannelValue, typename Layout, bool IsPlanar=false, bool IsStep=false, bool IsMutable=true>
2218struct iterator_type { typedef ... type; };
2219
2220template <typename ChannelValue, typename Layout, bool IsPlanar=false, bool IsXStep=false, bool IsMutable=true>
2221struct locator_type { typedef ... type; };
2222
2223template <typename ChannelValue, typename Layout, bool IsPlanar=false, bool IsXStep=false, bool IsMutable=true>
2224struct view_type { typedef ... type; };
2225
2226template <typename ChannelValue, typename Layout, bool IsPlanar=false, typename Alloc=std::allocator<unsigned char> >
2227struct image_type { typedef ... type; };
2228
2229template <typename BitField, typename ChannelBitSizeVector, typename Layout, typename Alloc=std::allocator<unsigned char> >
2230struct packed_image_type { typedef ... type; };
2231
2232template <typename ChannelBitSizeVector, typename Layout, typename Alloc=std::allocator<unsigned char> >
2233struct bit_aligned_image_type { typedef ... type; };
2234\endcode
2235
2236There are also helper metafunctions to construct packed and bit-aligned images with up to five channels:
2237
2238\code
2239template <typename BitField, unsigned Size1,
2240 typename Layout, typename Alloc=std::allocator<unsigned char> >
2241struct packed_image1_type { typedef ... type; };
2242
2243template <typename BitField, unsigned Size1, unsigned Size2,
2244 typename Layout, typename Alloc=std::allocator<unsigned char> >
2245struct packed_image2_type { typedef ... type; };
2246
2247template <typename BitField, unsigned Size1, unsigned Size2, unsigned Size3,
2248 typename Layout, typename Alloc=std::allocator<unsigned char> >
2249struct packed_image3_type { typedef ... type; };
2250
2251template <typename BitField, unsigned Size1, unsigned Size2, unsigned Size3, unsigned Size4,
2252 typename Layout, typename Alloc=std::allocator<unsigned char> >
2253struct packed_image4_type { typedef ... type; };
2254
2255template <typename BitField, unsigned Size1, unsigned Size2, unsigned Size3, unsigned Size4, unsigned Size5,
2256 typename Layout, typename Alloc=std::allocator<unsigned char> >
2257struct packed_image5_type { typedef ... type; };
2258
2259template <unsigned Size1,
2260 typename Layout, typename Alloc=std::allocator<unsigned char> >
2261struct bit_aligned_image1_type { typedef ... type; };
2262
2263template <unsigned Size1, unsigned Size2,
2264 typename Layout, typename Alloc=std::allocator<unsigned char> >
2265struct bit_aligned_image2_type { typedef ... type; };
2266
2267template <unsigned Size1, unsigned Size2, unsigned Size3,
2268 typename Layout, typename Alloc=std::allocator<unsigned char> >
2269struct bit_aligned_image3_type { typedef ... type; };
2270
2271template <unsigned Size1, unsigned Size2, unsigned Size3, unsigned Size4,
2272 typename Layout, typename Alloc=std::allocator<unsigned char> >
2273struct bit_aligned_image4_type { typedef ... type; };
2274
2275template <unsigned Size1, unsigned Size2, unsigned Size3, unsigned Size4, unsigned Size5,
2276 typename Layout, typename Alloc=std::allocator<unsigned char> >
2277struct bit_aligned_image5_type { typedef ... type; };
2278
2279\endcode
2280
2281Here \p ChannelValue models \p ChannelValueConcept. We don't need \p IsYStep because GIL's memory-based locator and
2282view already allow the vertical step to be specified dynamically. Iterators and views can be constructed from a pixel type:
2283
2284\code
2285template <typename Pixel, bool IsPlanar=false, bool IsStep=false, bool IsMutable=true>
2286struct iterator_type_from_pixel { typedef ... type; };
2287
2288template <typename Pixel, bool IsPlanar=false, bool IsStepX=false, bool IsMutable=true>
2289struct view_type_from_pixel { typedef ... type; };
2290\endcode
2291
2292Using a heterogeneous pixel type will result in heterogeneous iterators and views. Types can also be constructed from horizontal iterator:
2293
2294\code
2295template <typename XIterator>
2296struct type_from_x_iterator {
2297 typedef ... step_iterator_t;
2298 typedef ... xy_locator_t;
2299 typedef ... view_t;
2300};
2301\endcode
2302
2303There are metafunctions to construct the type of a construct from an existing type by changing one or more of its properties:
2304
2305\code
2306template <typename PixelReference,
2307 typename ChannelValue, typename Layout, typename IsPlanar, typename IsMutable>
2308struct derived_pixel_reference_type {
2309 typedef ... type; // Models PixelConcept
2310};
2311
2312template <typename Iterator,
2313 typename ChannelValue, typename Layout, typename IsPlanar, typename IsStep, typename IsMutable>
2314struct derived_iterator_type {
2315 typedef ... type; // Models PixelIteratorConcept
2316};
2317
2318template <typename View,
2319 typename ChannelValue, typename Layout, typename IsPlanar, typename IsXStep, typename IsMutable>
2320struct derived_view_type {
2321 typedef ... type; // Models ImageViewConcept
2322};
2323
2324template <typename Image,
2325 typename ChannelValue, typename Layout, typename IsPlanar>
2326struct derived_image_type {
2327 typedef ... type; // Models ImageConcept
2328};
2329\endcode
2330
2331You can replace one or more of its properties and use \p boost::use_default for the rest. In this case \p IsPlanar, \p IsStep and \p IsMutable
2332are MPL boolean constants. For example, here is how to create the type of a view just like \p View, but being grayscale and planar:
2333
2334\code
2335typedef typename derived_view_type<View, boost::use_default, gray_t, mpl::true_>::type VT;
2336\endcode
2337
2338You can get pixel-related types of any pixel-based GIL constructs (pixels, iterators, locators and views) using the following
2339metafunctions provided by PixelBasedConcept, HomogeneousPixelBasedConcept and metafunctions built on top of them:
2340
2341\code
2342template <typename T> struct color_space_type { typedef ... type; };
2343template <typename T> struct channel_mapping_type { typedef ... type; };
2344template <typename T> struct is_planar { typedef ... type; };
2345
2346// Defined by homogeneous constructs
2347template <typename T> struct channel_type { typedef ... type; };
2348template <typename T> struct num_channels { typedef ... type; };
2349\endcode
2350
2351These are metafunctions, some of which return integral types which can be evaluated like this:
2352
2353\code
2354BOOST_STATIC_ASSERT(is_planar<rgb8_planar_view_t>::value == true);
2355\endcode
2356
2357\endcode
2358
2359GIL also supports type analysis metafunctions of the form:
2360[pixel_reference/iterator/locator/view/image] + \p "_is_" + [basic/mutable/step]. For example:
2361
2362\code
2363if (view_is_mutable<View>::value) {
2364 ...
2365}
2366\endcode
2367
2368A <i>basic</i> GIL construct is a memory-based construct that uses the built-in GIL classes and does not have any function object to invoke upon dereferencing.
2369For example, a simple planar or interleaved, step or non-step RGB image view is basic, but a color converted view or a virtual view is not.
2370
2371<hr>
2372\section IO_DG 13. I/O Extension
2373
2374GIL's I/O extension provides low level image i/o utilities. It supports loading and saving several image formats, each of which requires linking
2375against the corresponding library:
2376
2377- <b>JPEG</b>: To use JPEG files, include the file <tt>gil/extension/io/jpeg_io.hpp</tt>. If you are using run-time images,
2378you need to include <tt>gil/extension/io/jpeg_dynamic_io.hpp</tt> instead. You need to compile and link against libjpeg.lib
2379(available at http://www.ijg.org). You need to have <tt>jpeglib.h</tt> in your include path.
2380
2381- <b>TIFF</b>: To use TIFF files, include the file <tt>gil/extension/io/tiff_io.hpp</tt>. If you are using run-time images,
2382you need to include <tt>gil/extension/io/tiff_dynamic_io.hpp</tt> instead. You need to compile and link against libtiff.lib
2383(available at http://www.libtiff.org). You need to have <tt>tiffio.h</tt> in your include path.
2384
2385- <b>PNG</b>: To use PNG files, include the file <tt>gil/extension/io/png_io.hpp</tt>. If you are using run-time images,
2386you need to include <tt>gil/extension/io/png_dynamic_io.hpp</tt> instead. You need to compile and link against libpng.lib
2387(available at http://wwwlibpng.org). You need to have <tt>png.h</tt> in your include path.
2388
2389You don't need to install all these libraries; just the ones you will use.
2390Here are the I/O APIs for JPEG files (replace \p "jpeg" with \p "tiff" or \p "png" for the APIs of the other libraries):
2391
2392\code
2393// Returns the width and height of the JPEG file at the specified location.
2394// Throws std::ios_base::failure if the location does not correspond to a valid JPEG file
2395point2<std::ptrdiff_t> jpeg_read_dimensions(const char*);
2396
2397// Allocates a new image whose dimensions are determined by the given jpeg image file, and loads the pixels into it.
2398// Triggers a compile assert if the image color space or channel depth are not supported by the JPEG library or by the I/O extension.
2399// Throws std::ios_base::failure if the file is not a valid JPEG file, or if its color space or channel depth are not
2400// compatible with the ones specified by Image
2401template <typename Img> void jpeg_read_image(const char*, Img&);
2402
2403// Allocates a new image whose dimensions are determined by the given jpeg image file, and loads the pixels into it,
2404// color-converting and channel-converting if necessary.
2405// Triggers a compile assert if the image color space or channel depth are not supported by the JPEG library or by the I/O extension.
2406// Throws std::ios_base::failure if the file is not a valid JPEG file or if it fails to read it.
2407template <typename Img> void jpeg_read_and_convert_image(const char*, Img&);
2408template <typename Img, typename CCV> void jpeg_read_and_convert_image(const char*, Img&, CCV color_converter);
2409
2410// Loads the image specified by the given jpeg image file name into the given view.
2411// Triggers a compile assert if the view color space and channel depth are not supported by the JPEG library or by the I/O extension.
2412// Throws std::ios_base::failure if the file is not a valid JPEG file, or if its color space or channel depth are not
2413// compatible with the ones specified by View, or if its dimensions don't match the ones of the view.
2414template <typename View> void jpeg_read_view(const char*, const View&);
2415
2416// Loads the image specified by the given jpeg image file name into the given view and color-converts (and channel-converts) it if necessary.
2417// Triggers a compile assert if the view color space and channel depth are not supported by the JPEG library or by the I/O extension.
2418// Throws std::ios_base::failure if the file is not a valid JPEG file, or if its dimensions don't match the ones of the view.
2419template <typename View> void jpeg_read_and_convert_view(const char*, const View&);
2420template <typename View, typename CCV> void jpeg_read_and_convert_view(const char*, const View&, CCV color_converter);
2421
2422// Saves the view to a jpeg file specified by the given jpeg image file name.
2423// Triggers a compile assert if the view color space and channel depth are not supported by the JPEG library or by the I/O extension.
2424// Throws std::ios_base::failure if it fails to create the file.
2425template <typename View> void jpeg_write_view(const char*, const View&);
2426
2427// Determines whether the given view type is supported for reading
2428template <typename View> struct jpeg_read_support {
2429 static const bool value = ...;
2430};
2431
2432// Determines whether the given view type is supported for writing
2433template <typename View> struct jpeg_write_support {
2434 static const bool value = ...;
2435};
2436\endcode
2437
2438If you use the dynamic image extension, make sure to include \p "jpeg_dynamic_io.hpp" instead of \p "jpeg_io.hpp".
2439In addition to the above methods, you have the following overloads dealing with dynamic images:
2440
2441\code
2442// Opens the given JPEG file name, selects the first type in Images whose color space and channel are compatible to those of the image file
2443// and creates a new image of that type with the dimensions specified by the image file.
2444// Throws std::ios_base::failure if none of the types in Images are compatible with the type on disk.
2445template <typename Images> void jpeg_read_image(const char*, any_image<Images>&);
2446
2447// Saves the currently instantiated view to a jpeg file specified by the given jpeg image file name.
2448// Throws std::ios_base::failure if the currently instantiated view type is not supported for writing by the I/O extension
2449// or if it fails to create the file.
2450template <typename Views> void jpeg_write_view(const char*, any_image_view<Views>&);
2451\endcode
2452
2453All of the above methods have overloads taking \p std::string instead of <tt>const char*</tt>
2454
2455<hr>
2456\section SampleImgCodeDG 14. Sample Code
2457
2458\subsection PixelLevelExampleDG Pixel-level Sample Code
2459
2460Here are some operations you can do with pixel values, pointers and references:
2461
2462\code
2463rgb8_pixel_t p1(255,0,0); // make a red RGB pixel
2464bgr8_pixel_t p2 = p1; // RGB and BGR are compatible and the channels will be properly mapped.
2465assert(p1==p2); // p2 will also be red.
2466assert(p2[0]!=p1[0]); // operator[] gives physical channel order (as laid down in memory)
2467assert(semantic_at_c<0>(p1)==semantic_at_c<0>(p2)); // this is how to compare the two red channels
2468get_color(p1,green_t()) = get_color(p2,blue_t()); // channels can also be accessed by name
2469
2470const unsigned char* r;
2471const unsigned char* g;
2472const unsigned char* b;
2473rgb8c_planar_ptr_t ptr(r,g,b); // constructing const planar pointer from const pointers to each plane
2474
2475rgb8c_planar_ref_t ref=*ptr; // just like built-in reference, dereferencing a planar pointer returns a planar reference
2476
2477p2=ref; p2=p1; p2=ptr[7]; p2=rgb8_pixel_t(1,2,3); // planar/interleaved references and values to RGB/BGR can be freely mixed
2478
2479//rgb8_planar_ref_t ref2; // compile error: References have no default constructors
2480//ref2=*ptr; // compile error: Cannot construct non-const reference by dereferencing const pointer
2481//ptr[3]=p1; // compile error: Cannot set the fourth pixel through a const pointer
2482//p1 = pixel<float, rgb_layout_t>();// compile error: Incompatible channel depth
2483//p1 = pixel<bits8, rgb_layout_t>();// compile error: Incompatible color space (even though it has the same number of channels)
2484//p1 = pixel<bits8,rgba_layout_t>();// compile error: Incompatible color space (even though it contains red, green and blue channels)
2485\endcode
2486
2487Here is how to use pixels in generic code:
2488
2489\code
2490template <typename GrayPixel, typename RGBPixel>
2491void gray_to_rgb(const GrayPixel& src, RGBPixel& dst) {
2492 gil_function_requires<PixelConcept<GrayPixel> >();
2493 gil_function_requires<MutableHomogeneousPixelConcept<RGBPixel> >();
2494
2495 typedef typename color_space_type<GrayPixel>::type gray_cs_t;
2496 BOOST_STATIC_ASSERT((boost::is_same<gray_cs_t,gray_t>::value));
2497
2498 typedef typename color_space_type<RGBPixel>::type rgb_cs_t;
2499 BOOST_STATIC_ASSERT((boost::is_same<rgb_cs_t,rgb_t>::value));
2500
2501 typedef typename channel_type<GrayPixel>::type gray_channel_t;
2502 typedef typename channel_type<RGBPixel>::type rgb_channel_t;
2503
2504 gray_channel_t gray = get_color(src,gray_color_t());
2505 static_fill(dst, channel_convert<rgb_channel_t>(gray));
2506}
2507
2508// example use patterns:
2509
2510// converting gray l-value to RGB and storing at (5,5) in a 16-bit BGR interleaved image:
2511bgr16_view_t b16(...);
2512gray_to_rgb(gray8_pixel_t(33), b16(5,5));
2513
2514// storing the first pixel of an 8-bit grayscale image as the 5-th pixel of 32-bit planar RGB image:
2515rgb32f_planar_view_t rpv32;
2516gray8_view_t gv8(...);
2517gray_to_rgb(*gv8.begin(), rpv32[5]);
2518\endcode
2519
2520As the example shows, both the source and the destination can be references or values, planar or interleaved, as long as they model \p PixelConcept
2521and \p MutablePixelConcept respectively.
2522
2523
2524\subsection SafeAreaExampleDG Creating a Copy of an Image with a Safe Buffer
2525
2526Suppose we want to convolve an image with multiple kernels, the largest of which is 2K+1 x 2K+1 pixels. It may be worth
2527creating a margin of K pixels around the image borders. Here is how to do it:
2528
2529\code
2530template <typename SrcView, // Models ImageViewConcept (the source view)
2531 typename DstImage> // Models ImageConcept (the returned image)
2532void create_with_margin(const SrcView& src, int k, DstImage& result) {
2533 gil_function_requires<ImageViewConcept<SrcView> >();
2534 gil_function_requires<ImageConcept<DstImage> >();
2535 gil_function_requires<ViewsCompatibleConcept<SrcView, typename DstImage::view_t> >();
2536
2537 result=DstImage(src.width()+2*k, src.height()+2*k);
2538 typename DstImage::view_t centerImg=subimage_view(view(result), k,k,src.width(),src.height());
2539 std::copy(src.begin(), src.end(), centerImg.begin());
2540}
2541\endcode
2542
2543We allocated a larger image, then we used \p subimage_view to create a shallow image of
2544its center area of top left corner at (k,k) and of identical size as \p src, and finally we copied \p src into that center image. If the margin
2545needs initialization, we could have done it with \p fill_pixels. Here is how to simplify this code using
2546the \p copy_pixels algorithm:
2547
2548\code
2549template <typename SrcView, typename DstImage>
2550void create_with_margin(const SrcView& src, int k, DstImage& result) {
2551 result.recreate(src.width()+2*k, src.height()+2*k);
2552 copy_pixels(src, subimage_view(view(result), k,k,src.width(),src.height()));
2553}
2554\endcode
2555
2556(Note also that \p image::recreate is more efficient than \p operator=, as the latter will do an unnecessary copy construction).
2557Not only does the above example work for planar and interleaved images of any color space and pixel depth; it is also optimized.
2558GIL overrides \p std::copy - when called on two identical interleaved images with no padding at the end of rows, it
2559simply does a \p memmove. For planar images it does \p memmove for each channel. If one of the images has padding, (as in
2560our case) it will try to do \p memmove for each row. When an image has no padding, it will use its lightweight
2561horizontal iterator (as opposed to the more complex 1D image iterator that has to check for the end of rows).
2562It choses the fastest method, taking into account both static and run-time parameters.
2563
2564\subsection HistogramExampleDG Histogram
2565
2566The histogram can be computed by counting the number of pixel values that fall in each bin.
2567The following method takes a grayscale (one-dimensional) image view, since only grayscale pixels
2568are convertible to integers:
2569\code
2570template <typename GrayView, typename R>
2571void grayimage_histogram(const GrayView& img, R& hist) {
2572 for (typename GrayView::iterator it=img.begin(); it!=img.end(); ++it)
2573 ++hist[*it];
2574}
2575\endcode
2576
2577Using \p boost::lambda and GIL's \p for_each_pixel algorithm, we can write this more compactly:
2578
2579\code
2580template <typename GrayView, typename R>
2581void grayimage_histogram(const GrayView& v, R& hist) {
2582 for_each_pixel(v, ++var(hist)[_1]);
2583}
2584\endcode
2585
2586Where \p for_each_pixel invokes \p std::for_each and \p var and \p _1 are \p boost::lambda constructs.
2587To compute the luminosity histogram, we call the above method using the grayscale view of an image:
2588
2589\code
2590template <typename View, typename R>
2591void luminosity_histogram(const View& v, R& hist) {
2592 grayimage_histogram(color_converted_view<gray8_pixel_t>(v),hist);
2593}
2594\endcode
2595
2596This is how to invoke it:
2597
2598\code
2599unsigned char hist[256];
2600std::fill(hist,hist+256,0);
2601luminosity_histogram(my_view,hist);
2602\endcode
2603
2604If we want to view the histogram of the second channel of the image in the top left 100x100 area, we call:
2605
2606\code
2607grayimage_histogram(nth_channel_view(subimage_view(img,0,0,100,100),1),hist);
2608\endcode
2609
2610No pixels are copied and no extra memory is allocated - the code operates directly on the source pixels, which could
2611be in any supported color space and channel depth. They could be either planar or interleaved.
2612
2613\subsection ImageViewsExampleDG Using Image Views
2614
2615The following code illustrates the power of using image views:
2616
2617\code
2618jpeg_read_image("monkey.jpg", img);
2619step1=view(img);
2620step2=subimage_view(step1, 200,300, 150,150);
2621step3=color_converted_view<rgb8_view_t,gray8_pixel_t>(step2);
2622step4=rotated180_view(step3);
2623step5=subsampled_view(step4, 2,1);
2624jpeg_write_view("monkey_transform.jpg", step5);
2625\endcode
2626
2627The intermediate images are shown here:
2628\image html monkey_steps.jpg
2629
2630Notice that no pixels are ever copied. All the work is done inside \p jpeg_write_view.
2631If we call our \p luminosity_histogram with \p step5 it will do the right thing.
2632
2633
2634<hr>
2635\section ExtendingGIL_DG 15. Extending the Generic Image Library
2636
2637You can define your own pixel iterators, locators, image views, images, channel types, color spaces and algorithms.
2638You can make virtual images that live on the disk, inside a jpeg file, somewhere on the internet, or even fully-synthetic images
2639such as the Mandelbrot set.
2640As long as they properly model the corresponding concepts, they will work with any existing GIL code.
2641Most such extensions require no changes to the library and can thus be
2642supplied in another module.
2643
2644\subsection NewColorSpacesDG Defining New Color Spaces
2645
2646Each color space is in a separate file. To add a new color space, just copy one of the existing ones (like rgb.hpp) and change it
2647accordingly. If you want color conversion support, you will have to provide methods to convert between it and the existing color spaces
2648(see color_convert.h). For convenience you may want to provide useful typedefs for pixels, pointers, references and images with the new
2649color space (see typedefs.h).
2650
2651\subsection NewChannelsDG Defining New Channel Types
2652
2653Most of the time you don't need to do anything special to use a new channel type. You can just use it:
2654
2655\code
2656typedef pixel<double,rgb_layout_t> rgb64_pixel_t; // 64 bit RGB pixel
2657typedef rgb64_pixel* rgb64_pixel_ptr_t;// pointer to 64-bit interleaved data
2658typedef image_type<double,rgb_layout_t>::type rgb64_image_t; // 64-bit interleaved image
2659\endcode
2660
2661If you want to use your own channel class, you will need to provide a specialization of \p channel_traits for it (see channel.hpp).
2662If you want to do conversion between your and existing channel types, you will need to provide an overload of \p channel_convert.
2663
2664\subsection NewColorConversionDG Overloading Color Conversion
2665
2666Suppose you want to provide your own color conversion. For example, you may want to implement higher quality color conversion using color profiles.
2667Typically you may want to redefine color conversion only in some instances and default to GIL's color conversion in all other cases. Here is, for
2668example, how to overload color conversion so that color conversion to gray inverts the result but everything else remains the same:
2669
2670\code
2671// make the default use GIL's default
2672template <typename SrcColorSpace, typename DstColorSpace>
2673struct my_color_converter_impl
2674 : public default_color_converter_impl<SrcColorSpace,DstColorSpace> {};
2675
2676// provide specializations only for cases you care about
2677// (in this case, if the destination is grayscale, invert it)
2678template <typename SrcColorSpace>
2679struct my_color_converter_impl<SrcColorSpace,gray_t> {
2680 template <typename SrcP, typename DstP> // Model PixelConcept
2681 void operator()(const SrcP& src, DstP& dst) const {
2682 default_color_converter_impl<SrcColorSpace,gray_t>()(src,dst);
2683 get_color(dst,gray_color_t())=channel_invert(get_color(dst,gray_color_t()));
2684 }
2685};
2686
2687// create a color converter object that dispatches to your own implementation
2688struct my_color_converter {
2689 template <typename SrcP, typename DstP> // Model PixelConcept
2690 void operator()(const SrcP& src,DstP& dst) const {
2691 typedef typename color_space_type<SrcP>::type SrcColorSpace;
2692 typedef typename color_space_type<DstP>::type DstColorSpace;
2693 my_color_converter_impl<SrcColorSpace,DstColorSpace>()(src,dst);
2694 }
2695};
2696\endcode
2697
2698GIL's color conversion functions take the color converter as an optional parameter. You can pass your own color converter:
2699
2700\code
2701color_converted_view<gray8_pixel_t>(img_view,my_color_converter());
2702\endcode
2703
2704\subsection NewImagesDG Defining New Image Views
2705
2706<p> You can provide your own pixel iterators, locators and views, overriding either the mechanism for getting from one pixel to the next or doing an arbitrary
2707pixel transformation on dereference. For example, let's look at the implementation of \p color_converted_view (an image factory method that,
2708given any image view, returns a new, otherwise identical view, except that color conversion is performed on pixel access).
2709First we need to define a model of \p PixelDereferenceAdaptorConcept; a function object that will be called when we dereference a pixel iterator.
2710It will call \p color_convert to convert to the destination pixel type:
2711
2712\code
2713template <typename SrcConstRefP, // const reference to the source pixel
2714 typename DstP> // Destination pixel value (models PixelValueConcept)
2715class color_convert_deref_fn {
2716public:
2717 typedef color_convert_deref_fn const_t;
2718 typedef DstP value_type;
2719 typedef value_type reference; // read-only dereferencing
2720 typedef const value_type& const_reference;
2721 typedef SrcConstRefP argument_type;
2722 typedef reference result_type;
2723 BOOST_STATIC_CONSTANT(bool, is_mutable=false);
2724
2725 result_type operator()(argument_type srcP) const {
2726 result_type dstP;
2727 color_convert(srcP,dstP);
2728 return dstP;
2729 }
2730};
2731
2732\endcode
2733
2734We then use the \p add_deref member struct of image views to construct the type of a view that invokes a given function object (\p deref_t) upon
2735dereferencing. In our case, it performs color conversion:
2736
2737\code
2738template <typename SrcView, typename DstP>
2739struct color_converted_view_type {
2740private:
2741 typedef typename SrcView::const_t::reference src_pix_ref; // const reference to pixel in SrcView
2742 typedef color_convert_deref_fn<src_pix_ref, DstP> deref_t; // the dereference adaptor that performs color conversion
2743 typedef typename SrcView::template add_deref<deref_t> add_ref_t;
2744public:
2745 typedef typename add_ref_t::type type; // the color converted view type
2746 static type make(const SrcView& sv) { return add_ref_t::make(sv, deref_t()); }
2747};
2748\endcode
2749
2750Finally our \p color_converted_view code simply creates color-converted view from the source view:
2751
2752\code
2753template <typename DstP, typename View> inline
2754typename color_converted_view_type<View,DstP>::type color_convert_view(const View& src) {
2755 return color_converted_view_type<View,DstP>::make(src);
2756}
2757\endcode
2758
2759(The actual color convert view transformation is slightly more complicated, as it takes an optional color conversion object, which
2760allows users to specify their own color conversion methods).
2761See the GIL tutorial for an example of creating a virtual image view that defines the Mandelbrot set.
2762
2763<hr>
2764\section TechnicalitiesDG 16. Technicalities
2765
2766\subsection CreatingReferenceProxyDG Creating a reference proxy
2767
2768Sometimes it is necessary to create a proxy class that represents a reference to a given object. Examples of these are GIL's reference
2769to a planar pixel (\p planar_pixel_reference) and GIL's subbyte channel references. Writing a reference proxy class can be tricky. One
2770problem is that the proxy reference is constructed as a temporary object and returned by value upon dereferencing the iterator:
2771
2772\code
2773struct rgb_planar_pixel_iterator {
2774 typedef my_reference_proxy<T> reference;
2775 reference operator*() const { return reference(red,green,blue); }
2776};
2777\endcode
2778
2779The problem arises when an iterator is dereferenced directly into a function that takes a mutable pixel:
2780
2781\code
2782template <typename Pixel> // Models MutablePixelConcept
2783void invert_pixel(Pixel& p);
2784
2785rgb_planar_pixel_iterator myIt;
2786invert_pixel(*myIt); // compile error!
2787\endcode
2788
2789C++ does not allow for matching a temporary object against a non-constant reference. The solution is to:
2790- Use const qualifier on all members of the reference proxy object:
2791
2792\code
2793template <typename T>
2794struct my_reference_proxy {
2795 const my_reference_proxy& operator=(const my_reference_proxy& p) const;
2796 const my_reference_proxy* operator->() const { return this; }
2797 ...
2798};
2799\endcode
2800
2801- Use different classes to denote mutable and constant reference (maybe based on the constness of the template parameter)
2802
2803- Define the reference type of your iterator with const qualifier:
2804
2805\code
2806struct iterator_traits<rgb_planar_pixel_iterator> {
2807 typedef const my_reference_proxy<T> reference;
2808};
2809\endcode
2810
2811A second important issue is providing an overload for \p swap for your reference class. The default \p std::swap will not
2812work correctly. You must use a real value type as the temporary.
2813A further complication is that in some implementations of the STL the \p swap function is incorreclty called qualified, as \p std::swap.
2814The only way for these STL algorithms to use your overload is if you define it in the \p std namespace:
2815\code
2816namespace std {
2817 template <typename T>
2818 void swap(my_reference_proxy<T>& x, my_reference_proxy<T>& y) {
2819 my_value<T> tmp=x;
2820 x=y;
2821 y=tmp;
2822 }
2823}
2824\endcode
2825
2826Lastly, remember that constructors and copy-constructors of proxy references are always shallow and assignment operators are deep.
2827
2828We are grateful to Dave Abrahams, Sean Parent and Alex Stepanov for suggesting the above solution.
2829
2830<hr>
2831\section ConclusionDG 17. Conclusion
2832
2833<p>The Generic Image Library is designed with the following five goals in mind:
2834
2835\li <b> Generality.</b> Abstracts image representations from algorithms on images. It allows for writing code once and have it work for any image type.
2836\li <b> Performance.</b> Speed has been instrumental to the design of the library. The generic algorithms provided in the library are in many cases comparable in
2837 speed to hand-coding the algorithm for a specific image type.
2838\li <b> Flexibility.</b> Compile-type parameter resolution results in faster code, but severely limits code flexibility. The library allows for any
2839 image parameter to be specified at run time, at a minor performance cost.
2840\li <b> Extensibility.</b> Virtually every construct in GIL can be extended - new channel types, color spaces, layouts, iterators, locators, image views and images
2841 can be provided by modeling the corresponding GIL concepts.
2842\li <b> Compatibility.</b> The library is designed as an STL complement. Generic STL algorithms can be used for pixel manipulation, and they
2843 are specifically targeted for optimization. The library works with existing raw pixel data from another image library.
2844
2845<div id="footerrow"><!--give footer 25px of white above--></div><div id="footer" title="footer: links to copyright and other legal information"><p><a href="licenses.html" class="el">Copyright &copy; 2005 Adobe Systems Incorporated</a></p><ul id="list1"><!-- due to a rendering error in IE, these links should all be on one line without returns --><li id="terms"><a title="Terms of Use" href="http://www.adobe.com/misc/copyright.html">Terms of Use</a></li><li><a title="Privacy Policy" href="http://www.adobe.com/misc/privacy.html">Privacy Policy</a></li><li><a href="http://access.adobe.com">Accessibility</a></li><li><a title="Avoid software piracy" href="http://www.adobe.com/aboutadobe/antipiracy/main.html">Avoid software piracy</a></li><li id="tms"><a title="Permissions and trademarks" href="http://www.adobe.com/misc/agreement.html">Permissions and trademarks</a></li><li><a title="Product License Agreements" href="http://www.adobe.com/products/eulas/main.html">Product License Agreements</a></li></ul></div>
2846
2847*/
2848