image_view.rst 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. Image View
  2. ==========
  3. .. contents::
  4. :local:
  5. :depth: 2
  6. Overview
  7. --------
  8. An image view is a generalization of STL range concept to multiple dimensions.
  9. Similar to ranges (and iterators), image views are shallow, don't own the
  10. underlying data and don't propagate their constness over the data.
  11. For example, a constant image view cannot be resized, but may allow modifying
  12. the pixels. For pixel-immutable operations, use constant-value image view
  13. (also called non-mutable image view). Most general N-dimensional views satisfy
  14. the following concept:
  15. .. code-block:: cpp
  16. concept RandomAccessNDImageViewConcept<Regular View>
  17. {
  18. typename value_type; // for pixel-based views, the pixel type
  19. typename reference; // result of dereferencing
  20. typename difference_type; // result of operator-(iterator,iterator) (1-dimensional!)
  21. typename const_t; where RandomAccessNDImageViewConcept<View>; // same as View, but over immutable values
  22. typename point_t; where PointNDConcept<point_t>; // N-dimensional point
  23. typename locator; where RandomAccessNDLocatorConcept<locator>; // N-dimensional locator.
  24. typename iterator; where RandomAccessTraversalConcept<iterator>; // 1-dimensional iterator over all values
  25. typename reverse_iterator; where RandomAccessTraversalConcept<reverse_iterator>;
  26. typename size_type; // the return value of size()
  27. // Equivalent to RandomAccessNDLocatorConcept::axis
  28. template <size_t D> struct axis {
  29. typename coord_t = point_t::axis<D>::coord_t;
  30. typename iterator; where RandomAccessTraversalConcept<iterator>; // iterator along D-th axis.
  31. where SameType<coord_t, iterator::difference_type>;
  32. where SameType<iterator::value_type,value_type>;
  33. };
  34. // Defines the type of a view similar to this type, except it invokes Deref upon dereferencing
  35. template <PixelDereferenceAdaptorConcept Deref> struct add_deref {
  36. typename type; where RandomAccessNDImageViewConcept<type>;
  37. static type make(const View& v, const Deref& deref);
  38. };
  39. static const size_t num_dimensions = point_t::num_dimensions;
  40. // Create from a locator at the top-left corner and dimensions
  41. View::View(const locator&, const point_type&);
  42. size_type View::size() const; // total number of elements
  43. reference operator[](View, const difference_type&) const; // 1-dimensional reference
  44. iterator View::begin() const;
  45. iterator View::end() const;
  46. reverse_iterator View::rbegin() const;
  47. reverse_iterator View::rend() const;
  48. iterator View::at(const point_t&);
  49. point_t View::dimensions() const; // number of elements along each dimension
  50. bool View::is_1d_traversable() const; // Does an iterator over the first dimension visit each value?
  51. // iterator along a given dimension starting at a given point
  52. template <size_t D> View::axis<D>::iterator View::axis_iterator(const point_t&) const;
  53. reference operator()(View,const point_t&) const;
  54. };
  55. concept MutableRandomAccessNDImageViewConcept<RandomAccessNDImageViewConcept View>
  56. {
  57. where Mutable<reference>;
  58. };
  59. Two-dimensional image views have the following extra requirements:
  60. .. code-block:: cpp
  61. concept RandomAccess2DImageViewConcept<RandomAccessNDImageViewConcept View>
  62. {
  63. where num_dimensions==2;
  64. typename x_iterator = axis<0>::iterator;
  65. typename y_iterator = axis<1>::iterator;
  66. typename x_coord_t = axis<0>::coord_t;
  67. typename y_coord_t = axis<1>::coord_t;
  68. typename xy_locator = locator;
  69. x_coord_t View::width() const;
  70. y_coord_t View::height() const;
  71. // X-navigation
  72. x_iterator View::x_at(const point_t&) const;
  73. x_iterator View::row_begin(y_coord_t) const;
  74. x_iterator View::row_end (y_coord_t) const;
  75. // Y-navigation
  76. y_iterator View::y_at(const point_t&) const;
  77. y_iterator View::col_begin(x_coord_t) const;
  78. y_iterator View::col_end (x_coord_t) const;
  79. // navigating in 2D
  80. xy_locator View::xy_at(const point_t&) const;
  81. // (x,y) versions of all methods taking point_t
  82. View::View(x_coord_t,y_coord_t,const locator&);
  83. iterator View::at(x_coord_t,y_coord_t) const;
  84. reference operator()(View,x_coord_t,y_coord_t) const;
  85. xy_locator View::xy_at(x_coord_t,y_coord_t) const;
  86. x_iterator View::x_at(x_coord_t,y_coord_t) const;
  87. y_iterator View::y_at(x_coord_t,y_coord_t) const;
  88. };
  89. concept MutableRandomAccess2DImageViewConcept<RandomAccess2DImageViewConcept View>
  90. : MutableRandomAccessNDImageViewConcept<View> {};
  91. Image views that GIL typically uses operate on value types that model
  92. ``PixelValueConcept`` and have some additional requirements:
  93. .. code-block:: cpp
  94. concept ImageViewConcept<RandomAccess2DImageViewConcept View>
  95. {
  96. where PixelValueConcept<value_type>;
  97. where PixelIteratorConcept<x_iterator>;
  98. where PixelIteratorConcept<y_iterator>;
  99. where x_coord_t == y_coord_t;
  100. typename coord_t = x_coord_t;
  101. std::size_t View::num_channels() const;
  102. };
  103. concept MutableImageViewConcept<ImageViewConcept View>
  104. : MutableRandomAccess2DImageViewConcept<View>
  105. {};
  106. Two image views are compatible if they have compatible pixels and the same
  107. number of dimensions:
  108. .. code-block:: cpp
  109. concept ViewsCompatibleConcept<ImageViewConcept V1, ImageViewConcept V2>
  110. {
  111. where PixelsCompatibleConcept<V1::value_type, V2::value_type>;
  112. where V1::num_dimensions == V2::num_dimensions;
  113. };
  114. Compatible views must also have the same dimensions (i.e. the same width and
  115. height). Many algorithms taking multiple views require that they be pairwise
  116. compatible.
  117. .. seealso::
  118. - `RandomAccessNDImageViewConcept<View> <reference/structboost_1_1gil_1_1_random_access_n_d_image_view_concept.html>`_
  119. - `MutableRandomAccessNDImageViewConcept<View> <reference/structboost_1_1gil_1_1_mutable_random_access_n_d_image_view_concept.html>`_
  120. - `RandomAccess2DImageViewConcept<View> <reference/structboost_1_1gil_1_1_random_access2_d_image_view_concept.html>`_
  121. - `MutableRandomAccess2DImageViewConcept<View> <reference/structboost_1_1gil_1_1_mutable_random_access2_d_image_view_concept.html>`_
  122. - `ImageViewConcept<View> <reference/structboost_1_1gil_1_1_image_view_concept.html>`_
  123. - `MutableImageViewConcept<View> <reference/structboost_1_1gil_1_1_mutable_image_view_concept.html>`_
  124. - `ViewsCompatibleConcept<View1,View2> <reference/structboost_1_1gil_1_1_views_compatible_concept.html>`_
  125. Models
  126. ------
  127. GIL provides a model for ``ImageViewConcept`` called ``image_view``. It is
  128. templated over a model of ``PixelLocatorConcept``. (If instantiated with a
  129. model of ``MutablePixelLocatorConcept``, it models
  130. ``MutableImageViewConcept``). Synopsis:
  131. .. code-block:: cpp
  132. // Locator models PixelLocatorConcept, could be MutablePixelLocatorConcept
  133. template <typename Locator>
  134. class image_view
  135. {
  136. public:
  137. typedef Locator xy_locator;
  138. typedef iterator_from_2d<Locator> iterator;
  139. ...
  140. private:
  141. xy_locator _pixels; // 2D pixel locator at the top left corner of the image view range
  142. point_t _dimensions; // width and height
  143. };
  144. Image views are lightweight objects. A regular interleaved view is typically
  145. 16 bytes long - two integers for the width and height (inside dimensions) one
  146. for the number of bytes between adjacent rows (inside the locator) and one
  147. pointer to the beginning of the pixel block.
  148. Algorithms
  149. ----------
  150. GIL provides algorithms constructing views from raw data or other views.
  151. Creating Views from Raw Pixels
  152. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  153. Standard image views can be constructed from raw data of any supported color
  154. space, bit depth, channel ordering or planar vs. interleaved structure.
  155. Interleaved views are constructed using ``interleaved_view``, supplying the
  156. image dimensions, number of bytes per row, and a pointer to the first pixel:
  157. .. code-block:: cpp
  158. // Iterator models pixel iterator (e.g. rgb8_ptr_t or rgb8c_ptr_t)
  159. template <typename Iterator>
  160. image_view<...> interleaved_view(ptrdiff_t width, ptrdiff_t height, Iterator pixels, ptrdiff_t rowsize)
  161. Planar views are defined for every color space and take each plane separately.
  162. Here is the RGB one:
  163. .. code-block:: cpp
  164. // Iterator models channel iterator (e.g. bits8* or bits8 const*)
  165. template <typename Iterator>
  166. image_view<...> planar_rgb_view(
  167. ptrdiff_t width, ptrdiff_t height,
  168. IC r, IC g, IC b, ptrdiff_t rowsize);
  169. Note that the supplied pixel/channel iterators could be constant (read-only),
  170. in which case the returned view is a constant-value (immutable) view.
  171. Creating Image Views from Other Image Views
  172. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  173. It is possible to construct one image view from another by changing some
  174. policy of how image data is interpreted. The result could be a view whose type
  175. is derived from the type of the source. GIL uses the following metafunctions
  176. to get the derived types:
  177. .. code-block:: cpp
  178. // Some result view types
  179. template <typename View>
  180. struct dynamic_xy_step_type : public dynamic_y_step_type<typename dynamic_x_step_type<View>::type> {};
  181. template <typename View>
  182. struct dynamic_xy_step_transposed_type : public dynamic_xy_step_type<typename transposed_type<View>::type> {};
  183. // color and bit depth converted view to match pixel type P
  184. template <typename SrcView, // Models ImageViewConcept
  185. typename DstP, // Models PixelConcept
  186. typename ColorConverter=gil::default_color_converter>
  187. struct color_converted_view_type
  188. {
  189. typedef ... type; // image view adaptor with value type DstP, over SrcView
  190. };
  191. // single-channel view of the N-th channel of a given view
  192. template <typename SrcView>
  193. struct nth_channel_view_type
  194. {
  195. typedef ... type;
  196. };
  197. GIL Provides the following view transformations:
  198. .. code-block:: cpp
  199. // flipped upside-down, left-to-right, transposed view
  200. template <typename View> typename dynamic_y_step_type<View>::type flipped_up_down_view(const View& src);
  201. template <typename View> typename dynamic_x_step_type<View>::type flipped_left_right_view(const View& src);
  202. template <typename View> typename dynamic_xy_step_transposed_type<View>::type transposed_view(const View& src);
  203. // rotations
  204. template <typename View> typename dynamic_xy_step_type<View>::type rotated180_view(const View& src);
  205. template <typename View> typename dynamic_xy_step_transposed_type<View>::type rotated90cw_view(const View& src);
  206. template <typename View> typename dynamic_xy_step_transposed_type<View>::type rotated90ccw_view(const View& src);
  207. // view of an axis-aligned rectangular area within an image
  208. template <typename View> View subimage_view(const View& src,
  209. const View::point_t& top_left, const View::point_t& dimensions);
  210. // subsampled view (skipping pixels in X and Y)
  211. template <typename View> typename dynamic_xy_step_type<View>::type subsampled_view(const View& src,
  212. const View::point_t& step);
  213. template <typename View, typename P>
  214. color_converted_view_type<View,P>::type color_converted_view(const View& src);
  215. template <typename View, typename P, typename CCV> // with a custom color converter
  216. color_converted_view_type<View,P,CCV>::type color_converted_view(const View& src);
  217. template <typename View>
  218. nth_channel_view_type<View>::view_t nth_channel_view(const View& view, int n);
  219. The implementations of most of these view factory methods are straightforward.
  220. Here is, for example, how the flip views are implemented. The flip upside-down
  221. view creates a view whose first pixel is the bottom left pixel of the original
  222. view and whose y-step is the negated step of the source.
  223. .. code-block:: cpp
  224. template <typename View>
  225. typename dynamic_y_step_type<View>::type flipped_up_down_view(const View& src)
  226. {
  227. gil_function_requires<ImageViewConcept<View> >();
  228. typedef typename dynamic_y_step_type<View>::type RView;
  229. return RView(src.dimensions(),typename RView::xy_locator(src.xy_at(0,src.height()-1),-1));
  230. }
  231. The call to ``gil_function_requires`` ensures (at compile time) that the
  232. template parameter is a valid model of ``ImageViewConcept``. Using it
  233. generates easier to track compile errors, creates no extra code and has no
  234. run-time performance impact. We are using the ``boost::concept_check library``,
  235. but wrapping it in ``gil_function_requires``, which performs the check if the
  236. ``BOOST_GIL_USE_CONCEPT_CHECK`` is set. It is unset by default, because there
  237. is a significant increase in compile time when using concept checks. We will
  238. skip ``gil_function_requires`` in the code examples in this guide for the sake
  239. of succinctness.
  240. Image views can be freely composed (see section :doc:`metafunctions` for
  241. explanation of the typedefs ``rgb16_image_t`` and ``gray16_step_view_t)``:
  242. .. code-block:: cpp
  243. rgb16_image_t img(100,100); // an RGB interleaved image
  244. // grayscale view over the green (index 1) channel of img
  245. gray16_step_view_t green=nth_channel_view(view(img),1);
  246. // 50x50 view of the green channel of img, upside down and taking every other pixel in X and in Y
  247. gray16_step_view_t ud_fud=flipped_up_down_view(subsampled_view(green,2,2));
  248. As previously stated, image views are fast, constant-time, shallow views over
  249. the pixel data. The above code does not copy any pixels; it operates on the
  250. pixel data allocated when ``img`` was created.
  251. STL-Style Algorithms on Image Views
  252. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  253. Image views provide 1D iteration of their pixels via ``begin()`` and ``end()``
  254. methods, which makes it possible to use STL algorithms with them. However,
  255. using nested loops over X and Y is in many cases more efficient.
  256. The algorithms in this section resemble STL algorithms, but they abstract away
  257. the nested loops and take views (as opposed to ranges) as input.
  258. .. code-block:: cpp
  259. // Equivalents of std::copy and std::uninitialized_copy
  260. // where ImageViewConcept<V1>, MutableImageViewConcept<V2>, ViewsCompatibleConcept<V1,V2>
  261. template <typename V1, typename V2>
  262. void copy_pixels(const V1& src, const V2& dst);
  263. template <typename V1, typename V2>
  264. void uninitialized_copy_pixels(const V1& src, const V2& dst);
  265. // Equivalents of std::fill and std::uninitialized_fill
  266. // where MutableImageViewConcept<V>, PixelConcept<Value>, PixelsCompatibleConcept<Value,V::value_type>
  267. template <typename V, typename Value>
  268. void fill_pixels(const V& dst, const Value& val);
  269. template <typename V, typename Value>
  270. void uninitialized_fill_pixels(const V& dst, const Value& val);
  271. // Equivalent of std::for_each
  272. // where ImageViewConcept<V>, boost::UnaryFunctionConcept<F>
  273. // where PixelsCompatibleConcept<V::reference, F::argument_type>
  274. template <typename V, typename F>
  275. F for_each_pixel(const V& view, F fun);
  276. template <typename V, typename F>
  277. F for_each_pixel_position(const V& view, F fun);
  278. // Equivalent of std::generate
  279. // where MutableImageViewConcept<V>, boost::UnaryFunctionConcept<F>
  280. // where PixelsCompatibleConcept<V::reference, F::argument_type>
  281. template <typename V, typename F>
  282. void generate_pixels(const V& dst, F fun);
  283. // Equivalent of std::transform with one source
  284. // where ImageViewConcept<V1>, MutableImageViewConcept<V2>
  285. // where boost::UnaryFunctionConcept<F>
  286. // where PixelsCompatibleConcept<V1::const_reference, F::argument_type>
  287. // where PixelsCompatibleConcept<F::result_type, V2::reference>
  288. template <typename V1, typename V2, typename F>
  289. F transform_pixels(const V1& src, const V2& dst, F fun);
  290. template <typename V1, typename V2, typename F>
  291. F transform_pixel_positions(const V1& src, const V2& dst, F fun);
  292. // Equivalent of std::transform with two sources
  293. // where ImageViewConcept<V1>, ImageViewConcept<V2>, MutableImageViewConcept<V3>
  294. // where boost::BinaryFunctionConcept<F>
  295. // where PixelsCompatibleConcept<V1::const_reference, F::first_argument_type>
  296. // where PixelsCompatibleConcept<V2::const_reference, F::second_argument_type>
  297. // where PixelsCompatibleConcept<F::result_type, V3::reference>
  298. template <typename V1, typename V2, typename V3, typename F>
  299. F transform_pixels(const V1& src1, const V2& src2, const V3& dst, F fun);
  300. template <typename V1, typename V2, typename V3, typename F>
  301. F transform_pixel_positions(const V1& src1, const V2& src2, const V3& dst, F fun);
  302. // Copies a view into another, color converting the pixels if needed, with the default or user-defined color converter
  303. // where ImageViewConcept<V1>, MutableImageViewConcept<V2>
  304. // V1::value_type must be convertible to V2::value_type.
  305. template <typename V1, typename V2>
  306. void copy_and_convert_pixels(const V1& src, const V2& dst);
  307. template <typename V1, typename V2, typename ColorConverter>
  308. void copy_and_convert_pixels(const V1& src, const V2& dst, ColorConverter ccv);
  309. // Equivalent of std::equal
  310. // where ImageViewConcept<V1>, ImageViewConcept<V2>, ViewsCompatibleConcept<V1,V2>
  311. template <typename V1, typename V2>
  312. bool equal_pixels(const V1& view1, const V2& view2);
  313. Algorithms that take multiple views require that they have the same
  314. dimensions. ``for_each_pixel_position`` and ``transform_pixel_positions`` pass
  315. pixel locators, as opposed to pixel references, to their function objects.
  316. This allows for writing algorithms that use pixel neighbours, as the tutorial
  317. demonstrates.
  318. Most of these algorithms check whether the image views are 1D-traversable.
  319. A 1D-traversable image view has no gaps at the end of the rows.
  320. In other words, if an x_iterator of that view is advanced past the last pixel
  321. in a row it will move to the first pixel of the next row. When image views are
  322. 1D-traversable, the algorithms use a single loop and run more efficiently.
  323. If one or more of the input views are not 1D-traversable, the algorithms
  324. fall-back to an X-loop nested inside a Y-loop.
  325. The algorithms typically delegate the work to their corresponding STL
  326. algorithms. For example, ``copy_pixels`` calls ``std::copy`` either for each
  327. row, or, when the images are 1D-traversable, once for all pixels.
  328. In addition, overloads are sometimes provided for the STL algorithms.
  329. For example, ``std::copy`` for planar iterators is overloaded to perform
  330. ``std::copy`` for each of the planes. ``std::copy`` over bitwise-copyable
  331. pixels results in ``std::copy`` over unsigned char, which STL
  332. implements via ``memmove``.
  333. As a result ``copy_pixels`` may result in a single call to ``memmove`` for
  334. interleaved 1D-traversable views, or one per each plane of planar
  335. 1D-traversable views, or one per each row of interleaved non-1D-traversable
  336. images, etc.
  337. GIL also provides some beta-versions of image processing algorithms, such as
  338. resampling and convolution in a numerics extension available on
  339. http://stlab.adobe.com/gil/download.html. This code is in early stage of
  340. development and is not optimized for speed