image_view.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  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. BOOST_ASSERT(i < size());
  215. return begin() + i;
  216. }
  217. auto at(point_t const& p) const -> iterator
  218. {
  219. BOOST_ASSERT(0 <= p.x && p.x < width());
  220. BOOST_ASSERT(0 <= p.y && p.y < height());
  221. return begin() + p.y * width() + p.x;
  222. }
  223. auto at(x_coord_t x, y_coord_t y) const -> iterator
  224. {
  225. BOOST_ASSERT(0 <= x && x < width());
  226. BOOST_ASSERT(0 <= y && y < height());
  227. return begin() + y * width() + x;
  228. }
  229. //\}@
  230. //\{@
  231. /// \name 2-D navigation
  232. auto operator()(point_t const& p) const -> reference
  233. {
  234. BOOST_ASSERT(0 <= p.x && p.x < width());
  235. BOOST_ASSERT(0 <= p.y && p.y < height());
  236. return _pixels(p.x, p.y);
  237. }
  238. auto operator()(x_coord_t x, y_coord_t y) const -> reference
  239. {
  240. BOOST_ASSERT(0 <= x && x < width());
  241. BOOST_ASSERT(0 <= y && y < height());
  242. return _pixels(x, y);
  243. }
  244. template <std::size_t D>
  245. auto axis_iterator(point_t const& p) const -> typename axis<D>::iterator
  246. {
  247. // allow request for iterators from inclusive range of [begin, end]
  248. BOOST_ASSERT(0 <= p.x && p.x <= width());
  249. BOOST_ASSERT(0 <= p.y && p.y <= height());
  250. return _pixels.template axis_iterator<D>(p);
  251. }
  252. auto xy_at(x_coord_t x, y_coord_t y) const -> xy_locator
  253. {
  254. // TODO: Are relative locations of neighbors with negative offsets valid? Sampling?
  255. BOOST_ASSERT(x < width());
  256. BOOST_ASSERT(y < height());
  257. return _pixels + point_t(x, y);
  258. }
  259. auto xy_at(point_t const& p) const -> locator
  260. {
  261. // TODO: Are relative locations of neighbors with negative offsets valid? Sampling?
  262. BOOST_ASSERT(p.x < width());
  263. BOOST_ASSERT(p.y < height());
  264. return _pixels + p;
  265. }
  266. //\}@
  267. //\{@
  268. /// \name X navigation
  269. auto x_at(x_coord_t x, y_coord_t y) const -> x_iterator
  270. {
  271. BOOST_ASSERT(0 <= x && x <= width()); // allow request for [begin, end] inclusive
  272. BOOST_ASSERT(0 <= y && y < height());
  273. return _pixels.x_at(x, y);
  274. }
  275. auto x_at(point_t const& p) const -> x_iterator
  276. {
  277. BOOST_ASSERT(0 <= p.x && p.x <= width()); // allow request for [begin, end] inclusive
  278. BOOST_ASSERT(0 <= p.y && p.y < height());
  279. return _pixels.x_at(p);
  280. }
  281. auto row_begin(y_coord_t y) const -> x_iterator
  282. {
  283. BOOST_ASSERT(0 <= y && y < height());
  284. return x_at(0, y);
  285. }
  286. auto row_end(y_coord_t y) const -> x_iterator
  287. {
  288. BOOST_ASSERT(0 <= y && y < height());
  289. return x_at(width(), y);
  290. }
  291. //\}@
  292. //\{@
  293. /// \name Y navigation
  294. auto y_at(x_coord_t x, y_coord_t y) const -> y_iterator
  295. {
  296. BOOST_ASSERT(0 <= x && x < width());
  297. BOOST_ASSERT(0 <= y && y <= height()); // allow request for [begin, end] inclusive
  298. return xy_at(x, y).y();
  299. }
  300. auto y_at(point_t const& p) const -> y_iterator
  301. {
  302. BOOST_ASSERT(0 <= p.x && p.x < width());
  303. BOOST_ASSERT(0 <= p.y && p.y <= height()); // allow request for [begin, end] inclusive
  304. return xy_at(p).y();
  305. }
  306. auto col_begin(x_coord_t x) const -> y_iterator
  307. {
  308. BOOST_ASSERT(0 <= x && x < width());
  309. return y_at(x, 0);
  310. }
  311. auto col_end(x_coord_t x) const -> y_iterator
  312. {
  313. BOOST_ASSERT(0 <= x && x < width());
  314. return y_at(x, height());
  315. }
  316. //\}@
  317. private:
  318. template <typename L2>
  319. friend class image_view;
  320. point_t _dimensions;
  321. xy_locator _pixels;
  322. };
  323. template <typename L2>
  324. inline void swap(image_view<L2>& x, image_view<L2>& y) {
  325. using std::swap;
  326. swap(x._dimensions,y._dimensions);
  327. swap(x._pixels, y._pixels); // TODO: Extend further
  328. }
  329. /////////////////////////////
  330. // PixelBasedConcept
  331. /////////////////////////////
  332. template <typename L>
  333. struct channel_type<image_view<L> > : public channel_type<L> {};
  334. template <typename L>
  335. struct color_space_type<image_view<L> > : public color_space_type<L> {};
  336. template <typename L>
  337. struct channel_mapping_type<image_view<L> > : public channel_mapping_type<L> {};
  338. template <typename L>
  339. struct is_planar<image_view<L> > : public is_planar<L> {};
  340. /////////////////////////////
  341. // HasDynamicXStepTypeConcept
  342. /////////////////////////////
  343. template <typename L>
  344. struct dynamic_x_step_type<image_view<L>>
  345. {
  346. using type = image_view<typename gil::dynamic_x_step_type<L>::type>;
  347. };
  348. /////////////////////////////
  349. // HasDynamicYStepTypeConcept
  350. /////////////////////////////
  351. template <typename L>
  352. struct dynamic_y_step_type<image_view<L>>
  353. {
  354. using type = image_view<typename gil::dynamic_y_step_type<L>::type>;
  355. };
  356. /////////////////////////////
  357. // HasTransposedTypeConcept
  358. /////////////////////////////
  359. template <typename L>
  360. struct transposed_type<image_view<L>>
  361. {
  362. using type = image_view<typename transposed_type<L>::type>;
  363. };
  364. }} // namespace boost::gil
  365. #endif