1Examples 2======== 3 4.. contents:: 5 :local: 6 :depth: 2 7 8Pixel-level Operations 9---------------------- 10 11Here are some operations you can do with pixel values, pixel pointers and 12pixel 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 39Here 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 73As the example shows, both the source and the destination can be references or 74values, planar or interleaved, as long as they model ``PixelConcept`` and 75``MutablePixelConcept`` respectively. 76 77 78Resizing image canvas 79--------------------- 80 81Resizing an image canvas means adding a buffer of pixels around existing 82pixels. Size of canvas of an image can never be smaller than the image itself. 83 84Suppose we want to convolve an image with multiple kernels, the largest of 85which is 2K+1 x 2K+1 pixels. It may be worth creating a margin of K pixels 86around 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 103We allocated a larger image, then we used ``subimage_view`` to create a 104shallow image of its center area of top left corner at (k,k) and of identical 105size as ``src``, and finally we copied ``src`` into that center image. If the 106margin needs initialization, we could have done it with ``fill_pixels``. Here 107is 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 119the latter will do an unnecessary copy construction). Not only does the above 120example work for planar and interleaved images of any color space and pixel 121depth; it is also optimized. GIL overrides ``std::copy`` - when called on two 122identical interleaved images with no padding at the end of rows, it simply 123does a ``memmove``. For planar images it does ``memmove`` for each channel. 124If 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 126lightweight horizontal iterator (as opposed to the more complex 1D image 127iterator that has to check for the end of rows). It choses the fastest method, 128taking into account both static and run-time parameters. 129 130Histogram 131--------- 132 133The histogram can be computed by counting the number of pixel values that fall 134in each bin. The following method takes a grayscale (one-dimensional) image 135view, 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 146Using ``boost::lambda`` and GIL's ``for_each_pixel`` algorithm, we can write 147this 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 157Where ``for_each_pixel`` invokes ``std::for_each`` and ``var`` and ``_1`` are 158``boost::lambda`` constructs. To compute the luminosity histogram, we call the 159above 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 169This 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 177If we want to view the histogram of the second channel of the image in the top 178left 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 184No pixels are copied and no extra memory is allocated - the code operates 185directly on the source pixels, which could be in any supported color space and 186channel depth. They could be either planar or interleaved. 187 188Using image views 189----------------- 190 191The 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 203The intermediate images are shown here: 204 205.. image:: ../images/monkey_steps.jpg 206 207Notice 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. 210