Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / gil / doc / design / pixel.rst
1 Pixel
2 =====
3
4 .. contents::
5    :local:
6    :depth: 2
7
8 Overview
9 --------
10
11 A pixel is a set of channels defining the color at a given point in an
12 image. Conceptually, a pixel is little more than a color base whose
13 elements model ``ChannelConcept``. All properties of pixels inherit
14 from color bases: pixels may be *homogeneous* if all of their channels
15 have the same type; otherwise they are called *heterogeneous*. The
16 channels of a pixel may be addressed using semantic or physical
17 indexing, or by color; all color-base algorithms work on pixels as
18 well. Two pixels are *compatible* if their color spaces are the same
19 and their channels, paired semantically, are compatible. Note that
20 constness, memory organization and reference/value are ignored. For
21 example, an 8-bit RGB planar reference is compatible to a constant
22 8-bit BGR interleaved pixel value. Most pairwise pixel operations
23 (copy construction, assignment, equality, etc.) are only defined for
24 compatible pixels.
25
26 Pixels (as well as other GIL constructs built on pixels, such as
27 iterators, locators, views and images) must provide metafunctions to
28 access their color space, channel mapping, number of channels, and
29 (for homogeneous pixels) the channel type:
30
31 .. code-block:: cpp
32
33   concept PixelBasedConcept<typename T>
34   {
35     typename color_space_type<T>;
36         where Metafunction<color_space_type<T> >;
37         where ColorSpaceConcept<color_space_type<T>::type>;
38     typename channel_mapping_type<T>;
39         where Metafunction<channel_mapping_type<T> >;
40         where ChannelMappingConcept<channel_mapping_type<T>::type>;
41     typename is_planar<T>;
42         where Metafunction<is_planar<T> >;
43         where SameType<is_planar<T>::type, bool>;
44   };
45
46   concept HomogeneousPixelBasedConcept<PixelBasedConcept T>
47   {
48     typename channel_type<T>;
49         where Metafunction<channel_type<T> >;
50         where ChannelConcept<channel_type<T>::type>;
51   };
52
53 Pixels model the following concepts:
54
55 .. code-block:: cpp
56
57   concept PixelConcept<typename P> : ColorBaseConcept<P>, PixelBasedConcept<P>
58   {
59     where is_pixel<P>::value==true;
60     // where for each K [0..size<P>::value-1]:
61     //      ChannelConcept<kth_element_type<K> >;
62
63     typename value_type;       where PixelValueConcept<value_type>;
64     typename reference;        where PixelConcept<reference>;
65     typename const_reference;  where PixelConcept<const_reference>;
66     static const bool P::is_mutable;
67
68     template <PixelConcept P2> where { PixelConcept<P,P2> }
69         P::P(P2);
70     template <PixelConcept P2> where { PixelConcept<P,P2> }
71         bool operator==(const P&, const P2&);
72     template <PixelConcept P2> where { PixelConcept<P,P2> }
73         bool operator!=(const P&, const P2&);
74   };
75
76   concept MutablePixelConcept<typename P> : PixelConcept<P>, MutableColorBaseConcept<P>
77   {
78     where is_mutable==true;
79   };
80
81   concept HomogeneousPixelConcept<PixelConcept P> : HomogeneousColorBaseConcept<P>, HomogeneousPixelBasedConcept<P>
82   {
83     P::template element_const_reference_type<P>::type operator[](P p, std::size_t i) const { return dynamic_at_c(P,i); }
84   };
85
86   concept MutableHomogeneousPixelConcept<MutablePixelConcept P> : MutableHomogeneousColorBaseConcept<P>
87   {
88     P::template element_reference_type<P>::type operator[](P p, std::size_t i) { return dynamic_at_c(p,i); }
89   };
90
91   concept PixelValueConcept<typename P> : PixelConcept<P>, Regular<P>
92   {
93     where SameType<value_type,P>;
94   };
95
96   concept PixelsCompatibleConcept<PixelConcept P1, PixelConcept P2> : ColorBasesCompatibleConcept<P1,P2>
97   {
98     // where for each K [0..size<P1>::value):
99     //    ChannelsCompatibleConcept<kth_semantic_element_type<P1,K>::type, kth_semantic_element_type<P2,K>::type>;
100   };
101
102 A pixel is *convertible* to a second pixel if it is possible to
103 approximate its color in the form of the second pixel. Conversion is
104 an explicit, non-symmetric and often lossy operation (due to both
105 channel and color space approximation). Convertibility requires
106 modeling the following concept:
107
108 .. code-block:: cpp
109
110   template <PixelConcept SrcPixel, MutablePixelConcept DstPixel>
111   concept PixelConvertibleConcept
112   {
113     void color_convert(const SrcPixel&, DstPixel&);
114   };
115
116 The distinction between ``PixelConcept`` and ``PixelValueConcept`` is
117 analogous to that for channels and color bases - pixel reference proxies model
118 both, but only pixel values model the latter.
119
120 .. seealso::
121
122   - `PixelBasedConcept<P> <reference/structboost_1_1gil_1_1_pixel_based_concept.html>`_
123   - `PixelConcept<Pixel> <reference/structboost_1_1gil_1_1_pixel_concept.html>`_
124   - `MutablePixelConcept<Pixel> <reference/structboost_1_1gil_1_1_mutable_pixel_concept.html>`_
125   - `PixelValueConcept<Pixel> <reference/structboost_1_1gil_1_1_pixel_value_concept.html>`_
126   - `HomogeneousPixelConcept<Pixel> <reference/structboost_1_1gil_1_1_homogeneous_pixel_based_concept.html>`_
127   - `MutableHomogeneousPixelConcept<Pixel> <reference/structboost_1_1gil_1_1_mutable_homogeneous_pixel_concept.html>`_
128   - `HomogeneousPixelValueConcept<Pixel> <reference/structboost_1_1gil_1_1_homogeneous_pixel_value_concept.html>`_
129   - `PixelsCompatibleConcept<Pixel1, Pixel2> <reference/structboost_1_1gil_1_1_pixels_compatible_concept.html>`_
130   - `PixelConvertibleConcept<SrcPixel, DstPixel> <reference/structboost_1_1gil_1_1_pixel_convertible_concept.html>`_
131
132 Models
133 ------
134
135 The most commonly used pixel is a homogeneous pixel whose values are
136 together in memory. For this purpose GIL provides the struct
137 ``pixel``, templated over the channel value and layout:
138
139 .. code-block:: cpp
140
141   // models HomogeneousPixelValueConcept
142   template <typename ChannelValue, typename Layout> struct pixel;
143
144   // Those typedefs are already provided by GIL
145   typedef pixel<bits8, rgb_layout_t> rgb8_pixel_t;
146   typedef pixel<bits8, bgr_layout_t> bgr8_pixel_t;
147
148   bgr8_pixel_t bgr8(255,0,0);     // pixels can be initialized with the channels directly
149   rgb8_pixel_t rgb8(bgr8);        // compatible pixels can also be copy-constructed
150
151   rgb8 = bgr8;            // assignment and equality is defined between compatible pixels
152   assert(rgb8 == bgr8);   // assignment and equality operate on the semantic channels
153
154   // The first physical channels of the two pixels are different
155   assert(at_c<0>(rgb8) != at_c<0>(bgr8));
156   assert(dynamic_at_c(bgr8,0) != dynamic_at_c(rgb8,0));
157   assert(rgb8[0] != bgr8[0]); // same as above (but operator[] is defined for pixels only)
158
159 Planar pixels have their channels distributed in memory. While they share the
160 same value type (``pixel``) with interleaved pixels, their reference type is a
161 proxy class containing references to each of the channels.
162 This is implemented with the struct ``planar_pixel_reference``:
163
164 .. code-block:: cpp
165
166   // models HomogeneousPixel
167   template <typename ChannelReference, typename ColorSpace> struct planar_pixel_reference;
168
169   // Define the type of a mutable and read-only reference. (These typedefs are already provided by GIL)
170   typedef planar_pixel_reference<      bits8&,rgb_t> rgb8_planar_ref_t;
171   typedef planar_pixel_reference<const bits8&,rgb_t> rgb8c_planar_ref_t;
172
173 Note that, unlike the ``pixel`` struct, planar pixel references are templated
174 over the color space, not over the pixel layout. They always use a canonical
175 channel ordering. Ordering of their elements is unnecessary because their
176 elements are references to the channels.
177
178 Sometimes the channels of a pixel may not be byte-aligned. For example an RGB
179 pixel in '5-5-6' format is a 16-bit pixel whose red, green and blue channels
180 occupy bits [0..4],[5..9] and [10..15] respectively. GIL provides a model for
181 such packed pixel formats:
182
183 .. code-block:: cpp
184
185   // define an rgb565 pixel
186   typedef packed_pixel_type<uint16_t, mpl::vector3_c<unsigned,5,6,5>, rgb_layout_t>::type rgb565_pixel_t;
187
188   function_requires<PixelValueConcept<rgb565_pixel_t> >();
189   static_assert(sizeof(rgb565_pixel_t) == 2, "");
190
191   // define a bgr556 pixel
192   typedef packed_pixel_type<uint16_t, mpl::vector3_c<unsigned,5,6,5>, bgr_layout_t>::type bgr556_pixel_t;
193
194   function_requires<PixelValueConcept<bgr556_pixel_t> >();
195
196   // rgb565 is compatible with bgr556.
197   function_requires<PixelsCompatibleConcept<rgb565_pixel_t,bgr556_pixel_t> >();
198
199 In some cases, the pixel itself may not be byte aligned. For example,
200 consider an RGB pixel in '2-3-2' format. Its size is 7 bits. GIL
201 refers to such pixels, pixel iterators and images as
202 "bit-aligned". Bit-aligned pixels (and images) are more complex than
203 packed ones. Since packed pixels are byte-aligned, we can use a C++
204 reference as the reference type to a packed pixel, and a C pointer as
205 an x_iterator over a row of packed pixels. For bit-aligned constructs
206 we need a special reference proxy class (bit_aligned_pixel_reference)
207 and iterator class (bit_aligned_pixel_iterator). The value type of
208 bit-aligned pixels is a packed_pixel. Here is how to use bit_aligned
209 pixels and pixel iterators:
210
211 .. code-block:: cpp
212
213   // Mutable reference to a BGR232 pixel
214   typedef const bit_aligned_pixel_reference<unsigned char, mpl::vector3_c<unsigned,2,3,2>, bgr_layout_t, true>  bgr232_ref_t;
215
216   // A mutable iterator over BGR232 pixels
217   typedef bit_aligned_pixel_iterator<bgr232_ref_t> bgr232_ptr_t;
218
219   // BGR232 pixel value. It is a packed_pixel of size 1 byte. (The last bit is unused)
220   typedef std::iterator_traits<bgr232_ptr_t>::value_type bgr232_pixel_t;
221   static_assert(sizeof(bgr232_pixel_t) == 1, "");
222
223   bgr232_pixel_t red(0,0,3); // = 0RRGGGBB, = 01100000 = 0x60
224
225   // a buffer of 7 bytes fits exactly 8 BGR232 pixels.
226   unsigned char pix_buffer[7];
227   std::fill(pix_buffer,pix_buffer+7,0);
228
229   // Fill the 8 pixels with red
230   bgr232_ptr_t pix_it(&pix_buffer[0],0);  // start at bit 0 of the first pixel
231   for (int i=0; i<8; ++i)
232   {
233     *pix_it++ = red;
234   }
235   // Result: 0x60 0x30 0x11 0x0C 0x06 0x83 0xC1
236
237 Algorithms
238 ----------
239
240 Since pixels model ``ColorBaseConcept`` and ``PixelBasedConcept`` all
241 algorithms and metafunctions of color bases can work with them as well:
242
243 .. code-block:: cpp
244
245   // This is how to access the first semantic channel (red)
246   assert(semantic_at_c<0>(rgb8) == semantic_at_c<0>(bgr8));
247
248   // This is how to access the red channel by name
249   assert(get_color<red_t>(rgb8) == get_color<red_t>(bgr8));
250
251   // This is another way of doing it (some compilers don't like the first one)
252   assert(get_color(rgb8,red_t()) == get_color(bgr8,red_t()));
253
254   // This is how to use the PixelBasedConcept metafunctions
255   BOOST_MPL_ASSERT(num_channels<rgb8_pixel_t>::value == 3);
256   BOOST_MPL_ASSERT((is_same<channel_type<rgb8_pixel_t>::type, bits8>));
257   BOOST_MPL_ASSERT((is_same<color_space_type<bgr8_pixel_t>::type, rgb_t> ));
258   BOOST_MPL_ASSERT((is_same<channel_mapping_type<bgr8_pixel_t>::type, mpl::vector3_c<int,2,1,0> > ));
259
260   // Pixels contain just the three channels and nothing extra
261   BOOST_MPL_ASSERT(sizeof(rgb8_pixel_t)==3);
262
263   rgb8_planar_ref_t ref(bgr8);    // copy construction is allowed from a compatible mutable pixel type
264
265   get_color<red_t>(ref) = 10;     // assignment is ok because the reference is mutable
266   assert(get_color<red_t>(bgr8)==10);  // references modify the value they are bound to
267
268   // Create a zero packed pixel and a full regular unpacked pixel.
269   rgb565_pixel_t r565;
270   rgb8_pixel_t rgb_full(255,255,255);
271
272   // Convert all channels of the unpacked pixel to the packed one & assert the packed one is full
273   get_color(r565,red_t())   = channel_convert<rgb565_channel0_t>(get_color(rgb_full,red_t()));
274   get_color(r565,green_t()) = channel_convert<rgb565_channel1_t>(get_color(rgb_full,green_t()));
275   get_color(r565,blue_t())  = channel_convert<rgb565_channel2_t>(get_color(rgb_full,blue_t()));
276   assert(r565 == rgb565_pixel_t((uint16_t)65535));
277
278 GIL also provides the ``color_convert`` algorithm to convert between pixels of
279 different color spaces and channel types:
280
281 .. code-block:: cpp
282
283   rgb8_pixel_t red_in_rgb8(255,0,0);
284   cmyk16_pixel_t red_in_cmyk16;
285   color_convert(red_in_rgb8,red_in_cmyk16);