examples.rst 7.9 KB

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