image_view.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. //
  2. // Copyright 2005-2007 Adobe Systems Incorporated
  3. //
  4. // Distributed under the Boost Software License, Version 1.0
  5. // See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt
  7. //
  8. #ifndef BOOST_GIL_IMAGE_VIEW_HPP
  9. #define BOOST_GIL_IMAGE_VIEW_HPP
  10. #include <boost/gil/dynamic_step.hpp>
  11. #include <boost/gil/iterator_from_2d.hpp>
  12. #include <boost/assert.hpp>
  13. #include <cstddef>
  14. #include <iterator>
  15. namespace boost { namespace gil {
  16. ////////////////////////////////////////////////////////////////////////////////////////
  17. /// \class image_view
  18. /// \ingroup ImageViewModel PixelBasedModel
  19. /// \brief A lightweight object that interprets memory as a 2D array of pixels. Models ImageViewConcept,PixelBasedConcept,HasDynamicXStepTypeConcept,HasDynamicYStepTypeConcept,HasTransposedTypeConcept
  20. ///
  21. /// Image view consists of a pixel 2D locator (defining the mechanism for navigating in 2D)
  22. /// and the image dimensions.
  23. ///
  24. /// Image views to images are what ranges are to STL containers. They are lightweight objects,
  25. /// that don't own the pixels. It is the user's responsibility that the underlying data remains
  26. /// valid for the lifetime of the image view.
  27. ///
  28. /// Similar to iterators and ranges, constness of views does not extend to constness of pixels.
  29. /// A const \p image_view does not allow changing its location in memory (resizing, moving) but does
  30. /// not prevent one from changing the pixels. The latter requires an image view whose value_type
  31. /// is const.
  32. ///
  33. /// Images have interfaces consistent with STL 1D random access containers, so they can be used
  34. /// directly in STL algorithms like:
  35. /// \code
  36. /// std::fill(img.begin(), img.end(), red_pixel);
  37. /// \endcode
  38. ///
  39. /// In addition, horizontal, vertical and 2D random access iterators are provided.
  40. ///
  41. /// Note also that \p image_view does not require that its element type be a pixel. It could be
  42. /// instantiated with a locator whose \p value_type models only \p Regular. In this case the image
  43. /// view models the weaker RandomAccess2DImageViewConcept, and does not model PixelBasedConcept.
  44. /// Many generic algorithms don't require the elements to be pixels.
  45. ///
  46. ////////////////////////////////////////////////////////////////////////////////////////
  47. template <typename Loc> // Models 2D Pixel Locator
  48. class image_view
  49. {
  50. public:
  51. // aliases required by ConstRandomAccessNDImageViewConcept
  52. static const std::size_t num_dimensions=2;
  53. using value_type = typename Loc::value_type;
  54. using reference = typename Loc::reference; // result of dereferencing
  55. using coord_t = typename Loc::coord_t; // 1D difference type (same for all dimensions)
  56. using difference_type = coord_t; // result of operator-(1d_iterator,1d_iterator)
  57. using point_t = typename Loc::point_t;
  58. using locator = Loc;
  59. using const_t = image_view<typename Loc::const_t>; // same as this type, but over const values
  60. template <std::size_t D> struct axis
  61. {
  62. using coord_t = typename Loc::template axis<D>::coord_t; // difference_type along each dimension
  63. using iterator = typename Loc::template axis<D>::iterator; // 1D iterator type along each dimension
  64. };
  65. using iterator = iterator_from_2d<Loc>; // 1D iterator type for each pixel left-to-right inside top-to-bottom
  66. using const_iterator = typename const_t::iterator; // may be used to examine, but not to modify values
  67. using const_reference = typename const_t::reference; // behaves as a const reference
  68. using pointer = typename std::iterator_traits<iterator>::pointer; // behaves as a pointer to the value type
  69. using reverse_iterator = std::reverse_iterator<iterator>;
  70. using size_type = std::size_t;
  71. // aliases required by ConstRandomAccess2DImageViewConcept
  72. using xy_locator = locator;
  73. using x_iterator = typename xy_locator::x_iterator; // pixel iterator along a row
  74. using y_iterator = typename xy_locator::y_iterator; // pixel iterator along a column
  75. using x_coord_t = typename xy_locator::x_coord_t;
  76. using y_coord_t = typename xy_locator::y_coord_t;
  77. template <typename Deref>
  78. struct add_deref
  79. {
  80. using type = image_view<typename Loc::template add_deref<Deref>::type>;
  81. static type make(image_view<Loc> const& view, Deref const& d)
  82. {
  83. return type(view.dimensions(), Loc::template add_deref<Deref>::make(view.pixels(), d));
  84. }
  85. };
  86. image_view() : _dimensions(0,0) {}
  87. image_view(image_view const& img_view)
  88. : _dimensions(img_view.dimensions()), _pixels(img_view.pixels())
  89. {}
  90. template <typename View>
  91. image_view(View const& view) : _dimensions(view.dimensions()), _pixels(view.pixels()) {}
  92. template <typename L2>
  93. image_view(point_t const& dims, L2 const& loc) : _dimensions(dims), _pixels(loc) {}
  94. template <typename L2>
  95. image_view(coord_t width, coord_t height, L2 const& loc)
  96. : _dimensions(x_coord_t(width), y_coord_t(height)), _pixels(loc)
  97. {}
  98. template <typename View>
  99. image_view& operator=(View const& view)
  100. {
  101. _pixels = view.pixels();
  102. _dimensions = view.dimensions();
  103. return *this;
  104. }
  105. image_view& operator=(image_view const& view)
  106. {
  107. // TODO: Self-assignment protection?
  108. _pixels = view.pixels();
  109. _dimensions = view.dimensions();
  110. return *this;
  111. }
  112. template <typename View>
  113. bool operator==(View const &view) const
  114. {
  115. return pixels() == view.pixels() && dimensions() == view.dimensions();
  116. }
  117. template <typename View>
  118. bool operator!=(View const& view) const
  119. {
  120. return !(*this == view);
  121. }
  122. template <typename L2>
  123. friend void swap(image_view<L2> &lhs, image_view<L2> &rhs);
  124. /// \brief Exchanges the elements of the current view with those of \a other
  125. /// in constant time.
  126. ///
  127. /// \note Required by the Collection concept
  128. /// \see https://www.boost.org/libs/utility/Collection.html
  129. void swap(image_view<Loc>& other)
  130. {
  131. using boost::gil::swap;
  132. swap(*this, other);
  133. }
  134. auto dimensions() const -> point_t const&
  135. {
  136. return _dimensions;
  137. }
  138. auto pixels() const -> locator const&
  139. {
  140. return _pixels;
  141. }
  142. auto width() const -> x_coord_t
  143. {
  144. return dimensions().x;
  145. }
  146. auto height() const -> y_coord_t
  147. {
  148. return dimensions().y;
  149. }
  150. auto num_channels() const -> std::size_t
  151. {
  152. return gil::num_channels<value_type>::value;
  153. }
  154. bool is_1d_traversable() const
  155. {
  156. return _pixels.is_1d_traversable(width());
  157. }
  158. /// \brief Returns true if the view has no elements, false otherwise.
  159. ///
  160. /// \note Required by the Collection concept
  161. /// \see https://www.boost.org/libs/utility/Collection.html
  162. bool empty() const
  163. {
  164. return !(width() > 0 && height() > 0);
  165. }
  166. /// \brief Returns a reference to the first element in raster order.
  167. ///
  168. /// \note Required by the ForwardCollection, since view model the concept.
  169. /// \see https://www.boost.org/libs/utility/Collection.html
  170. auto front() const -> reference
  171. {
  172. BOOST_ASSERT(!empty());
  173. return *begin();
  174. }
  175. /// \brief Returns a reference to the last element in raster order.
  176. ///
  177. /// \note Required by the ForwardCollection, since view model the concept.
  178. /// \see https://www.boost.org/libs/utility/Collection.html
  179. auto back() const -> reference
  180. {
  181. BOOST_ASSERT(!empty());
  182. return *rbegin();
  183. }
  184. //\{@
  185. /// \name 1D navigation
  186. auto size() const -> size_type
  187. {
  188. return width() * height();
  189. }
  190. auto begin() const -> iterator
  191. {
  192. return iterator(_pixels, _dimensions.x);
  193. }
  194. auto end() const -> iterator
  195. {
  196. // potential performance problem!
  197. return begin() + static_cast<difference_type>(size());
  198. }
  199. auto rbegin() const -> reverse_iterator
  200. {
  201. return reverse_iterator(end());
  202. }
  203. auto rend() const -> reverse_iterator
  204. {
  205. return reverse_iterator(begin());
  206. }
  207. auto operator[](difference_type i) const -> reference
  208. {
  209. BOOST_ASSERT(i < static_cast<difference_type>(size()));
  210. return begin()[i]; // potential performance problem!
  211. }
  212. auto at(difference_type i) const -> iterator
  213. {
  214. // UB if the specified increment advances non-incrementable iterator (i.e. past-the-end)
  215. BOOST_ASSERT(i < static_cast<difference_type>(size()));
  216. return begin() + i;
  217. }
  218. auto at(point_t const& p) const -> iterator
  219. {
  220. // UB if the specified coordinates advance non-incrementable iterator (i.e. past-the-end)
  221. BOOST_ASSERT(0 <= p.x && p.x < width());
  222. BOOST_ASSERT(0 <= p.y && p.y < height());
  223. return begin() + p.y * width() + p.x;
  224. }
  225. auto at(x_coord_t x, y_coord_t y) const -> iterator
  226. {
  227. // UB if the specified coordinates advance non-incrementable iterator (i.e. past-the-end)
  228. BOOST_ASSERT(0 <= x && x < width());
  229. BOOST_ASSERT(0 <= y && y < height());
  230. return begin() + y * width() + x;
  231. }
  232. //\}@
  233. //\{@
  234. /// \name 2-D navigation
  235. auto operator()(point_t const& p) const -> reference
  236. {
  237. BOOST_ASSERT(0 <= p.x && p.x < width());
  238. BOOST_ASSERT(0 <= p.y && p.y < height());
  239. return _pixels(p.x, p.y);
  240. }
  241. auto operator()(x_coord_t x, y_coord_t y) const -> reference
  242. {
  243. BOOST_ASSERT(0 <= x && x < width());
  244. BOOST_ASSERT(0 <= y && y < height());
  245. return _pixels(x, y);
  246. }
  247. template <std::size_t D>
  248. auto axis_iterator(point_t const& p) const -> typename axis<D>::iterator
  249. {
  250. // Allow request for iterators from inclusive range of [begin, end]
  251. BOOST_ASSERT(0 <= p.x && p.x <= width());
  252. BOOST_ASSERT(0 <= p.y && p.y <= height());
  253. return _pixels.template axis_iterator<D>(p);
  254. }
  255. auto xy_at(x_coord_t x, y_coord_t y) const -> xy_locator
  256. {
  257. // TODO: Are relative locations of neighbors with negative offsets valid? Sampling?
  258. BOOST_ASSERT(x < width());
  259. BOOST_ASSERT(y <= height());
  260. return _pixels + point_t(x, y);
  261. }
  262. auto xy_at(point_t const& p) const -> xy_locator
  263. {
  264. // TODO: Are relative locations of neighbors with negative offsets valid? Sampling?
  265. BOOST_ASSERT(p.x < width());
  266. BOOST_ASSERT(p.y < height());
  267. return _pixels + p;
  268. }
  269. //\}@
  270. //\{@
  271. /// \name X navigation
  272. auto x_at(x_coord_t x, y_coord_t y) const -> x_iterator
  273. {
  274. BOOST_ASSERT(0 <= x && x <= width()); // allow request for [begin, end] inclusive
  275. BOOST_ASSERT(0 <= y && y < height()); // TODO: For empty image/view, shouldn't we accept: row_begin(0) == view.row_end(0) ?
  276. return _pixels.x_at(x, y);
  277. }
  278. auto x_at(point_t const& p) const -> x_iterator
  279. {
  280. BOOST_ASSERT(0 <= p.x && p.x <= width()); // allow request for [begin, end] inclusive
  281. BOOST_ASSERT(0 <= p.y && p.y < height()); // TODO: For empty image/view, shouldn't we accept: row_begin(0) == view.row_end(0) ?
  282. return _pixels.x_at(p);
  283. }
  284. auto row_begin(y_coord_t y) const -> x_iterator
  285. {
  286. BOOST_ASSERT(0 <= y && y < height());
  287. return x_at(0, y);
  288. }
  289. auto row_end(y_coord_t y) const -> x_iterator
  290. {
  291. BOOST_ASSERT(0 <= y && y < height());
  292. return x_at(width(), y);
  293. }
  294. //\}@
  295. //\{@
  296. /// \name Y navigation
  297. auto y_at(x_coord_t x, y_coord_t y) const -> y_iterator
  298. {
  299. BOOST_ASSERT(0 <= x && x < width()); // TODO: For empty image/view, shouldn't we accept: view.col_begin(0) == view.col_end(0) ?
  300. BOOST_ASSERT(0 <= y && y <= height()); // allow request for [begin, end] inclusive
  301. return xy_at(x, y).y();
  302. }
  303. auto y_at(point_t const& p) const -> y_iterator
  304. {
  305. BOOST_ASSERT(0 <= p.x && p.x < width()); // TODO: For empty image/view, shouldn't we accept: view.col_begin(0) == view.col_end(0) ?
  306. BOOST_ASSERT(0 <= p.y && p.y <= height()); // allow request for [begin, end] inclusive
  307. return xy_at(p).y();
  308. }
  309. auto col_begin(x_coord_t x) const -> y_iterator
  310. {
  311. BOOST_ASSERT(0 <= x && x < width());
  312. return y_at(x, 0);
  313. }
  314. auto col_end(x_coord_t x) const -> y_iterator
  315. {
  316. BOOST_ASSERT(0 <= x && x < width());
  317. return y_at(x, height());
  318. }
  319. //\}@
  320. private:
  321. template <typename L2>
  322. friend class image_view;
  323. point_t _dimensions;
  324. xy_locator _pixels;
  325. };
  326. template <typename L2>
  327. inline void swap(image_view<L2>& x, image_view<L2>& y) {
  328. using std::swap;
  329. swap(x._dimensions,y._dimensions);
  330. swap(x._pixels, y._pixels); // TODO: Extend further
  331. }
  332. /////////////////////////////
  333. // PixelBasedConcept
  334. /////////////////////////////
  335. template <typename L>
  336. struct channel_type<image_view<L> > : public channel_type<L> {};
  337. template <typename L>
  338. struct color_space_type<image_view<L> > : public color_space_type<L> {};
  339. template <typename L>
  340. struct channel_mapping_type<image_view<L> > : public channel_mapping_type<L> {};
  341. template <typename L>
  342. struct is_planar<image_view<L> > : public is_planar<L> {};
  343. /////////////////////////////
  344. // HasDynamicXStepTypeConcept
  345. /////////////////////////////
  346. template <typename L>
  347. struct dynamic_x_step_type<image_view<L>>
  348. {
  349. using type = image_view<typename gil::dynamic_x_step_type<L>::type>;
  350. };
  351. /////////////////////////////
  352. // HasDynamicYStepTypeConcept
  353. /////////////////////////////
  354. template <typename L>
  355. struct dynamic_y_step_type<image_view<L>>
  356. {
  357. using type = image_view<typename gil::dynamic_y_step_type<L>::type>;
  358. };
  359. /////////////////////////////
  360. // HasTransposedTypeConcept
  361. /////////////////////////////
  362. template <typename L>
  363. struct transposed_type<image_view<L>>
  364. {
  365. using type = image_view<typename transposed_type<L>::type>;
  366. };
  367. }} // namespace boost::gil
  368. #endif