1 ////////////////////////////////////////////////////////////////////////////////////////
3 /// \brief Doxygen documentation
4 /// \author Lubomir Bourdev and Hailin Jin \n
5 /// Adobe Systems Incorporated
8 ////////////////////////////////////////////////////////////////////////////////////////
11 \page GILDesignGuide Generic Image Library Design Guide
13 \author Lubomir Bourdev (lbourdev@adobe.com) and Hailin Jin (hljin@adobe.com) \n
14 Adobe Systems Incorporated
16 \date September 15, 2007
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.
20 It 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
22 - \ref OverviewSectionDG
23 - \ref ConceptsSectionDG
25 - \ref ChannelSectionDG
26 - \ref ColorSpaceSectionDG
27 - \ref ColorBaseSectionDG
29 - \ref PixelIteratorSectionDG
30 - \ref FundamentalIteratorDG
31 - \ref IteratorAdaptorDG
32 - \ref PixelDereferenceAdaptorAG
35 - \ref IteratorFrom2DDG
36 - \ref ImageViewSectionDG
37 - \ref ImageViewFrowRawDG
38 - \ref ImageViewFrowImageViewDG
41 - \ref MetafunctionsDG
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
53 - \ref TechnicalitiesDG
58 \section OverviewSectionDG 1. Overview
60 Images are essential in any image processing, vision and video project, and yet the variability in image representations makes it difficult
61 to 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.
63 In 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.
65 There are two common memory structures for an image. <i>Interleaved</i> images are represented by grouping the pixels together in memory and
66 interleaving all channels together, whereas <i>planar</i> images keep the channels in separate color planes. Here is a 4x3 RGB image in
67 which the second pixel of the first row is marked in red, in interleaved form:
69 \image html interleaved.jpg
72 \image html planar.jpg
74 Note also that rows may optionally be aligned resulting in a potential padding at the end of rows.
76 The 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.)
83 It also supports user-defined models of images, and images whose parameters are specified at run-time.
84 GIL abstracts image representation from algorithms applied on images and allows us to write the algorithm once and have it work
85 on 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.
87 This document follows bottom-up design. Each section defines concepts that build on top of concepts defined in previous sections.
88 It is recommended to read the sections in order.
91 \section ConceptsSectionDG 2. About Concepts
93 All 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
94 be used correctly in generic algorithms. The requirements include syntactic and algorithming guarantees.
95 For 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
96 it satisfies the requirements of \p PixelConcept, all other GIL classes and algorithms can be used with it. See more about concepts here:
97 http://www.generic-programming.org/languages/conceptcpp/
99 In 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:
100 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2081.pdf
102 Here are some common concepts that will be used in GIL. Most of them are defined here:
103 http://www.generic-programming.org/languages/conceptcpp/concept_web.php
106 auto concept DefaultConstructible<typename T> {
110 auto concept CopyConstructible<typename T> {
115 auto concept Assignable<typename T, typename U = T> {
116 typename result_type;
117 result_type operator=(T&, U);
120 auto concept EqualityComparable<typename T, typename U = T> {
121 bool operator==(T x, T y);
122 bool operator!=(T x, T y) { return !(x==y); }
125 concept SameType<typename T, typename U> { /* unspecified */ };
126 template<typename T> concept_map SameType<T, T> { /* unspecified */ };
128 auto concept Swappable<typename T> {
129 void swap(T& t, T& u);
133 Here are some additional basic concepts that GIL needs:
137 auto concept Regular<typename T> : DefaultConstructible<T>, CopyConstructible<T>, EqualityComparable<T>, Assignable<T>, Swappable<T> {};
139 auto concept Metafunction<typename T> {
161 \section PointSectionDG 3. Point
163 A point defines the location of a pixel inside an image. It can also be used to describe the dimensions of an image.
164 In most general terms, points are N-dimensional and model the following concept:
167 concept PointNDConcept<typename T> : Regular<T> {
168 // the type of a coordinate along each axis
169 template <size_t K> struct axis; where Metafunction<axis>;
171 const size_t num_dimensions;
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();
179 GIL uses a two-dimensional point, which is a refinement of \p PointNDConcept in which both dimensions are of the same type:
182 concept Point2DConcept<typename T> : PointNDConcept<T> {
183 where num_dimensions == 2;
184 where SameType<axis<0>::type, axis<1>::type>;
186 typename value_type = axis<0>::type;
188 const value_type& operator[](const T&, size_t i);
189 value_type& operator[]( T&, size_t i);
195 <b>Related Concepts:</b>
202 GIL provides a model of \p Point2DConcept, \p point2<T> where \p T is the coordinate type.
224 \section ChannelSectionDG 4. Channel
226 A channel indicates the intensity of a color component (for example, the red channel in an RGB pixel).
227 Typical channel operations are getting, comparing and setting the channel values. Channels have associated
228 minimum and maximum value. GIL channels model the following concept:
232 concept 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
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
245 concept MutableChannelConcept<ChannelConcept T> : Swappable<T>, Assignable<T> {};
247 concept ChannelValueConcept<ChannelConcept T> : Regular<T> {};
250 GIL allows built-in integral and floating point types to be channels. Therefore the associated types and range information
251 are defined in \p channel_traits with the following default implementation:
254 template <typename T>
255 struct channel_traits {
256 typedef T value_type;
257 typedef T& reference;
259 typedef T& const const_reference;
260 typedef T* const const_pointer;
262 static value_type min_value() { return std::numeric_limits<T>::min(); }
263 static value_type max_value() { return std::numeric_limits<T>::max(); }
267 Two channel types are <i>compatible</i> if they have the same value type:
270 concept ChannelsCompatibleConcept<ChannelConcept T1, ChannelConcept T2> {
271 where SameType<T1::value_type, T2::value_type>;
275 A channel may be <i>convertible</i> to another channel:
278 template <ChannelConcept Src, ChannelValueConcept Dst>
279 concept ChannelConvertibleConcept {
280 Dst channel_convert(Src);
284 Note that \p ChannelConcept and \p MutableChannelConcept do not require a default constructor. Channels that also
285 support default construction (and thus are regular types) model \p ChannelValueConcept. To understand the motivation
286 for this distinction, consider a 16-bit RGB pixel in a "565" bit pattern. Its channels correspond to bit ranges. To support
287 such channels, we need to create a custom proxy class corresponding to a reference to a subbyte channel.
288 Such a proxy reference class models only \p ChannelConcept, because, similar to native C++ references, it
289 may not have a default constructor.
291 Note also that algorithms may impose additional requirements on channels, such as support for arithmentic operations.
293 <b>Related Concepts:</b>
296 - ChannelValueConcept\<T>
297 - MutableChannelConcept\<T>
298 - ChannelsCompatibleConcept\<T1,T2>
299 - ChannelConvertibleConcept\<SrcChannel,DstChannel>
303 All built-in integral and floating point types are valid channels. GIL provides standard typedefs for some integral channels:
306 typedef boost::uint8_t bits8;
307 typedef boost::uint16_t bits16;
308 typedef boost::uint32_t bits32;
309 typedef boost::int8_t bits8s;
310 typedef boost::int16_t bits16s;
311 typedef boost::int32_t bits32s;
314 The 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,
315 as specified by its \p std::numeric_limits. Sometimes the physical range is not appropriate. GIL provides \p scoped_channel_value, a model for a
316 channel adapter that allows for specifying a custom range. We use it to define a [0..1] floating point channel type as follows:
319 struct float_zero { static float apply() { return 0.0f; } };
320 struct float_one { static float apply() { return 1.0f; } };
321 typedef scoped_channel_value<float,float_zero,float_one> bits32f;
324 GIL also provides models for channels corresponding to ranges of bits:
327 // Value of a channel defined over NumBits bits. Models ChannelValueConcept
328 template <int NumBits> class packed_channel_value;
330 // Reference to a channel defined over NumBits bits. Models ChannelConcept
331 template <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
334 class packed_channel_reference;
336 // Reference to a channel defined over NumBits bits. Its FirstBit is a run-time parameter. Models ChannelConcept
337 template <int NumBits, // Defines the sequence of bits in the data value that contain the channel
338 bool Mutable> // true if the reference is mutable
339 class packed_dynamic_channel_reference;
342 Note that there are two models of a reference proxy which differ based on whether the offset of the channel range is
343 specified as a template or a run-time parameter. The first model is faster and more compact while the second model is more
344 flexible. For example, the second model allows us to construct an iterator over bitrange channels.
348 Here is how to construct the three channels of a 16-bit "565" pixel and set them to their maximum value:
351 typedef packed_channel_reference<0,5,true> channel16_0_5_reference_t;
352 typedef packed_channel_reference<5,6,true> channel16_5_6_reference_t;
353 typedef packed_channel_reference<11,5,true> channel16_11_5_reference_t;
355 boost::uint16_t data=0;
356 channel16_0_5_reference_t channel1(&data);
357 channel16_5_6_reference_t channel2(&data);
358 channel16_11_5_reference_t channel3(&data);
360 channel1=channel_traits<channel16_0_5_reference_t>::max_value();
361 channel2=channel_traits<channel16_5_6_reference_t>::max_value();
362 channel3=channel_traits<channel16_11_5_reference_t>::max_value();
366 Assignment, equality comparison and copy construction are defined only between compatible channels:
369 packed_channel_value<5> channel_6bit = channel1;
370 channel_6bit = channel3;
372 //channel_6bit = channel2; // compile error: Assignment between incompatible channels.
375 All channel models provided by GIL are pairwise convertible:
378 channel1 = channel_traits<channel16_0_5_reference_t>::max_value();
379 assert(channel1 == 31);
381 bits16 chan16 = channel_convert<bits16>(channel1);
382 assert(chan16 == 65535);
385 Channel conversion is a lossy operation. GIL's channel conversion is a linear transformation between the ranges of the source and destination channel.
386 It 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
387 because it will not properly match the maximum values. Instead GIL multiplies the source by 257).
389 All channel models that GIL provides are convertible from/to an integral or floating point type. Thus they support arithmetic operations.
390 Here are the channel-level algorithms that GIL provides:
393 // Converts a source channel value into a destrination channel. Linearly maps the value of the source
394 // into the range of the destination
395 template <typename DstChannel, typename SrcChannel>
396 typename channel_traits<DstChannel>::value_type channel_convert(SrcChannel src);
398 // returns max_value - x + min_value
399 template <typename Channel>
400 typename channel_traits<Channel>::value_type channel_invert(Channel x);
402 // returns a * b / max_value
403 template <typename Channel>
404 typename channel_traits<Channel>::value_type channel_multiply(Channel a, Channel b);
423 \section ColorSpaceSectionDG 5. Color Space and Layout
425 A color space captures the set and interpretation of channels comprising a pixel. It is an MPL random access sequence containing the types
426 of 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).
428 <b>Related Concepts:</b>
430 - ColorSpaceConcept\<ColorSpace>
431 - ColorSpacesCompatibleConcept\<ColorSpace1,ColorSpace2>
432 - ChannelMappingConcept\<Mapping>
436 GIL currently provides the following color spaces: \p gray_t, \p rgb_t, \p rgba_t, and \p cmyk_t. It also provides unnamed
437 N-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
439 and \p argb_layout_t.
441 As an example, here is how GIL defines the RGBA color space:
448 typedef mpl::vector4<red_t,green_t,blue_t,alpha_t> rgba_t;
451 The 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.
452 While 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
453 specified by \p ChannelMappingConcept, which is an MPL random access sequence of integral types. A color space and its associated mapping are often used together.
454 Thus they are grouped in GIL's layout:
457 template <typename ColorSpace,
458 typename ChannelMapping = mpl::range_c<int,0,mpl::size<ColorSpace>::value> >
460 typedef ColorSpace color_space_t;
461 typedef ChannelMapping channel_mapping_t;
465 Here is how to create layouts for the RGBA color space:
468 typedef layout<rgba_t> rgba_layout_t; // default ordering is 0,1,2,3...
469 typedef layout<rgba_t, mpl::vector4_c<int,2,1,0,3> > bgra_layout_t;
470 typedef layout<rgba_t, mpl::vector4_c<int,1,2,3,0> > argb_layout_t;
471 typedef layout<rgba_t, mpl::vector4_c<int,3,2,1,0> > abgr_layout_t;
501 \section ColorBaseSectionDG 6. Color Base
503 A 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
504 elements are channel values. The color base concept, however, can be used in other scenarios. For example, a planar pixel has channels that are not
505 contiguous in memory. Its reference is a proxy class that uses a color base whose elements are channel references. Its iterator uses a color base
506 whose elements are channel iterators.
508 Color base models must satisfy the following concepts:
511 concept ColorBaseConcept<typename T> : CopyConstructible<T>, EqualityComparable<T> {
512 // a GIL layout (the color space and element permutation)
515 // The type of K-th element
516 template <int K> struct kth_element_type;
517 where Metafunction<kth_element_type>;
519 // The result of at_c
520 template <int K> struct kth_element_const_reference_type;
521 where Metafunction<kth_element_const_reference_type>;
523 template <int K> kth_element_const_reference_type<T,K>::type at_c(T);
525 template <ColorBaseConcept T2> where { ColorBasesCompatibleConcept<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&);
534 concept MutableColorBaseConcept<ColorBaseConcept T> : Assignable<T>, Swappable<T> {
535 template <int K> struct kth_element_reference_type;
536 where Metafunction<kth_element_reference_type>;
538 template <int K> kth_element_reference_type<T,K>::type at_c(T);
540 template <ColorBaseConcept T2> where { ColorBasesCompatibleConcept<T,T2> }
541 T& operator=(T&, const T2&);
544 concept ColorBaseValueConcept<typename T> : MutableColorBaseConcept<T>, Regular<T> {
547 concept 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;
553 concept MutableHomogeneousColorBaseConcept<MutableColorBaseConcept CB> : HomogeneousColorBaseConcept<CB> {
554 kth_element_reference_type<0>::type dynamic_at_c(const CB&, std::size_t n);
557 concept HomogeneousColorBaseValueConcept<typename T> : MutableHomogeneousColorBaseConcept<T>, Regular<T> {
560 concept 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>;
568 A color base must have an associated layout (which consists of a color space, as well as an ordering of the channels).
569 There are two ways to index the elements of a color base: A physical index corresponds to the way they are ordered in memory, and
570 a semantic index corresponds to the way the elements are ordered in their color space.
571 For 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
572 in physical ordering is the blue element, whereas the first semantic element is the red one.
573 Models of \p ColorBaseConcept are required to provide the \p at_c<K>(ColorBase) function, which allows for accessing the elements based on their
574 physical order. GIL provides a \p semantic_at_c<K>(ColorBase) function (described later) which can operate on any model of ColorBaseConcept and returns
575 the corresponding semantic element.
577 Two color bases are <i>compatible</i> if they have the same color space and their elements (paired semantically) are convertible to each other.
582 GIL provides a model for a homogeneous color base (a color base whose elements all have the same type).
586 template <typename Element, typename Layout, int K> struct homogeneous_color_base;
590 It is used in the implementation of GIL's pixel, planar pixel reference and planar pixel iterator.
591 Another model of \p ColorBaseConcept is \p packed_pixel - it is a pixel whose channels are bit ranges. See the \ref PixelSectionDG
596 GIL provides the following functions and metafunctions operating on color bases:
599 // Metafunction returning an mpl::int_ equal to the number of elements in the color base
600 template <class ColorBase> struct size;
602 // Returns the type of the return value of semantic_at_c<K>(color_base)
603 template <class ColorBase, int K> struct kth_semantic_element_reference_type;
604 template <class ColorBase, int K> struct kth_semantic_element_const_reference_type;
606 // Returns a reference to the element with K-th semantic index.
607 template <class ColorBase, int K>
608 typename kth_semantic_element_reference_type<ColorBase,K>::type semantic_at_c(ColorBase& p)
609 template <class ColorBase, int K>
610 typename kth_semantic_element_const_reference_type<ColorBase,K>::type semantic_at_c(const ColorBase& p)
612 // Returns the type of the return value of get_color<Color>(color_base)
613 template <typename Color, typename ColorBase> struct color_reference_t;
614 template <typename Color, typename ColorBase> struct color_const_reference_t;
616 // Returns a reference to the element corresponding to the given color
617 template <typename ColorBase, typename Color>
618 typename color_reference_t<Color,ColorBase>::type get_color(ColorBase& cb, Color=Color());
619 template <typename ColorBase, typename Color>
620 typename color_const_reference_t<Color,ColorBase>::type get_color(const ColorBase& cb, Color=Color());
622 // Returns the element type of the color base. Defined for homogeneous color bases only
623 template <typename ColorBase> struct element_type;
624 template <typename ColorBase> struct element_reference_type;
625 template <typename ColorBase> struct element_const_reference_type;
628 GIL also provides the following algorithms which operate on color bases. Note that they all pair the elements semantically:
631 // Equivalents to std::equal, std::copy, std::fill, std::generate
632 template <typename CB1,typename CB2> bool static_equal(const CB1& p1, const CB2& p2);
633 template <typename Src,typename Dst> void static_copy(const Src& src, Dst& dst);
634 template <typename CB, typename Op> void static_generate(CB& dst,Op op);
636 // Equivalents to std::transform
637 template <typename CB , typename Dst,typename Op> Op static_transform( CB&,Dst&,Op);
638 template <typename CB , typename Dst,typename Op> Op static_transform(const CB&,Dst&,Op);
639 template <typename CB1,typename CB2,typename Dst,typename Op> Op static_transform( CB1&, CB2&,Dst&,Op);
640 template <typename CB1,typename CB2,typename Dst,typename Op> Op static_transform(const CB1&, CB2&,Dst&,Op);
641 template <typename CB1,typename CB2,typename Dst,typename Op> Op static_transform( CB1&,const CB2&,Dst&,Op);
642 template <typename CB1,typename CB2,typename Dst,typename Op> Op static_transform(const CB1&,const CB2&,Dst&,Op);
644 // Equivalents to std::for_each
645 template <typename CB1, typename Op> Op static_for_each( CB1&,Op);
646 template <typename CB1, typename Op> Op static_for_each(const CB1&,Op);
647 template <typename CB1,typename CB2, typename Op> Op static_for_each( CB1&, CB2&,Op);
648 template <typename CB1,typename CB2, typename Op> Op static_for_each( CB1&,const CB2&,Op);
649 template <typename CB1,typename CB2, typename Op> Op static_for_each(const CB1&, CB2&,Op);
650 template <typename CB1,typename CB2, typename Op> Op static_for_each(const CB1&,const CB2&,Op);
651 template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each( CB1&, CB2&, CB3&,Op);
652 template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each( CB1&, CB2&,const CB3&,Op);
653 template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each( CB1&,const CB2&, CB3&,Op);
654 template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each( CB1&,const CB2&,const CB3&,Op);
655 template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each(const CB1&, CB2&, CB3&,Op);
656 template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each(const CB1&, CB2&,const CB3&,Op);
657 template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each(const CB1&,const CB2&, CB3&,Op);
658 template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each(const CB1&,const CB2&,const CB3&,Op);
660 // The following algorithms are only defined for homogeneous color bases:
661 // Equivalent to std::fill
662 template <typename HCB, typename Element> void static_fill(HCB& p, const Element& v);
664 // Equivalents to std::min_element and std::max_element
665 template <typename HCB> typename element_const_reference_type<HCB>::type static_min(const HCB&);
666 template <typename HCB> typename element_reference_type<HCB>::type static_min( HCB&);
667 template <typename HCB> typename element_const_reference_type<HCB>::type static_max(const HCB&);
668 template <typename HCB> typename element_reference_type<HCB>::type static_max( HCB&);
671 These algorithms are designed after the corresponding STL algorithms, except that instead of ranges they take color bases and operate on their elements.
672 In addition, they are implemented with a compile-time recursion (thus the prefix "static_"). Finally, they pair the elements semantically instead of based
673 on their physical order in memory. For example, here is the implementation of \p static_equal:
677 template <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);
684 template <> struct element_recursion<0> {
685 template <typename P1,typename P2>
686 static bool static_equal(const P1&, const P2&) { return true; }
690 template <typename P1,typename P2>
691 bool 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);
697 This algorithm is used when invoking \p operator== on two pixels, for example. By using semantic accessors we are properly comparing an RGB pixel
698 to 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.
740 \section PixelSectionDG 7. Pixel
742 A 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
743 model \p ChannelConcept.
744 All 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
745 called <i>heterogeneous</i>. The channels of a pixel may be addressed using semantic or physical indexing, or by color; all color-base algorithms
746 work on pixels as well. Two pixels are <i>compatible</i> if their color spaces are the same and their channels, paired semantically, are compatible.
747 Note that constness, memory organization and reference/value are ignored. For example, an 8-bit RGB planar reference is compatible to a constant 8-bit
748 BGR interleaved pixel value. Most pairwise pixel operations (copy construction, assignment, equality, etc.) are only defined for compatible pixels.
750 Pixels (as well as other GIL constructs built on pixels, such as iterators, locators, views and images) must provide metafunctions to access
751 their color space, channel mapping, number of channels, and (for homogeneous pixels) the channel type:
754 concept 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>;
766 concept HomogeneousPixelBasedConcept<PixelBasedConcept T> {
767 typename channel_type<T>;
768 where Metafunction<channel_type<T> >;
769 where ChannelConcept<channel_type<T>::type>;
773 Pixels model the following concepts:
776 concept 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> >;
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;
786 template <PixelConcept P2> where { PixelConcept<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&);
794 concept MutablePixelConcept<typename P> : PixelConcept<P>, MutableColorBaseConcept<P> {
795 where is_mutable==true;
798 concept 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); }
802 concept 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); }
806 concept PixelValueConcept<typename P> : PixelConcept<P>, Regular<P> {
807 where SameType<value_type,P>;
810 concept 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>;
816 A 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,
817 non-symmetric and often lossy operation (due to both channel and color space approximation). Convertability requires modeling the following concept:
820 template <PixelConcept SrcPixel, MutablePixelConcept DstPixel>
821 concept PixelConvertibleConcept {
822 void color_convert(const SrcPixel&, DstPixel&);
826 The distinction between \p PixelConcept and \p PixelValueConcept is analogous to that for channels and color bases - pixel reference proxies model both,
827 but only pixel values model the latter.
829 <b>Related Concepts:</b>
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>
843 The most commonly used pixel is a homogeneous pixel whose values are together in memory.
844 For this purpose GIL provides the struct \p pixel, templated over the channel value and layout:
847 // models HomogeneousPixelValueConcept
848 template <typename ChannelValue, typename Layout> struct pixel;
850 // Those typedefs are already provided by GIL
851 typedef pixel<bits8, rgb_layout_t> rgb8_pixel_t;
852 typedef pixel<bits8, bgr_layout_t> bgr8_pixel_t;
854 bgr8_pixel_t bgr8(255,0,0); // pixels can be initialized with the channels directly
855 rgb8_pixel_t rgb8(bgr8); // compatible pixels can also be copy-constructed
857 rgb8 = bgr8; // assignment and equality is defined between compatible pixels
858 assert(rgb8 == bgr8); // assignment and equality operate on the semantic channels
860 // The first physical channels of the two pixels are different
861 assert(at_c<0>(rgb8) != at_c<0>(bgr8));
862 assert(dynamic_at_c(bgr8,0) != dynamic_at_c(rgb8,0));
863 assert(rgb8[0] != bgr8[0]); // same as above (but operator[] is defined for pixels only)
866 Planar pixels have their channels distributed in memory. While they share the same value type (\p pixel) with interleaved pixels, their
867 reference type is a proxy class containing references to each of the channels. This is implemented with the struct \p planar_pixel_reference:
870 // models HomogeneousPixel
871 template <typename ChannelReference, typename ColorSpace> struct planar_pixel_reference;
873 // Define the type of a mutable and read-only reference. (These typedefs are already provided by GIL)
874 typedef planar_pixel_reference< bits8&,rgb_t> rgb8_planar_ref_t;
875 typedef planar_pixel_reference<const bits8&,rgb_t> rgb8c_planar_ref_t;
878 Note that, unlike the \p pixel struct, planar pixel references are templated over the color space, not over the pixel layout. They always
879 use a cannonical channel ordering. Ordering of their elements is unnecessary because their elements are references to the channels.
881 Sometimes 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
882 channels occupy bits [0..4],[5..9] and [10..15] respectively. GIL provides a model for such packed pixel formats:
885 // define an rgb565 pixel
886 typedef packed_pixel_type<uint16_t, mpl::vector3_c<unsigned,5,6,5>, rgb_layout_t>::type rgb565_pixel_t;
888 function_requires<PixelValueConcept<rgb565_pixel_t> >();
889 BOOST_STATIC_ASSERT((sizeof(rgb565_pixel_t)==2));
891 // define a bgr556 pixel
892 typedef packed_pixel_type<uint16_t, mpl::vector3_c<unsigned,5,6,5>, bgr_layout_t>::type bgr556_pixel_t;
894 function_requires<PixelValueConcept<bgr556_pixel_t> >();
896 // rgb565 is compatible with bgr556.
897 function_requires<PixelsCompatibleConcept<rgb565_pixel_t,bgr556_pixel_t> >();
900 In 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.
901 GIL refers to such pixels, pixel iterators and images as "bit-aligned". Bit-aligned pixels (and images) are more complex than packed ones.
902 Since 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
903 over a row of packed pixels. For bit-aligned constructs we need a special reference proxy class (bit_aligned_pixel_reference) and iterator
904 class (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:
907 // Mutable reference to a BGR232 pixel
908 typedef const bit_aligned_pixel_reference<unsigned char, mpl::vector3_c<unsigned,2,3,2>, bgr_layout_t, true> bgr232_ref_t;
910 // A mutable iterator over BGR232 pixels
911 typedef bit_aligned_pixel_iterator<bgr232_ref_t> bgr232_ptr_t;
913 // BGR232 pixel value. It is a packed_pixel of size 1 byte. (The last bit is unused)
914 typedef std::iterator_traits<bgr232_ptr_t>::value_type bgr232_pixel_t;
915 BOOST_STATIC_ASSERT((sizeof(bgr232_pixel_t)==1));
917 bgr232_pixel_t red(0,0,3); // = 0RRGGGBB, = 01100000 = 0x60
919 // a buffer of 7 bytes fits exactly 8 BGR232 pixels.
920 unsigned char pix_buffer[7];
921 std::fill(pix_buffer,pix_buffer+7,0);
923 // Fill the 8 pixels with red
924 bgr232_ptr_t pix_it(&pix_buffer[0],0); // start at bit 0 of the first pixel
925 for (int i=0; i<8; ++i) {
928 // Result: 0x60 0x30 0x11 0x0C 0x06 0x83 0xC1
934 Since pixels model \p ColorBaseConcept and \p PixelBasedConcept all algorithms and metafunctions of color bases can work with them as well:
937 // This is how to access the first semantic channel (red)
938 assert(semantic_at_c<0>(rgb8) == semantic_at_c<0>(bgr8));
940 // This is how to access the red channel by name
941 assert(get_color<red_t>(rgb8) == get_color<red_t>(bgr8));
943 // This is another way of doing it (some compilers don't like the first one)
944 assert(get_color(rgb8,red_t()) == get_color(bgr8,red_t()));
946 // This is how to use the PixelBasedConcept metafunctions
947 BOOST_MPL_ASSERT(num_channels<rgb8_pixel_t>::value == 3);
948 BOOST_MPL_ASSERT((is_same<channel_type<rgb8_pixel_t>::type, bits8>));
949 BOOST_MPL_ASSERT((is_same<color_space_type<bgr8_pixel_t>::type, rgb_t> ));
950 BOOST_MPL_ASSERT((is_same<channel_mapping_type<bgr8_pixel_t>::type, mpl::vector3_c<int,2,1,0> > ));
952 // Pixels contain just the three channels and nothing extra
953 BOOST_MPL_ASSERT(sizeof(rgb8_pixel_t)==3);
955 rgb8_planar_ref_t ref(bgr8); // copy construction is allowed from a compatible mutable pixel type
957 get_color<red_t>(ref) = 10; // assignment is ok because the reference is mutable
958 assert(get_color<red_t>(bgr8)==10); // references modify the value they are bound to
960 // Create a zero packed pixel and a full regular unpacked pixel.
962 rgb8_pixel_t rgb_full(255,255,255);
964 // Convert all channels of the unpacked pixel to the packed one & assert the packed one is full
965 get_color(r565,red_t()) = channel_convert<rgb565_channel0_t>(get_color(rgb_full,red_t()));
966 get_color(r565,green_t()) = channel_convert<rgb565_channel1_t>(get_color(rgb_full,green_t()));
967 get_color(r565,blue_t()) = channel_convert<rgb565_channel2_t>(get_color(rgb_full,blue_t()));
968 assert(r565 == rgb565_pixel_t((uint16_t)65535));
971 GIL also provides the \p color_convert algorithm to convert between pixels of different color spaces and channel types:
974 rgb8_pixel_t red_in_rgb8(255,0,0);
975 cmyk16_pixel_t red_in_cmyk16;
976 color_convert(red_in_rgb8,red_in_cmyk16);
1017 \section PixelIteratorSectionDG 8. Pixel Iterator
1019 \section FundamentalIteratorDG Fundamental Iterator
1021 Pixel iterators are random traversal iterators whose \p value_type models \p PixelValueConcept.
1022 Pixel iterators provide metafunctions to determine whether they are mutable (i.e. whether they allow for modifying the pixel they refer to),
1023 to get the immutable (read-only) type of the iterator, and to determine whether they are plain iterators or adaptors over another pixel iterator:
1026 concept 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
1034 template <typename Iterator>
1035 concept MutablePixelIteratorConcept : PixelIteratorConcept<Iterator>, MutableRandomAccessIteratorConcept<Iterator> {};
1038 <b>Related Concepts:</b>
1040 - PixelIteratorConcept\<Iterator>
1041 - MutablePixelIteratorConcept\<Iterator>
1045 A built-in pointer to pixel, \p pixel<ChannelValue,Layout>*, is GIL's model for pixel iterator over interleaved homogeneous pixels.
1046 Similarly, \p packed_pixel<PixelData,ChannelRefVec,Layout>* is GIL's model for an iterator over interleaved packed pixels.
1048 For planar homogeneous pixels, GIL provides the class \p planar_pixel_iterator, templated over a channel iterator and color space. Here is
1049 how the standard mutable and read-only planar RGB iterators over unsigned char are defined:
1052 template <typename ChannelPtr, typename ColorSpace> struct planar_pixel_iterator;
1054 // GIL provided typedefs
1055 typedef planar_pixel_iterator<const bits8*, rgb_t> rgb8c_planar_ptr_t;
1056 typedef planar_pixel_iterator< bits8*, rgb_t> rgb8_planar_ptr_t;
1059 \p planar_pixel_iterator also models \p HomogeneousColorBaseConcept (it subclasses from \p homogeneous_color_base) and, as a result, all color base
1060 algorithms apply to it. The element type of its color base is a channel iterator. For example, GIL implements \p operator++ of planar iterators approximately
1064 template <typename T>
1065 struct inc : public std::unary_function<T,T> {
1066 T operator()(T x) const { return ++x; }
1069 template <typename ChannelPtr, typename ColorSpace>
1070 planar_pixel_iterator<ChannelPtr,ColorSpace>&
1071 planar_pixel_iterator<ChannelPtr,ColorSpace>::operator++() {
1072 static_transform(*this,*this,inc<ChannelPtr>());
1077 Since \p static_transform uses compile-time recursion, incrementing an instance of \p rgb8_planar_ptr_t amounts to three pointer increments.
1078 GIL 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
1081 \section IteratorAdaptorDG Iterator Adaptor
1083 Iterator adaptor is an iterator that wraps around another iterator. Its \p is_iterator_adaptor metafunction must evaluate to true, and it
1084 needs 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:
1087 concept IteratorAdaptorConcept<RandomAccessTraversalIteratorConcept Iterator> {
1088 where SameType<is_iterator_adaptor<Iterator>::type, mpl::true_>;
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>;
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>;
1099 const iterator_adaptor_get_base<Iterator>::type& Iterator::base() const;
1102 template <boost_concepts::Mutable_ForwardIteratorConcept Iterator>
1103 concept MutableIteratorAdaptorConcept : IteratorAdaptorConcept<Iterator> {};
1106 <b>Related Concepts:</b>
1108 - IteratorAdaptorConcept\<Iterator>
1109 - MutableIteratorAdaptorConcept\<Iterator>
1113 GIL 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,
1116 for on-the-fly color conversion. It can be used to construct a shallow image "view" that pretends to have a different color space or
1117 channel depth. See \ref ImageViewFrowImageViewDG for more. The unary function \p Fn must model \p PixelDereferenceAdaptorConcept (see below).
1119 \section PixelDereferenceAdaptorAG Pixel Dereference Adaptor
1121 Pixel 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
1125 template <boost::UnaryFunctionConcept D>
1126 concept 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;
1133 where Convertible<value_type, result_type>;
1139 GIL 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
1145 GIL uses pixel dereference adaptors to implement image views that perform color conversion upon dereferencing, or that return the N-th channel of the
1146 underlying pixel. They can be used to model virtual image views that perform an arbitrary function upon dereferencing, for example a view of
1147 the Mandelbrot set. \p dereference_iterator_adaptor<Iterator,Fn> is an iterator wrapper over a pixel iterator \p Iterator that invokes the given dereference
1148 iterator adaptor \p Fn upon dereferencing.
1150 \section StepIteratorDG Step Iterator
1152 Sometimes we want to traverse pixels with a unit step other than the one provided by the fundamental pixel iterators.
1153 Examples 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)
1160 Step iterators are forward traversal iterators that allow changing the step between adjacent values:
1163 concept StepIteratorConcept<boost_concepts::ForwardTraversalConcept Iterator> {
1164 template <Integral D> void Iterator::set_step(D step);
1167 concept MutableStepIteratorConcept<boost_concepts::Mutable_ForwardIteratorConcept Iterator> : StepIteratorConcept<Iterator> {};
1170 GIL 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).
1171 This is necessary, for example, when implementing an iterator navigating along a column of pixels - the size of a row of pixels
1172 may sometimes not be divisible by the size of a pixel; for example rows may be word-aligned.
1174 To 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.
1175 It must supply functions returning the number of bits per memory unit (1 or 8), the current step in memory units,
1176 the 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
1177 a 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:
1181 concept 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); }
1192 It 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
1193 type that allows for dynamically specified horizontal step:
1196 concept HasDynamicXStepTypeConcept<typename T> {
1197 typename dynamic_x_step_type<T>;
1198 where Metafunction<dynamic_x_step_type<T> >;
1202 All models of pixel iterators, locators and image views that GIL provides support \p HasDynamicXStepTypeConcept.
1204 <b>Related Concepts:</b>
1206 - StepIteratorConcept\<Iterator>
1207 - MutableStepIteratorConcept\<Iterator>
1208 - MemoryBasedIteratorConcept\<Iterator>
1209 - HasDynamicXStepTypeConcept\<T>
1213 All standard memory-based iterators GIL currently provides model \p MemoryBasedIteratorConcept.
1214 GIL provides the class \p memory_based_step_iterator which models \p PixelIteratorConcept, \p StepIteratorConcept, and \p MemoryBasedIteratorConcept.
1215 It takes the base iterator as a template parameter (which must model \p PixelIteratorConcept and \p MemoryBasedIteratorConcept)
1216 and 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)
1217 to 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:
1220 template <typename I> // Models MemoryBasedIteratorConcept, HasDynamicXStepTypeConcept
1221 typename dynamic_x_step_type<I>::type make_step_iterator(const I& it, std::ptrdiff_t step);
1224 GIL 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
1225 and invokes a function object to get the value of the pixel upon dereferencing. It models \p PixelIteratorConcept and \p StepIteratorConcept but
1226 not \p MemoryBasedIteratorConcept.
1228 \section LocatorDG Pixel Locator
1230 A Locator allows for navigation in two or more dimensions. Locators are N-dimensional iterators in spirit, but we use a different
1231 name because they don't satisfy all the requirements of iterators. For example, they don't supply increment and decrement operators because it is unclear
1232 which dimension the operators should advance along.
1233 N-dimensional locators model the following concept:
1236 concept 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;
1244 static const size_t num_dimensions; // dimensionality of the locator
1245 where num_dimensions = point_t::num_dimensions;
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;
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);
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&);
1266 reference operator*(const Loc&);
1267 reference operator[](const Loc&, const difference_type&);
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&);
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;
1279 template <typename Loc>
1280 concept MutableRandomAccessNDLocatorConcept : RandomAccessNDLocatorConcept<Loc> {
1281 where Mutable<reference>;
1285 Two-dimensional locators have additional requirements:
1288 concept RandomAccess2DLocatorConcept<RandomAccessNDLocatorConcept Loc> {
1289 where num_dimensions==2;
1290 where Point2DConcept<point_t>;
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;
1297 // Only available to locators that have dynamic step in Y
1298 //Loc::Loc(const Loc& loc, y_coord_t);
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);
1303 x_iterator& Loc::x();
1304 x_iterator const& Loc::x() const;
1305 y_iterator& Loc::y();
1306 y_iterator const& Loc::y() const;
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;
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;
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;
1323 concept MutableRandomAccess2DLocatorConcept<RandomAccess2DLocatorConcept Loc> : MutableRandomAccessNDLocatorConcept<Loc> {};
1326 2D locators can have a dynamic step not just horizontally, but also vertically. This gives rise to the Y equivalent of \p HasDynamicXStepTypeConcept:
1329 concept HasDynamicYStepTypeConcept<typename T> {
1330 typename dynamic_y_step_type<T>;
1331 where Metafunction<dynamic_y_step_type<T> >;
1335 All locators and image views that GIL provides model \p HasDynamicYStepTypeConcept.
1337 Sometimes 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).
1338 Such locators and views must be transposable:
1341 concept HasTransposedTypeConcept<typename T> {
1342 typename transposed_type<T>;
1343 where Metafunction<transposed_type<T> >;
1347 All GIL provided locators and views model \p HasTransposedTypeConcept.
1349 The locators GIL uses operate over models of \p PixelConcept and their x and y dimension types are the same. They model the following concept:
1352 concept 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;
1358 typename coord_t = x_coord_t;
1361 concept MutablePixelLocatorConcept<PixelLocatorConcept Loc> : MutableRandomAccess2DLocatorConcept<Loc> {};
1364 <b>Related Concepts:</b>
1366 - HasDynamicYStepTypeConcept\<T>
1367 - HasTransposedTypeConcept\<T>
1368 - RandomAccessNDLocatorConcept\<Locator>
1369 - MutableRandomAccessNDLocatorConcept\<Locator>
1370 - RandomAccess2DLocatorConcept\<Locator>
1371 - MutableRandomAccess2DLocatorConcept\<Locator>
1372 - PixelLocatorConcept\<Locator>
1373 - MutablePixelLocatorConcept\<Locator>
1377 GIL provides two models of \p PixelLocatorConcept - a memory-based locator, \p memory_based_2d_locator and a virtual locator \p virtual_2d_locator.
1379 \p memory_based_2d_locator is a locator over planar or interleaved images that have their pixels in memory.
1380 It takes a model of \p StepIteratorConcept over pixels as a template parameter. (When instantiated with a model of \p MutableStepIteratorConcept,
1381 it models \p MutablePixelLocatorConcept).
1384 template <typename StepIterator> // Models StepIteratorConcept, MemoryBasedIteratorConcept
1385 class memory_based_2d_locator;
1388 The 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
1389 wrapper around \p StepIterator and uses it to navigate vertically, while its base iterator is used to navigate horizontally.
1391 Combining fundamental and step iterators allows us to create locators that describe complex
1392 pixel 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.
1393 Using 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)
1399 Of course, one could provide their own custom x-iterator. One such example described later is an iterator adaptor that performs color
1400 conversion when dereferenced.
1402 Given 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.
1405 Then 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
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
1409 given its X,Y coordiantes. Virtual locators can be used to implement virtual image views that can model any user-defined function. See the GIL
1410 tutorial for an example of using virtual locators to create a view of the Mandelbrot set.
1412 Both the virtual and the memory-based locators subclass from \p pixel_2d_locator_base, a base class that provides most of the interface required
1413 by \p PixelLocatorConcept. Users may find this base class useful if they need to provide other models of \p PixelLocatorConcept.
1415 Here is some sample code using locators:
1418 loc=img.xy_at(10,10); // start at pixel (x=10,y=10)
1419 above=loc.cache_location(0,-1); // remember relative locations of neighbors above and below
1420 below=loc.cache_location(0, 1);
1421 ++loc.x(); // move to (11,10)
1422 loc.y()+=15; // move to (11,25)
1423 loc-=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
1428 The standard GIL locators are fast and lightweight objects. For example, the locator for a simple interleaved image consists of
1429 one 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
1430 incrementing a raw pointer (or N pointers for planar images). Computing 2D offsets is slower as it requires multiplication and addition.
1431 Filters, for example, need to access the same neighbors for every pixel in the image, in which case the relative positions can be cached
1432 into 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
1435 \section IteratorFrom2DDG Iterator over 2D image
1437 Sometimes 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
1438 as 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
1439 memory-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
1440 information for it to determine when to do a "carriage return". Synopsis:
1443 template <typename Locator> // Models PixelLocatorConcept
1444 class iterator_from_2d {
1446 iterator_from_2d(const Locator& loc, int x, int width);
1448 iterator_from_2d& operator++(); // if (++_x<_width) ++_p.x(); else _p+=point_t(-_width,1);
1457 Iterating 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.
1458 This 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
1460 adds 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.
1489 \section ImageViewSectionDG 9. Image View
1491 An image view is a generalization of STL's range concept to multiple dimensions. Similar to ranges (and iterators), image views are shallow, don't
1492 own the underlying data and don't propagate their constness over the data. For example, a constant image view cannot be resized, but may allow
1493 modifying the pixels. For pixel-immutable operations, use constant-value image view (also called non-mutable image view).
1494 Most general N-dimensional views satisfy the following concept:
1497 concept 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()
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>;
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);
1522 static const size_t num_dimensions = point_t::num_dimensions;
1524 // Create from a locator at the top-left corner and dimensions
1525 View::View(const locator&, const point_type&);
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?
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;
1540 reference operator()(View,const point_t&) const;
1543 concept MutableRandomAccessNDImageViewConcept<RandomAccessNDImageViewConcept View> {
1544 where Mutable<reference>;
1548 Two-dimensional image views have the following extra requirements:
1551 concept RandomAccess2DImageViewConcept<RandomAccessNDImageViewConcept View> {
1552 where num_dimensions==2;
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;
1560 x_coord_t View::width() const;
1561 y_coord_t View::height() const;
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;
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;
1574 xy_locator View::xy_at(const point_t&) const;
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;
1585 concept MutableRandomAccess2DImageViewConcept<RandomAccess2DImageViewConcept View>
1586 : MutableRandomAccessNDImageViewConcept<View> {};
1589 Image views that GIL typically uses operate on value types that model \p PixelValueConcept and have some additional requirements:
1592 concept 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;
1598 typename coord_t = x_coord_t;
1600 std::size_t View::num_channels() const;
1604 concept MutableImageViewConcept<ImageViewConcept View> : MutableRandomAccess2DImageViewConcept<View> {};
1607 Two image views are compatible if they have compatible pixels and the same number of dimensions:
1609 concept ViewsCompatibleConcept<ImageViewConcept V1, ImageViewConcept V2> {
1610 where PixelsCompatibleConcept<V1::value_type, V2::value_type>;
1611 where V1::num_dimensions == V2::num_dimensions;
1615 Compatible 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.
1617 <b>Related Concepts:</b>
1619 - RandomAccessNDImageViewConcept\<View>
1620 - MutableRandomAccessNDImageViewConcept\<View>
1621 - RandomAccess2DImageViewConcept\<View>
1622 - MutableRandomAccess2DImageViewConcept\<View>
1623 - ImageViewConcept\<View>
1624 - MutableImageViewConcept\<View>
1625 - ViewsCompatibleConcept\<View1,View2>
1629 GIL 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:
1633 template <typename Locator> // Models PixelLocatorConcept (could be MutablePixelLocatorConcept)
1636 typedef Locator xy_locator;
1637 typedef iterator_from_2d<Locator> iterator;
1640 xy_locator _pixels; // 2D pixel locator at the top left corner of the image view range
1641 point_t _dimensions; // width and height
1645 Image views are lightweight objects. A regular interleaved view is typically 16 bytes long - two integers for the width and height (inside dimensions)
1646 one for the number of bytes between adjacent rows (inside the locator) and one pointer to the beginning of the pixel block.
1650 \subsection ImageViewFrowRawDG Creating Views from Raw Pixels
1652 Standard image views can be constructed from raw data of any supported color space, bit depth, channel ordering or planar vs. interleaved structure.
1653 Interleaved views are constructed using \p interleaved_view, supplying the image dimensions, number of bytes per row, and a
1654 pointer to the first pixel:
1657 template <typename Iterator> // Models pixel iterator (like rgb8_ptr_t or rgb8c_ptr_t)
1658 image_view<...> interleaved_view(ptrdiff_t width, ptrdiff_t height, Iterator pixels, ptrdiff_t rowsize)
1661 Planar views are defined for every color space and take each plane separately. Here is the RGB one:
1664 template <typename IC> // Models channel iterator (like bits8* or const bits8*)
1665 image_view<...> planar_rgb_view(ptrdiff_t width, ptrdiff_t height,
1666 IC r, IC g, IC b, ptrdiff_t rowsize);
1669 Note that the supplied pixel/channel iterators could be constant (read-only), in which case the returned view is a constant-value (immutable) view.
1671 \subsection ImageViewFrowImageViewDG Creating Image Views from Other Image Views
1673 It 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
1674 derived from the type of the source. GIL uses the following metafunctions to get the derived types:
1678 // Some result view types
1679 template <typename View>
1680 struct dynamic_xy_step_type : public dynamic_y_step_type<typename dynamic_x_step_type<View>::type> {};
1682 template <typename View>
1683 struct dynamic_xy_step_transposed_type : public dynamic_xy_step_type<typename transposed_type<View>::type> {};
1685 // color and bit depth converted view to match pixel type P
1686 template <typename SrcView, // Models ImageViewConcept
1687 typename DstP, // Models PixelConcept
1688 typename ColorConverter=gil::default_color_converter>
1689 struct color_converted_view_type {
1690 typedef ... type; // image view adaptor with value type DstP, over SrcView
1693 // single-channel view of the N-th channel of a given view
1694 template <typename SrcView>
1695 struct nth_channel_view_type {
1700 GIL Provides the following view transformations:
1703 // flipped upside-down, left-to-right, transposed view
1704 template <typename View> typename dynamic_y_step_type<View>::type flipped_up_down_view(const View& src);
1705 template <typename View> typename dynamic_x_step_type<View>::type flipped_left_right_view(const View& src);
1706 template <typename View> typename dynamic_xy_step_transposed_type<View>::type transposed_view(const View& src);
1709 template <typename View> typename dynamic_xy_step_type<View>::type rotated180_view(const View& src);
1710 template <typename View> typename dynamic_xy_step_transposed_type<View>::type rotated90cw_view(const View& src);
1711 template <typename View> typename dynamic_xy_step_transposed_type<View>::type rotated90ccw_view(const View& src);
1713 // view of an axis-aligned rectangular area within an image
1714 template <typename View> View subimage_view(const View& src,
1715 const View::point_t& top_left, const View::point_t& dimensions);
1717 // subsampled view (skipping pixels in X and Y)
1718 template <typename View> typename dynamic_xy_step_type<View>::type subsampled_view(const View& src,
1719 const View::point_t& step);
1721 template <typename View, typename P>
1722 color_converted_view_type<View,P>::type color_converted_view(const View& src);
1723 template <typename View, typename P, typename CCV> // with a custom color converter
1724 color_converted_view_type<View,P,CCV>::type color_converted_view(const View& src);
1726 template <typename View>
1727 nth_channel_view_type<View>::view_t nth_channel_view(const View& view, int n);
1730 The implementations of most of these view factory methods are straightforward. Here is, for example, how the flip views are implemented.
1731 The 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
1735 template <typename View>
1736 typename 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));
1743 The call to \p gil_function_requires ensures (at compile time) that the template parameter is a valid model of \p ImageViewConcept. Using it
1744 generates easier to track compile errors, creates no extra code and has no run-time performance impact.
1745 We 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
1746 is 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
1747 in the code examples in this guide for the sake of succinctness.
1749 Image views can be freely composed (see section \ref MetafunctionsDG for the typedefs \p rgb16_image_t and \p gray16_step_view_t):
1752 rgb16_image_t img(100,100); // an RGB interleaved image
1754 // grayscale view over the green (index 1) channel of img
1755 gray16_step_view_t green=nth_channel_view(view(img),1);
1757 // 50x50 view of the green channel of img, upside down and taking every other pixel in X and in Y
1758 gray16_step_view_t ud_fud=flipped_up_down_view(subsampled_view(green,2,2));
1761 As previously stated, image views are fast, constant-time, shallow views over the pixel data. The above code does not copy any pixels; it operates
1762 on the pixel data allocated when \p img was created.
1764 \subsection ImageViewAlgorithmsDG STL-Style Algorithms on Image Views
1766 <p>Image views provide 1D iteration of their pixels via begin() and end() methods, which makes it possible to use STL
1767 algorithms with them. However, using nested loops over X and Y is in many cases more efficient. The algorithms in this
1768 section resemble STL algorithms, but they abstract away the nested loops and take views (as opposed to ranges) as input.
1771 // Equivalents of std::copy and std::uninitialized_copy
1772 // where ImageViewConcept<V1>, MutableImageViewConcept<V2>, ViewsCompatibleConcept<V1,V2>
1773 template <typename V1, typename V2>
1774 void copy_pixels(const V1& src, const V2& dst);
1775 template <typename V1, typename V2>
1776 void uninitialized_copy_pixels(const V1& src, const V2& dst);
1778 // Equivalents of std::fill and std::uninitialized_fill
1779 // where MutableImageViewConcept<V>, PixelConcept<Value>, PixelsCompatibleConcept<Value,V::value_type>
1780 template <typename V, typename Value>
1781 void fill_pixels(const V& dst, const Value& val);
1782 template <typename V, typename Value>
1783 void uninitialized_fill_pixels(const V& dst, const Value& val);
1785 // Equivalent of std::for_each
1786 // where ImageViewConcept<V>, boost::UnaryFunctionConcept<F>
1787 // where PixelsCompatibleConcept<V::reference, F::argument_type>
1788 template <typename V, typename F>
1789 F for_each_pixel(const V& view, F fun);
1790 template <typename V, typename F>
1791 F for_each_pixel_position(const V& view, F fun);
1793 // Equivalent of std::generate
1794 // where MutableImageViewConcept<V>, boost::UnaryFunctionConcept<F>
1795 // where PixelsCompatibleConcept<V::reference, F::argument_type>
1796 template <typename V, typename F>
1797 void generate_pixels(const V& dst, F fun);
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>
1804 template <typename V1, typename V2, typename F>
1805 F transform_pixels(const V1& src, const V2& dst, F fun);
1806 template <typename V1, typename V2, typename F>
1807 F transform_pixel_positions(const V1& src, const V2& dst, F fun);
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>
1815 template <typename V1, typename V2, typename V3, typename F>
1816 F transform_pixels(const V1& src1, const V2& src2, const V3& dst, F fun);
1817 template <typename V1, typename V2, typename V3, typename F>
1818 F transform_pixel_positions(const V1& src1, const V2& src2, const V3& dst, F fun);
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.
1823 template <typename V1, typename V2>
1824 void copy_and_convert_pixels(const V1& src, const V2& dst);
1825 template <typename V1, typename V2, typename ColorConverter>
1826 void copy_and_convert_pixels(const V1& src, const V2& dst, ColorConverter ccv);
1828 // Equivalent of std::equal
1829 // where ImageViewConcept<V1>, ImageViewConcept<V2>, ViewsCompatibleConcept<V1,V2>
1830 template <typename V1, typename V2>
1831 bool equal_pixels(const V1& view1, const V2& view2);
1834 Algorithms 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.
1836 This allows for writing algorithms that use pixel neighbors, as the tutorial demonstrates.
1838 Most 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.
1839 In 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.
1840 When 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
1841 1D-traversable, the algorithms fall-back to an X-loop nested inside a Y-loop.
1843 The algorithms typically delegate the work to their corresponding STL algorithms. For example, \p copy_pixels calls \p std::copy either for each
1844 row, or, when the images are 1D-traversable, once for all pixels.
1846 In 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
1848 implements via \p memmove.
1850 As 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
1851 1D-traversable views, or one per each row of interleaved non-1D-traversable images, etc.
1853 GIL also provides some beta-versions of image processing algorithms, such as resampling and convolution in a numerics extension available on
1854 http://stlab.adobe.com/gil/download.html. This code is in early stage of development and is not optimized for speed
1876 \section ImageSectionDG 10. Image
1878 An image is a container that owns the pixels of a given image view. It allocates them in its constructor and deletes
1879 them in the destructor. It has a deep assignment operator and copy constructor. Images are used rarely, just when
1880 data ownership is important. Most STL algorithms operate on ranges, not containers. Similarly most GIL algorithms operate on image
1881 views (which images provide).
1883 In the most general form images are N-dimensional and satisfy the following concept:
1886 concept 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;
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);
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);
1899 const point_t& Img::dimensions() const;
1900 const const_view_t& const_view(const Img&);
1901 const view_t& view(Img&);
1905 Two-dimensional images have additional requirements:
1908 concept 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;
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);
1915 x_coord_t Img::width() const;
1916 y_coord_t Img::height() const;
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);
1923 GIL's images have views that model \p ImageViewConcept and operate on pixels.
1926 concept ImageConcept<RandomAccess2DImageConcept Img> {
1927 where MutableImageViewConcept<view_t>;
1928 typename coord_t = view_t::coord_t;
1932 Images, unlike locators and image views, don't have 'mutable' set of concepts because immutable images are not very useful.
1934 <b>Related Concepts:</b>
1936 - RandomAccessNDImageConcept\<Image>
1937 - RandomAccess2DImageConcept\<Image>
1938 - ImageConcept\<Image>
1942 GIL provides a class, \p image, which is templated over the value type (the pixel) and models \p ImageConcept.
1945 template <typename Pixel, \\ Models PixelValueConcept
1946 bool IsPlanar, \\ planar or interleaved image
1947 typename A=std::allocator<unsigned char> >
1951 The image constructor takes an alignment parameter which allows for constructing images that are word-aligned or 8-byte aligned. The alignment is specified in
1952 bytes. The default value for alignment is 0, which means there is no padding at the end of rows. Many operations are
1953 faster 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.
1956 \section VariantSecDG 11. Run-time specified images and image views
1958 The color space, channel depth, channel ordering, and interleaved/planar structure of an image are defined by the type of its template argument, which
1959 makes them compile-time bound. Often some of these parameters are available only at run time.
1960 Consider, 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
1961 depth. How can we possibly write this using our generic image? What type is the image loading code supposed to return?
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:
1965 #include <boost/gil/extension/dynamic_image/dynamic_image_all.hpp>
1966 using namespace boost;
1968 #define ASSERT_SAME(A,B) BOOST_STATIC_ASSERT((is_same< A,B >::value))
1970 // Define the set of allowed images
1971 typedef mpl::vector<rgb8_image_t, cmyk16_planar_image_t> my_images_t;
1973 // Create any_image class (or any_image_view) class
1974 typedef any_image<my_images_t> my_any_image_t;
1976 // Associated view types are available (equivalent to the ones in image_t)
1977 typedef any_image_view<mpl::vector2<rgb8_view_t, cmyk16_planar_view_t > > AV;
1978 ASSERT_SAME(my_any_image_t::view_t, AV);
1980 typedef any_image_view<mpl::vector2<rgb8c_view_t, cmyk16c_planar_view_t> > CAV;
1981 ASSERT_SAME(my_any_image_t::const_view_t, CAV);
1982 ASSERT_SAME(my_any_image_t::const_view_t, my_any_image_t::view_t::const_t);
1984 typedef any_image_view<mpl::vector2<rgb8_step_view_t, cmyk16_planar_step_view_t> > SAV;
1985 ASSERT_SAME(typename dynamic_x_step_type<my_any_image_t::view_t>::type, SAV);
1987 // Assign it a concrete image at run time:
1988 my_any_image_t myImg = my_any_image_t(rgb8_image_t(100,100));
1990 // Change it to another at run time. The previous image gets destroyed
1991 myImg = cmyk16_planar_image_t(200,100);
1993 // Assigning to an image not in the allowed set throws an exception
1994 myImg = gray8_image_t(); // will throw std::bad_cast
1997 \p any_image and \p any_image_view subclass from GIL's \p variant class, which breaks down the instantiated type
1998 into a non-templated underlying base type and a unique instantiation type identifier. The underlying base instance is represented
1999 as a block of bytes. The block is large enough to hold the largest of the specified types.
2001 GIL's variant is similar to \p boost::variant in spirit (hence we borrow the name from there) but it differs in several ways from
2002 the current boost implementation. Perhaps the biggest difference is that GIL's variant always takes a single argument, which is a model
2003 of MPL Random Access Sequence enumerating the allowed types. Having a single interface allows GIL's variant to be used easier in generic code. Synopsis:
2006 template <typename Types> // models MPL Random Access Container
2011 typedef Types types_t;
2014 variant(const variant& v);
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);
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);
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);
2029 template <typename T> static bool has_type();
2031 template <typename T> const T& _dynamic_cast() const;
2032 template <typename T> T& _dynamic_cast();
2034 template <typename T> bool current_type_is() const;
2037 template <typename UOP, typename Types>
2038 UOP::result_type apply_operation(variant<Types>& v, UOP op);
2039 template <typename UOP, typename Types>
2040 UOP::result_type apply_operation(const variant<Types>& v, UOP op);
2042 template <typename BOP, typename Types1, typename Types2>
2043 BOP::result_type apply_operation( variant<Types1>& v1, variant<Types2>& v2, UOP op);
2045 template <typename BOP, typename Types1, typename Types2>
2046 BOP::result_type apply_operation(const variant<Types1>& v1, variant<Types2>& v2, UOP op);
2048 template <typename BOP, typename Types1, typename Types2>
2049 BOP::result_type apply_operation(const variant<Types1>& v1, const variant<Types2>& v2, UOP op);
2052 GIL's \p any_image_view and \p any_image are subclasses of \p variant:
2055 template <typename ImageViewTypes>
2056 class any_image_view : public variant<ImageViewTypes> {
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;
2064 template <typename T> explicit any_image_view(const T& obj);
2065 any_image_view(const any_image_view& v);
2067 template <typename T> any_image_view& operator=(const T& obj);
2068 any_image_view& operator=(const any_image_view& v);
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;
2077 template <typename ImageTypes>
2078 class any_image : public variant<ImageTypes> {
2079 typedef variant<ImageTypes> parent_t;
2081 typedef ... const_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;
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);
2092 template <typename T> any_image& operator=(const T& obj);
2093 any_image& operator=(const any_image& v);
2095 void recreate(const point_t& dims, unsigned alignment=1);
2096 void recreate(x_coord_t width, y_coord_t height, unsigned alignment=1);
2098 std::size_t num_channels() const;
2099 point_t dimensions() const;
2100 x_coord_t width() const;
2101 y_coord_t height() const;
2105 Operations are invoked on variants via \p apply_operation passing a function object to perform the operation. The code for every allowed type in the
2106 variant is instantiated and the appropriate instantiation is selected via a switch statement. Since image view algorithms typically have time complexity
2107 at least linear on the number of pixels, the single switch statement of image view variant adds practically no measurable performance overhead compared
2108 to templated image views.
2110 Variants behave like the underlying type. Their copy constructor will invoke the copy constructor of the underlying instance. Equality operator will
2111 check 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
2112 first type. That means that \p any_image_view has shallow default-constructor, copy-constructor, assigment and equaty comparison, whereas \p any_image
2115 It 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
2116 requirements 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
2118 the type resolution would have to be performed per pixel. Image-level algorithms should be implemented via \p apply_operation. That said,
2119 many common operations are shared between the static and dynamic types. In addition, all of the image view transformations and many STL-like image view
2120 algorithms have overloads operating on \p any_image_view, as illustrated with \p copy_pixels:
2123 rgb8_view_t v1(...); // concrete image view
2124 bgr8_view_t v2(...); // concrete image view compatible with v1 and of the same size
2125 any_image_view<Types> av(...); // run-time specified image view
2127 // Copies the pixels from v1 into v2.
2128 // If the pixels are incompatible triggers compile error
2131 // The source or destination (or both) may be run-time instantiated.
2132 // If they happen to be incompatible, throws std::bad_cast
2133 copy_pixels(v1, av);
2134 copy_pixels(av, v2);
2135 copy_pixels(av, av);
2138 By having algorithm overloads supporting dynamic constructs, we create a base upon which it is possible to write algorithms that can work with
2139 either 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:
2142 #include <boost\gil\extension\io\jpeg_dynamic_io.hpp>
2144 template <typename Image> // Could be rgb8_image_t or any_image<...>
2145 void save_180rot(const std::string& file_name) {
2147 jpeg_read_image(file_name, img);
2148 jpeg_write_view(file_name, rotated180_view(view(img)));
2152 It can be instantiated with either a compile-time or a runtime image because all functions it uses have overloads taking runtime constructs.
2153 For example, here is how \p rotated180_view is implemented:
2156 // implementation using templated view
2157 template <typename View>
2158 typename dynamic_xy_step_type<View>::type rotated180_view(const View& src) { ... }
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));
2170 // overloading of the function using variant. Takes and returns run-time bound view.
2171 // The returned view has a dynamic step
2172 template <typename ViewTypes> inline // Models MPL Random Access Container of models of ImageViewConcept
2173 typename 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>());
2178 Variants should be used with caution (especially algorithms that take more than one variant) because they instantiate the algorithm
2179 for every possible model that the variant can take. This can take a toll on compile time and executable size.
2180 Despite these limitations, \p variant is a powerful technique that allows us to combine the speed of compile-time resolution with
2181 the flexibility of run-time resolution. It allows us to treat images of different parameters uniformly as a collection and store
2182 them in the same container.
2186 \section MetafunctionsDG 12. Useful Metafunctions and Typedefs
2188 Flexibility comes at a price. GIL types can be very long and hard to read.
2189 To address this problem, GIL provides typedefs to refer to any standard image, pixel iterator, pixel locator, pixel reference or pixel value.
2190 They follow this pattern:
2192 \e ColorSpace + \e BitDepth + ["s|f"] + ["c"] + ["_planar"] + ["_step"] + \e ClassType + "_t"
2194 Where \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:
2201 bgr8_image_t i; // 8-bit unsigned (unsigned char) interleaved BGR image
2202 cmyk16_pixel_t; x; // 16-bit unsigned (unsigned short) CMYK pixel value;
2203 cmyk16sc_planar_ref_t p(x); // const reference to a 16-bit signed integral (signed short) planar CMYK pixel x.
2204 rgb32f_planar_step_ptr_t ii; // step iterator to a floating point 32-bit (float) planar RGB pixel.
2207 GIL provides the metafunctions that return the types of standard homogeneous memory-based GIL constructs given a channel type, a layout, and whether
2208 the construct is planar, has a step along the X direction, and is mutable:
2211 template <typename ChannelValue, typename Layout, bool IsPlanar=false, bool IsMutable=true>
2212 struct pixel_reference_type { typedef ... type; };
2214 template <typename Channel, typename Layout>
2215 struct pixel_value_type { typedef ... type; };
2217 template <typename ChannelValue, typename Layout, bool IsPlanar=false, bool IsStep=false, bool IsMutable=true>
2218 struct iterator_type { typedef ... type; };
2220 template <typename ChannelValue, typename Layout, bool IsPlanar=false, bool IsXStep=false, bool IsMutable=true>
2221 struct locator_type { typedef ... type; };
2223 template <typename ChannelValue, typename Layout, bool IsPlanar=false, bool IsXStep=false, bool IsMutable=true>
2224 struct view_type { typedef ... type; };
2226 template <typename ChannelValue, typename Layout, bool IsPlanar=false, typename Alloc=std::allocator<unsigned char> >
2227 struct image_type { typedef ... type; };
2229 template <typename BitField, typename ChannelBitSizeVector, typename Layout, typename Alloc=std::allocator<unsigned char> >
2230 struct packed_image_type { typedef ... type; };
2232 template <typename ChannelBitSizeVector, typename Layout, typename Alloc=std::allocator<unsigned char> >
2233 struct bit_aligned_image_type { typedef ... type; };
2236 There are also helper metafunctions to construct packed and bit-aligned images with up to five channels:
2239 template <typename BitField, unsigned Size1,
2240 typename Layout, typename Alloc=std::allocator<unsigned char> >
2241 struct packed_image1_type { typedef ... type; };
2243 template <typename BitField, unsigned Size1, unsigned Size2,
2244 typename Layout, typename Alloc=std::allocator<unsigned char> >
2245 struct packed_image2_type { typedef ... type; };
2247 template <typename BitField, unsigned Size1, unsigned Size2, unsigned Size3,
2248 typename Layout, typename Alloc=std::allocator<unsigned char> >
2249 struct packed_image3_type { typedef ... type; };
2251 template <typename BitField, unsigned Size1, unsigned Size2, unsigned Size3, unsigned Size4,
2252 typename Layout, typename Alloc=std::allocator<unsigned char> >
2253 struct packed_image4_type { typedef ... type; };
2255 template <typename BitField, unsigned Size1, unsigned Size2, unsigned Size3, unsigned Size4, unsigned Size5,
2256 typename Layout, typename Alloc=std::allocator<unsigned char> >
2257 struct packed_image5_type { typedef ... type; };
2259 template <unsigned Size1,
2260 typename Layout, typename Alloc=std::allocator<unsigned char> >
2261 struct bit_aligned_image1_type { typedef ... type; };
2263 template <unsigned Size1, unsigned Size2,
2264 typename Layout, typename Alloc=std::allocator<unsigned char> >
2265 struct bit_aligned_image2_type { typedef ... type; };
2267 template <unsigned Size1, unsigned Size2, unsigned Size3,
2268 typename Layout, typename Alloc=std::allocator<unsigned char> >
2269 struct bit_aligned_image3_type { typedef ... type; };
2271 template <unsigned Size1, unsigned Size2, unsigned Size3, unsigned Size4,
2272 typename Layout, typename Alloc=std::allocator<unsigned char> >
2273 struct bit_aligned_image4_type { typedef ... type; };
2275 template <unsigned Size1, unsigned Size2, unsigned Size3, unsigned Size4, unsigned Size5,
2276 typename Layout, typename Alloc=std::allocator<unsigned char> >
2277 struct bit_aligned_image5_type { typedef ... type; };
2281 Here \p ChannelValue models \p ChannelValueConcept. We don't need \p IsYStep because GIL's memory-based locator and
2282 view already allow the vertical step to be specified dynamically. Iterators and views can be constructed from a pixel type:
2285 template <typename Pixel, bool IsPlanar=false, bool IsStep=false, bool IsMutable=true>
2286 struct iterator_type_from_pixel { typedef ... type; };
2288 template <typename Pixel, bool IsPlanar=false, bool IsStepX=false, bool IsMutable=true>
2289 struct view_type_from_pixel { typedef ... type; };
2292 Using a heterogeneous pixel type will result in heterogeneous iterators and views. Types can also be constructed from horizontal iterator:
2295 template <typename XIterator>
2296 struct type_from_x_iterator {
2297 typedef ... step_iterator_t;
2298 typedef ... xy_locator_t;
2303 There are metafunctions to construct the type of a construct from an existing type by changing one or more of its properties:
2306 template <typename PixelReference,
2307 typename ChannelValue, typename Layout, typename IsPlanar, typename IsMutable>
2308 struct derived_pixel_reference_type {
2309 typedef ... type; // Models PixelConcept
2312 template <typename Iterator,
2313 typename ChannelValue, typename Layout, typename IsPlanar, typename IsStep, typename IsMutable>
2314 struct derived_iterator_type {
2315 typedef ... type; // Models PixelIteratorConcept
2318 template <typename View,
2319 typename ChannelValue, typename Layout, typename IsPlanar, typename IsXStep, typename IsMutable>
2320 struct derived_view_type {
2321 typedef ... type; // Models ImageViewConcept
2324 template <typename Image,
2325 typename ChannelValue, typename Layout, typename IsPlanar>
2326 struct derived_image_type {
2327 typedef ... type; // Models ImageConcept
2331 You 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
2332 are MPL boolean constants. For example, here is how to create the type of a view just like \p View, but being grayscale and planar:
2335 typedef typename derived_view_type<View, boost::use_default, gray_t, mpl::true_>::type VT;
2338 You can get pixel-related types of any pixel-based GIL constructs (pixels, iterators, locators and views) using the following
2339 metafunctions provided by PixelBasedConcept, HomogeneousPixelBasedConcept and metafunctions built on top of them:
2342 template <typename T> struct color_space_type { typedef ... type; };
2343 template <typename T> struct channel_mapping_type { typedef ... type; };
2344 template <typename T> struct is_planar { typedef ... type; };
2346 // Defined by homogeneous constructs
2347 template <typename T> struct channel_type { typedef ... type; };
2348 template <typename T> struct num_channels { typedef ... type; };
2351 These are metafunctions, some of which return integral types which can be evaluated like this:
2354 BOOST_STATIC_ASSERT(is_planar<rgb8_planar_view_t>::value == true);
2359 GIL also supports type analysis metafunctions of the form:
2360 [pixel_reference/iterator/locator/view/image] + \p "_is_" + [basic/mutable/step]. For example:
2363 if (view_is_mutable<View>::value) {
2368 A <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.
2369 For 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.
2372 \section IO_DG 13. I/O Extension
2374 GIL's I/O extension provides low level image i/o utilities. It supports loading and saving several image formats, each of which requires linking
2375 against the corresponding library:
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,
2378 you 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.
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,
2382 you 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.
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,
2386 you 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.
2389 You don't need to install all these libraries; just the ones you will use.
2390 Here are the I/O APIs for JPEG files (replace \p "jpeg" with \p "tiff" or \p "png" for the APIs of the other libraries):
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
2395 point2<std::ptrdiff_t> jpeg_read_dimensions(const char*);
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
2401 template <typename Img> void jpeg_read_image(const char*, Img&);
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.
2407 template <typename Img> void jpeg_read_and_convert_image(const char*, Img&);
2408 template <typename Img, typename CCV> void jpeg_read_and_convert_image(const char*, Img&, CCV color_converter);
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.
2414 template <typename View> void jpeg_read_view(const char*, const View&);
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.
2419 template <typename View> void jpeg_read_and_convert_view(const char*, const View&);
2420 template <typename View, typename CCV> void jpeg_read_and_convert_view(const char*, const View&, CCV color_converter);
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.
2425 template <typename View> void jpeg_write_view(const char*, const View&);
2427 // Determines whether the given view type is supported for reading
2428 template <typename View> struct jpeg_read_support {
2429 static const bool value = ...;
2432 // Determines whether the given view type is supported for writing
2433 template <typename View> struct jpeg_write_support {
2434 static const bool value = ...;
2438 If you use the dynamic image extension, make sure to include \p "jpeg_dynamic_io.hpp" instead of \p "jpeg_io.hpp".
2439 In addition to the above methods, you have the following overloads dealing with dynamic images:
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.
2445 template <typename Images> void jpeg_read_image(const char*, any_image<Images>&);
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.
2450 template <typename Views> void jpeg_write_view(const char*, any_image_view<Views>&);
2453 All of the above methods have overloads taking \p std::string instead of <tt>const char*</tt>
2456 \section SampleImgCodeDG 14. Sample Code
2458 \subsection PixelLevelExampleDG Pixel-level Sample Code
2460 Here are some operations you can do with pixel values, pointers and references:
2463 rgb8_pixel_t p1(255,0,0); // make a red RGB pixel
2464 bgr8_pixel_t p2 = p1; // RGB and BGR are compatible and the channels will be properly mapped.
2465 assert(p1==p2); // p2 will also be red.
2466 assert(p2[0]!=p1[0]); // operator[] gives physical channel order (as laid down in memory)
2467 assert(semantic_at_c<0>(p1)==semantic_at_c<0>(p2)); // this is how to compare the two red channels
2468 get_color(p1,green_t()) = get_color(p2,blue_t()); // channels can also be accessed by name
2470 const unsigned char* r;
2471 const unsigned char* g;
2472 const unsigned char* b;
2473 rgb8c_planar_ptr_t ptr(r,g,b); // constructing const planar pointer from const pointers to each plane
2475 rgb8c_planar_ref_t ref=*ptr; // just like built-in reference, dereferencing a planar pointer returns a planar reference
2477 p2=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
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)
2487 Here is how to use pixels in generic code:
2490 template <typename GrayPixel, typename RGBPixel>
2491 void gray_to_rgb(const GrayPixel& src, RGBPixel& dst) {
2492 gil_function_requires<PixelConcept<GrayPixel> >();
2493 gil_function_requires<MutableHomogeneousPixelConcept<RGBPixel> >();
2495 typedef typename color_space_type<GrayPixel>::type gray_cs_t;
2496 BOOST_STATIC_ASSERT((boost::is_same<gray_cs_t,gray_t>::value));
2498 typedef typename color_space_type<RGBPixel>::type rgb_cs_t;
2499 BOOST_STATIC_ASSERT((boost::is_same<rgb_cs_t,rgb_t>::value));
2501 typedef typename channel_type<GrayPixel>::type gray_channel_t;
2502 typedef typename channel_type<RGBPixel>::type rgb_channel_t;
2504 gray_channel_t gray = get_color(src,gray_color_t());
2505 static_fill(dst, channel_convert<rgb_channel_t>(gray));
2508 // example use patterns:
2510 // converting gray l-value to RGB and storing at (5,5) in a 16-bit BGR interleaved image:
2511 bgr16_view_t b16(...);
2512 gray_to_rgb(gray8_pixel_t(33), b16(5,5));
2514 // storing the first pixel of an 8-bit grayscale image as the 5-th pixel of 32-bit planar RGB image:
2515 rgb32f_planar_view_t rpv32;
2516 gray8_view_t gv8(...);
2517 gray_to_rgb(*gv8.begin(), rpv32[5]);
2520 As the example shows, both the source and the destination can be references or values, planar or interleaved, as long as they model \p PixelConcept
2521 and \p MutablePixelConcept respectively.
2524 \subsection SafeAreaExampleDG Creating a Copy of an Image with a Safe Buffer
2526 Suppose we want to convolve an image with multiple kernels, the largest of which is 2K+1 x 2K+1 pixels. It may be worth
2527 creating a margin of K pixels around the image borders. Here is how to do it:
2530 template <typename SrcView, // Models ImageViewConcept (the source view)
2531 typename DstImage> // Models ImageConcept (the returned image)
2532 void 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> >();
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());
2543 We allocated a larger image, then we used \p subimage_view to create a shallow image of
2544 its 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
2545 needs initialization, we could have done it with \p fill_pixels. Here is how to simplify this code using
2546 the \p copy_pixels algorithm:
2549 template <typename SrcView, typename DstImage>
2550 void 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()));
2556 (Note also that \p image::recreate is more efficient than \p operator=, as the latter will do an unnecessary copy construction).
2557 Not only does the above example work for planar and interleaved images of any color space and pixel depth; it is also optimized.
2558 GIL overrides \p std::copy - when called on two identical interleaved images with no padding at the end of rows, it
2559 simply does a \p memmove. For planar images it does \p memmove for each channel. If one of the images has padding, (as in
2560 our case) it will try to do \p memmove for each row. When an image has no padding, it will use its lightweight
2561 horizontal iterator (as opposed to the more complex 1D image iterator that has to check for the end of rows).
2562 It choses the fastest method, taking into account both static and run-time parameters.
2564 \subsection HistogramExampleDG Histogram
2566 The histogram can be computed by counting the number of pixel values that fall in each bin.
2567 The following method takes a grayscale (one-dimensional) image view, since only grayscale pixels
2568 are convertible to integers:
2570 template <typename GrayView, typename R>
2571 void grayimage_histogram(const GrayView& img, R& hist) {
2572 for (typename GrayView::iterator it=img.begin(); it!=img.end(); ++it)
2577 Using \p boost::lambda and GIL's \p for_each_pixel algorithm, we can write this more compactly:
2580 template <typename GrayView, typename R>
2581 void grayimage_histogram(const GrayView& v, R& hist) {
2582 for_each_pixel(v, ++var(hist)[_1]);
2586 Where \p for_each_pixel invokes \p std::for_each and \p var and \p _1 are \p boost::lambda constructs.
2587 To compute the luminosity histogram, we call the above method using the grayscale view of an image:
2590 template <typename View, typename R>
2591 void luminosity_histogram(const View& v, R& hist) {
2592 grayimage_histogram(color_converted_view<gray8_pixel_t>(v),hist);
2596 This is how to invoke it:
2599 unsigned char hist[256];
2600 std::fill(hist,hist+256,0);
2601 luminosity_histogram(my_view,hist);
2604 If we want to view the histogram of the second channel of the image in the top left 100x100 area, we call:
2607 grayimage_histogram(nth_channel_view(subimage_view(img,0,0,100,100),1),hist);
2610 No pixels are copied and no extra memory is allocated - the code operates directly on the source pixels, which could
2611 be in any supported color space and channel depth. They could be either planar or interleaved.
2613 \subsection ImageViewsExampleDG Using Image Views
2615 The following code illustrates the power of using image views:
2618 jpeg_read_image("monkey.jpg", img);
2620 step2=subimage_view(step1, 200,300, 150,150);
2621 step3=color_converted_view<rgb8_view_t,gray8_pixel_t>(step2);
2622 step4=rotated180_view(step3);
2623 step5=subsampled_view(step4, 2,1);
2624 jpeg_write_view("monkey_transform.jpg", step5);
2627 The intermediate images are shown here:
2628 \image html monkey_steps.jpg
2630 Notice that no pixels are ever copied. All the work is done inside \p jpeg_write_view.
2631 If we call our \p luminosity_histogram with \p step5 it will do the right thing.
2635 \section ExtendingGIL_DG 15. Extending the Generic Image Library
2637 You can define your own pixel iterators, locators, image views, images, channel types, color spaces and algorithms.
2638 You can make virtual images that live on the disk, inside a jpeg file, somewhere on the internet, or even fully-synthetic images
2639 such as the Mandelbrot set.
2640 As long as they properly model the corresponding concepts, they will work with any existing GIL code.
2641 Most such extensions require no changes to the library and can thus be
2642 supplied in another module.
2644 \subsection NewColorSpacesDG Defining New Color Spaces
2646 Each 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
2647 accordingly. 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
2649 color space (see typedefs.h).
2651 \subsection NewChannelsDG Defining New Channel Types
2653 Most of the time you don't need to do anything special to use a new channel type. You can just use it:
2656 typedef pixel<double,rgb_layout_t> rgb64_pixel_t; // 64 bit RGB pixel
2657 typedef rgb64_pixel* rgb64_pixel_ptr_t;// pointer to 64-bit interleaved data
2658 typedef image_type<double,rgb_layout_t>::type rgb64_image_t; // 64-bit interleaved image
2661 If you want to use your own channel class, you will need to provide a specialization of \p channel_traits for it (see channel.hpp).
2662 If you want to do conversion between your and existing channel types, you will need to provide an overload of \p channel_convert.
2664 \subsection NewColorConversionDG Overloading Color Conversion
2666 Suppose you want to provide your own color conversion. For example, you may want to implement higher quality color conversion using color profiles.
2667 Typically 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
2668 example, how to overload color conversion so that color conversion to gray inverts the result but everything else remains the same:
2671 // make the default use GIL's default
2672 template <typename SrcColorSpace, typename DstColorSpace>
2673 struct my_color_converter_impl
2674 : public default_color_converter_impl<SrcColorSpace,DstColorSpace> {};
2676 // provide specializations only for cases you care about
2677 // (in this case, if the destination is grayscale, invert it)
2678 template <typename SrcColorSpace>
2679 struct 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()));
2687 // create a color converter object that dispatches to your own implementation
2688 struct 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);
2698 GIL's color conversion functions take the color converter as an optional parameter. You can pass your own color converter:
2701 color_converted_view<gray8_pixel_t>(img_view,my_color_converter());
2704 \subsection NewImagesDG Defining New Image Views
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
2707 pixel transformation on dereference. For example, let's look at the implementation of \p color_converted_view (an image factory method that,
2708 given any image view, returns a new, otherwise identical view, except that color conversion is performed on pixel access).
2709 First we need to define a model of \p PixelDereferenceAdaptorConcept; a function object that will be called when we dereference a pixel iterator.
2710 It will call \p color_convert to convert to the destination pixel type:
2713 template <typename SrcConstRefP, // const reference to the source pixel
2714 typename DstP> // Destination pixel value (models PixelValueConcept)
2715 class color_convert_deref_fn {
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);
2725 result_type operator()(argument_type srcP) const {
2727 color_convert(srcP,dstP);
2734 We 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
2735 dereferencing. In our case, it performs color conversion:
2738 template <typename SrcView, typename DstP>
2739 struct color_converted_view_type {
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;
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()); }
2750 Finally our \p color_converted_view code simply creates color-converted view from the source view:
2753 template <typename DstP, typename View> inline
2754 typename color_converted_view_type<View,DstP>::type color_convert_view(const View& src) {
2755 return color_converted_view_type<View,DstP>::make(src);
2759 (The actual color convert view transformation is slightly more complicated, as it takes an optional color conversion object, which
2760 allows users to specify their own color conversion methods).
2761 See the GIL tutorial for an example of creating a virtual image view that defines the Mandelbrot set.
2764 \section TechnicalitiesDG 16. Technicalities
2766 \subsection CreatingReferenceProxyDG Creating a reference proxy
2768 Sometimes it is necessary to create a proxy class that represents a reference to a given object. Examples of these are GIL's reference
2769 to a planar pixel (\p planar_pixel_reference) and GIL's subbyte channel references. Writing a reference proxy class can be tricky. One
2770 problem is that the proxy reference is constructed as a temporary object and returned by value upon dereferencing the iterator:
2773 struct rgb_planar_pixel_iterator {
2774 typedef my_reference_proxy<T> reference;
2775 reference operator*() const { return reference(red,green,blue); }
2779 The problem arises when an iterator is dereferenced directly into a function that takes a mutable pixel:
2782 template <typename Pixel> // Models MutablePixelConcept
2783 void invert_pixel(Pixel& p);
2785 rgb_planar_pixel_iterator myIt;
2786 invert_pixel(*myIt); // compile error!
2789 C++ 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:
2793 template <typename T>
2794 struct my_reference_proxy {
2795 const my_reference_proxy& operator=(const my_reference_proxy& p) const;
2796 const my_reference_proxy* operator->() const { return this; }
2801 - Use different classes to denote mutable and constant reference (maybe based on the constness of the template parameter)
2803 - Define the reference type of your iterator with const qualifier:
2806 struct iterator_traits<rgb_planar_pixel_iterator> {
2807 typedef const my_reference_proxy<T> reference;
2811 A second important issue is providing an overload for \p swap for your reference class. The default \p std::swap will not
2812 work correctly. You must use a real value type as the temporary.
2813 A further complication is that in some implementations of the STL the \p swap function is incorreclty called qualified, as \p std::swap.
2814 The only way for these STL algorithms to use your overload is if you define it in the \p std namespace:
2817 template <typename T>
2818 void swap(my_reference_proxy<T>& x, my_reference_proxy<T>& y) {
2826 Lastly, remember that constructors and copy-constructors of proxy references are always shallow and assignment operators are deep.
2828 We are grateful to Dave Abrahams, Sean Parent and Alex Stepanov for suggesting the above solution.
2831 \section ConclusionDG 17. Conclusion
2833 <p>The Generic Image Library is designed with the following five goals in mind:
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.
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 © 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>