Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / gil / doc / design / examples.rst
1 Examples
2 ========
3
4 .. contents::
5    :local:
6    :depth: 2
7
8 Pixel-level Operations
9 ----------------------
10
11 Here are some operations you can do with pixel values, pixel pointers and
12 pixel references:
13
14 .. code-block:: cpp
15
16   rgb8_pixel_t p1(255,0,0);     // make a red RGB pixel
17   bgr8_pixel_t p2 = p1;         // RGB and BGR are compatible and the channels will be properly mapped.
18   assert(p1==p2);               // p2 will also be red.
19   assert(p2[0]!=p1[0]);         // operator[] gives physical channel order (as laid down in memory)
20   assert(semantic_at_c<0>(p1)==semantic_at_c<0>(p2)); // this is how to compare the two red channels
21   get_color(p1,green_t()) = get_color(p2,blue_t());  // channels can also be accessed by name
22
23   const unsigned char* r;
24   const unsigned char* g;
25   const unsigned char* b;
26   rgb8c_planar_ptr_t ptr(r,g,b); // constructing const planar pointer from const pointers to each plane
27
28   rgb8c_planar_ref_t ref=*ptr;   // just like built-in reference, dereferencing a planar pointer returns a planar reference
29
30   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
31
32   //rgb8_planar_ref_t ref2;      // compile error: References have no default constructors
33   //ref2=*ptr;                   // compile error: Cannot construct non-const reference by dereferencing const pointer
34   //ptr[3]=p1;                   // compile error: Cannot set the fourth pixel through a const pointer
35   //p1 = pixel<float, rgb_layout_t>();// compile error: Incompatible channel depth
36   //p1 = pixel<bits8, rgb_layout_t>();// compile error: Incompatible color space (even though it has the same number of channels)
37   //p1 = pixel<bits8,rgba_layout_t>();// compile error: Incompatible color space (even though it contains red, green and blue channels)
38
39 Here is how to use pixels in generic code:
40
41 .. code-block:: cpp
42
43   template <typename GrayPixel, typename RGBPixel>
44   void gray_to_rgb(const GrayPixel& src, RGBPixel& dst)
45   {
46     gil_function_requires<PixelConcept<GrayPixel> >();
47     gil_function_requires<MutableHomogeneousPixelConcept<RGBPixel> >();
48
49     typedef typename color_space_type<GrayPixel>::type gray_cs_t;
50     static_assert(boost::is_same<gray_cs_t,gray_t>::value, "");
51
52     typedef typename color_space_type<RGBPixel>::type  rgb_cs_t;
53     static_assert(boost::is_same<rgb_cs_t,rgb_t>::value, "");
54
55     typedef typename channel_type<GrayPixel>::type gray_channel_t;
56     typedef typename channel_type<RGBPixel>::type  rgb_channel_t;
57
58     gray_channel_t gray = get_color(src,gray_color_t());
59     static_fill(dst, channel_convert<rgb_channel_t>(gray));
60   }
61
62   // example use patterns:
63
64   // converting gray l-value to RGB and storing at (5,5) in a 16-bit BGR interleaved image:
65   bgr16_view_t b16(...);
66   gray_to_rgb(gray8_pixel_t(33), b16(5,5));
67
68   // storing the first pixel of an 8-bit grayscale image as the 5-th pixel of 32-bit planar RGB image:
69   rgb32f_planar_view_t rpv32;
70   gray8_view_t gv8(...);
71   gray_to_rgb(*gv8.begin(), rpv32[5]);
72
73 As the example shows, both the source and the destination can be references or
74 values, planar or interleaved, as long as they model ``PixelConcept`` and
75 ``MutablePixelConcept`` respectively.
76
77
78 Resizing image canvas
79 ---------------------
80
81 Resizing an image canvas means adding a buffer of pixels around existing
82 pixels. Size of canvas of an image can never be smaller than the image itself.
83
84 Suppose we want to convolve an image with multiple kernels, the largest of
85 which is 2K+1 x 2K+1 pixels. It may be worth creating a margin of K pixels
86 around the image borders. Here is how to do it:
87
88 .. code-block:: cpp
89
90   template <typename SrcView,   // Models ImageViewConcept (the source view)
91           typename DstImage>  // Models ImageConcept     (the returned image)
92   void create_with_margin(const SrcView& src, int k, DstImage& result)
93   {
94     gil_function_requires<ImageViewConcept<SrcView> >();
95     gil_function_requires<ImageConcept<DstImage> >();
96     gil_function_requires<ViewsCompatibleConcept<SrcView, typename DstImage::view_t> >();
97
98     result=DstImage(src.width()+2*k, src.height()+2*k);
99     typename DstImage::view_t centerImg=subimage_view(view(result), k,k,src.width(),src.height());
100     std::copy(src.begin(), src.end(), centerImg.begin());
101   }
102
103 We allocated a larger image, then we used ``subimage_view`` to create a
104 shallow image of its center area of top left corner at (k,k) and of identical
105 size as ``src``, and finally we copied ``src`` into that center image. If the
106 margin needs initialization, we could have done it with ``fill_pixels``. Here
107 is how to simplify this code using the ``copy_pixels`` algorithm:
108
109 .. code-block:: cpp
110
111   template <typename SrcView, typename DstImage>
112   void create_with_margin(const SrcView& src, int k, DstImage& result)
113   {
114     result.recreate(src.width()+2*k, src.height()+2*k);
115     copy_pixels(src, subimage_view(view(result), k,k,src.width(),src.height()));
116   }
117
118 (Note also that ``image::recreate`` is more efficient than ``operator=``, as
119 the latter will do an unnecessary copy construction). Not only does the above
120 example work for planar and interleaved images of any color space and pixel
121 depth; it is also optimized. GIL overrides ``std::copy`` - when called on two
122 identical interleaved images with no padding at the end of rows, it simply
123 does a ``memmove``. For planar images it does ``memmove`` for each channel.
124 If one of the images has padding, (as in our case) it will try to do
125 ``memmove`` for each row. When an image has no padding, it will use its
126 lightweight horizontal iterator (as opposed to the more complex 1D image
127 iterator that has to check for the end of rows). It choses the fastest method,
128 taking into account both static and run-time parameters.
129
130 Histogram
131 ---------
132
133 The histogram can be computed by counting the number of pixel values that fall
134 in each bin. The following method takes a grayscale (one-dimensional) image
135 view, since only grayscale pixels are convertible to integers:
136
137 .. code-block:: cpp
138
139   template <typename GrayView, typename R>
140   void grayimage_histogram(const GrayView& img, R& hist)
141   {
142     for (typename GrayView::iterator it=img.begin(); it!=img.end(); ++it)
143         ++hist[*it];
144   }
145
146 Using ``boost::lambda`` and GIL's ``for_each_pixel`` algorithm, we can write
147 this more compactly:
148
149 .. code-block:: cpp
150
151   template <typename GrayView, typename R>
152   void grayimage_histogram(const GrayView& v, R& hist)
153   {
154     for_each_pixel(v, ++var(hist)[_1]);
155   }
156
157 Where ``for_each_pixel`` invokes ``std::for_each`` and ``var`` and ``_1`` are
158 ``boost::lambda`` constructs. To compute the luminosity histogram, we call the
159 above method using the grayscale view of an image:
160
161 .. code-block:: cpp
162
163   template <typename View, typename R>
164   void luminosity_histogram(const View& v, R& hist)
165   {
166     grayimage_histogram(color_converted_view<gray8_pixel_t>(v),hist);
167   }
168
169 This is how to invoke it:
170
171 .. code-block:: cpp
172
173   unsigned char hist[256];
174   std::fill(hist,hist+256,0);
175   luminosity_histogram(my_view,hist);
176
177 If we want to view the histogram of the second channel of the image in the top
178 left 100x100 area, we call:
179
180 .. code-block:: cpp
181
182   grayimage_histogram(nth_channel_view(subimage_view(img,0,0,100,100),1),hist);
183
184 No pixels are copied and no extra memory is allocated - the code operates
185 directly on the source pixels, which could be in any supported color space and
186 channel depth. They could be either planar or interleaved.
187
188 Using image views
189 -----------------
190
191 The following code illustrates the power of using image views:
192
193 .. code-block:: cpp
194
195   jpeg_read_image("monkey.jpg", img);
196   step1=view(img);
197   step2=subimage_view(step1, 200,300, 150,150);
198   step3=color_converted_view<rgb8_view_t,gray8_pixel_t>(step2);
199   step4=rotated180_view(step3);
200   step5=subsampled_view(step4, 2,1);
201   jpeg_write_view("monkey_transform.jpg", step5);
202
203 The intermediate images are shown here:
204
205 .. image:: ../images/monkey_steps.jpg
206
207 Notice that no pixels are ever copied. All the work is done inside
208 ``jpeg_write_view``. If we call our ``luminosity_histogram`` with
209 ``step5`` it will do the right thing.