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