1 // Copyright (C) 2014 Davis E. King (davis@dlib.net) 2 // License: Boost Software License See LICENSE.txt for the full license. 3 #ifndef DLIB_GeNERIC_IMAGE_Hh_ 4 #define DLIB_GeNERIC_IMAGE_Hh_ 5 6 #include "../assert.h" 7 #include "../pixel.h" 8 #include <type_traits> 9 10 namespace dlib 11 { 12 13 /*! 14 In dlib, an "image" is any object that implements the generic image interface. In 15 particular, this simply means that an image type (let's refer to it as image_type 16 from here on) has the following seven global functions defined for it: 17 - long num_rows (const image_type& img) 18 - long num_columns (const image_type& img) 19 - void set_image_size( image_type& img, long rows, long cols) 20 - void* image_data ( image_type& img) 21 - const void* image_data (const image_type& img) 22 - long width_step (const image_type& img) 23 - void swap ( image_type& a, image_type& b) 24 And also provides a specialization of the image_traits template that looks like: 25 namespace dlib 26 { 27 template <> 28 struct image_traits<image_type> 29 { 30 typedef the_type_of_pixel_used_in_image_type pixel_type; 31 }; 32 } 33 34 Additionally, an image object must be default constructable. This means that 35 expressions of the form: 36 image_type img; 37 Must be legal. 38 39 Finally, the type of pixel in image_type must have a pixel_traits specialization. 40 That is, pixel_traits<typename image_traits<image_type>::pixel_type> must be one of 41 the specializations of pixel_traits. 42 43 44 To be very precise, the seven functions defined above are defined thusly: 45 46 long num_rows( 47 const image_type& img 48 ); 49 /!* 50 ensures 51 - returns the number of rows in the given image 52 *!/ 53 54 long num_columns( 55 const image_type& img 56 ); 57 /!* 58 ensures 59 - returns the number of columns in the given image 60 *!/ 61 62 void set_image_size( 63 image_type& img, 64 long rows, 65 long cols 66 ); 67 /!* 68 requires 69 - rows >= 0 && cols >= 0 70 ensures 71 - num_rows(#img) == rows 72 - num_columns(#img) == cols 73 *!/ 74 75 void* image_data( 76 image_type& img 77 ); 78 /!* 79 ensures 80 - returns a non-const pointer to the pixel at row and column position 0,0 81 in the given image. Or if the image has zero rows or columns in it 82 then this function returns NULL. 83 - The image lays pixels down in row major order. However, there might 84 be padding at the end of each row. The amount of padding is given by 85 width_step(img). 86 *!/ 87 88 const void* image_data( 89 const image_type& img 90 ); 91 /!* 92 ensures 93 - returns a const pointer to the pixel at row and column position 0,0 in 94 the given image. Or if the image has zero rows or columns in it then 95 this function returns NULL. 96 - The image lays pixels down in row major order. However, there might 97 be padding at the end of each row. The amount of padding is given by 98 width_step(img). 99 *!/ 100 101 long width_step( 102 const image_type& img 103 ); 104 /!* 105 ensures 106 - returns the size of one row of the image, in bytes. More precisely, 107 return a number N such that: (char*)image_data(img) + N*R == a 108 pointer to the first pixel in the R-th row of the image. This means 109 that the image must lay its pixels down in row major order. 110 *!/ 111 112 void swap( 113 image_type& a, 114 image_type& b 115 ); 116 /!* 117 ensures 118 - swaps the state of a and b 119 *!/ 120 !*/ 121 122 // ---------------------------------------------------------------------------------------- 123 124 template <typename image_type> 125 struct image_traits; 126 /*! 127 WHAT THIS OBJECT REPRESENTS 128 This is a traits class for generic image objects. You can use it to find out 129 the pixel type contained within an image via an expression of the form: 130 image_traits<image_type>::pixel_type 131 !*/ 132 133 template <typename image_type> 134 struct is_rgb_image { const static bool value = pixel_traits<typename image_traits<image_type>::pixel_type>::rgb; }; 135 136 template <typename image_type> 137 struct is_color_space_cartesian_image { const static bool value = 138 pixel_traits<typename image_traits<image_type>::pixel_type>::rgb || 139 pixel_traits<typename image_traits<image_type>::pixel_type>::lab || 140 pixel_traits<typename image_traits<image_type>::pixel_type>::grayscale; }; 141 /* 142 Tells if all color components of image pixels are in cartesian coordinates, compared to e.g. polar coordinates. 143 Polar coordinates that may require more complicated blending. 144 */ 145 146 template <typename image_type> 147 struct is_grayscale_image { const static bool value = pixel_traits<typename image_traits<image_type>::pixel_type>::grayscale; }; 148 149 150 // Check if T has image_traits<T> defined for it. 151 template <typename T, typename enabled = size_t> 152 struct is_image_type : public std::false_type{}; 153 template <typename T> 154 struct is_image_type<T, decltype(sizeof(image_traits<typename std::decay<T>::type>))> : public std::true_type{}; 155 156 // ---------------------------------------------------------------------------------------- 157 // ---------------------------------------------------------------------------------------- 158 // UTILITIES TO MAKE ACCESSING IMAGE PIXELS SIMPLER 159 // ---------------------------------------------------------------------------------------- 160 // ---------------------------------------------------------------------------------------- 161 162 template < 163 typename image_type 164 > 165 class image_view 166 { 167 /*! 168 REQUIREMENTS ON image_type 169 image_type must be an image object as defined at the top of this file. 170 171 WHAT THIS OBJECT REPRESENTS 172 This object takes an image object and wraps it with an interface that makes 173 it look like a dlib::array2d. That is, it makes it look similar to a 174 regular 2-dimensional C style array, making code which operates on the 175 pixels simple to read. 176 177 Note that an image_view instance is valid until the image given to its 178 constructor is modified through an interface other than the image_view 179 instance. This is because, for example, someone might cause the underlying 180 image object to reallocate its memory, thus invalidating the pointer to its 181 pixel data stored in the image_view. 182 183 As an side, the reason why this object stores a pointer to the image 184 object's data and uses that pointer instead of calling image_data() each 185 time a pixel is accessed is to allow for image objects to implement 186 complex, and possibly slow, image_data() functions. For example, an image 187 object might perform some kind of synchronization between a GPU and the 188 host memory during a call to image_data(). Therefore, we call image_data() 189 only in image_view's constructor to avoid the performance penalty of 190 calling it for each pixel access. 191 !*/ 192 193 public: 194 typedef typename image_traits<image_type>::pixel_type pixel_type; 195 196 image_view( 197 image_type& img 198 ) : 199 _data(reinterpret_cast<char*>(image_data(img))), 200 _width_step(width_step(img)), 201 _nr(num_rows(img)), 202 _nc(num_columns(img)), 203 _img(&img) 204 {} 205 206 long nr() const { return _nr; } 207 /*! 208 ensures 209 - returns the number of rows in this image. 210 !*/ 211 212 long nc() const { return _nc; } 213 /*! 214 ensures 215 - returns the number of columns in this image. 216 !*/ 217 218 unsigned long size() const { return static_cast<unsigned long>(nr()*nc()); } 219 /*! 220 ensures 221 - returns the number of pixels in this image. 222 !*/ 223 224 #ifndef ENABLE_ASSERTS 225 pixel_type* operator[] (long row) { return (pixel_type*)(_data+_width_step*row); } 226 /*! 227 requires 228 - 0 <= row < nr() 229 ensures 230 - returns a pointer to the first pixel in the row-th row. Therefore, the 231 pixel at row and column position r,c can be accessed via (*this)[r][c]. 232 !*/ 233 234 const pixel_type* operator[] (long row) const { return (const pixel_type*)(_data+_width_step*row); } 235 /*! 236 requires 237 - 0 <= row < nr() 238 ensures 239 - returns a const pointer to the first pixel in the row-th row. Therefore, 240 the pixel at row and column position r,c can be accessed via 241 (*this)[r][c]. 242 !*/ 243 #else 244 // If asserts are enabled then we need to return a proxy class so we can make sure 245 // the column accesses don't go out of bounds. 246 struct pix_row 247 { 248 pix_row(pixel_type* data_, long nc_) : data(data_),_nc(nc_) {} 249 const pixel_type& operator[] (long col) const 250 { 251 DLIB_ASSERT(0 <= col && col < _nc, 252 "\t The given column index is out of range." 253 << "\n\t col: " << col 254 << "\n\t _nc: " << _nc); 255 return data[col]; 256 } 257 pixel_type& operator[] (long col) 258 { 259 DLIB_ASSERT(0 <= col && col < _nc, 260 "\t The given column index is out of range." 261 << "\n\t col: " << col 262 << "\n\t _nc: " << _nc); 263 return data[col]; 264 } 265 private: 266 pixel_type* const data; 267 const long _nc; 268 }; 269 pix_row operator[] (long row) 270 { 271 DLIB_ASSERT(0 <= row && row < _nr, 272 "\t The given row index is out of range." 273 << "\n\t row: " << row 274 << "\n\t _nr: " << _nr); 275 return pix_row((pixel_type*)(_data+_width_step*row), _nc); 276 } 277 const pix_row operator[] (long row) const 278 { 279 DLIB_ASSERT(0 <= row && row < _nr, 280 "\t The given row index is out of range." 281 << "\n\t row: " << row 282 << "\n\t _nr: " << _nr); 283 return pix_row((pixel_type*)(_data+_width_step*row), _nc); 284 } 285 #endif 286 287 void set_size(long rows, long cols) 288 /*! 289 requires 290 - rows >= 0 && cols >= 0 291 ensures 292 - Tells the underlying image to resize itself to have the given number of 293 rows and columns. 294 - #nr() == rows 295 - #nc() == cols 296 !*/ 297 { 298 DLIB_ASSERT((cols >= 0 && rows >= 0), 299 "\t image_view::set_size(long rows, long cols)" 300 << "\n\t The images can't have negative rows or columns." 301 << "\n\t cols: " << cols 302 << "\n\t rows: " << rows 303 ); 304 set_image_size(*_img, rows, cols); *this = *_img; 305 } 306 307 void clear() { set_size(0,0); } 308 /*! 309 ensures 310 - sets the image to have 0 pixels in it. 311 !*/ 312 313 long get_width_step() const { return _width_step; } 314 315 private: 316 317 char* _data; 318 long _width_step; 319 long _nr; 320 long _nc; 321 image_type* _img; 322 }; 323 324 // ---------------------------------------------------------------------------------------- 325 326 template <typename image_type> 327 class const_image_view 328 { 329 /*! 330 REQUIREMENTS ON image_type 331 image_type must be an image object as defined at the top of this file. 332 333 WHAT THIS OBJECT REPRESENTS 334 This object is just like the image_view except that it provides a "const" 335 view into an image. That is, it has the same interface as image_view 336 except that you can't modify the image through a const_image_view. 337 !*/ 338 339 public: 340 typedef typename image_traits<image_type>::pixel_type pixel_type; 341 342 const_image_view( 343 const image_type& img 344 ) : 345 _data(reinterpret_cast<const char*>(image_data(img))), 346 _width_step(width_step(img)), 347 _nr(num_rows(img)), 348 _nc(num_columns(img)) 349 {} 350 351 long nr() const { return _nr; } 352 long nc() const { return _nc; } 353 unsigned long size() const { return static_cast<unsigned long>(nr()*nc()); } 354 #ifndef ENABLE_ASSERTS 355 const pixel_type* operator[] (long row) const { return (const pixel_type*)(_data+_width_step*row); } 356 #else 357 // If asserts are enabled then we need to return a proxy class so we can make sure 358 // the column accesses don't go out of bounds. 359 struct pix_row 360 { 361 pix_row(pixel_type* data_, long nc_) : data(data_),_nc(nc_) {} 362 const pixel_type& operator[] (long col) const 363 { 364 DLIB_ASSERT(0 <= col && col < _nc, 365 "\t The given column index is out of range." 366 << "\n\t col: " << col 367 << "\n\t _nc: " << _nc); 368 return data[col]; 369 } 370 private: 371 pixel_type* const data; 372 const long _nc; 373 }; 374 const pix_row operator[] (long row) const 375 { 376 DLIB_ASSERT(0 <= row && row < _nr, 377 "\t The given row index is out of range." 378 << "\n\t row: " << row 379 << "\n\t _nr: " << _nr); 380 return pix_row((pixel_type*)(_data+_width_step*row), _nc); 381 } 382 #endif 383 384 long get_width_step() const { return _width_step; } 385 386 private: 387 const char* _data; 388 long _width_step; 389 long _nr; 390 long _nc; 391 }; 392 393 // ---------------------------------------------------------------------------------------- 394 395 template <typename image_type> 396 image_view<image_type> make_image_view ( image_type& img) 397 { return image_view<image_type>(img); } 398 /*! 399 requires 400 - image_type == an image object that implements the interface defined at the 401 top of this file. 402 ensures 403 - constructs an image_view from an image object 404 !*/ 405 406 template <typename image_type> 407 const_image_view<image_type> make_image_view (const image_type& img) 408 { return const_image_view<image_type>(img); } 409 /*! 410 requires 411 - image_type == an image object that implements the interface defined at the 412 top of this file. 413 ensures 414 - constructs a const_image_view from an image object 415 !*/ 416 417 418 // Don't stack image views on image views since that's pointless and just slows the 419 // compilation. 420 template <typename T> image_view<T>& make_image_view ( image_view<T>& img) { return img; } 421 template <typename T> const image_view<T>& make_image_view ( const image_view<T>& img) { return img; } 422 template <typename T> const_image_view<T>& make_image_view ( const_image_view<T>& img) { return img; } 423 template <typename T> const const_image_view<T>& make_image_view ( const const_image_view<T>& img) { return img; } 424 425 // ---------------------------------------------------------------------------------------- 426 427 template <typename image_type> 428 inline unsigned long image_size( 429 const image_type& img 430 ) { return num_columns(img)*num_rows(img); } 431 /*! 432 requires 433 - image_type == an image object that implements the interface defined at the 434 top of this file. 435 ensures 436 - returns the number of pixels in the given image. 437 !*/ 438 439 // ---------------------------------------------------------------------------------------- 440 441 template <typename image_type> 442 inline long num_rows( 443 const image_type& img 444 ) { return img.nr(); } 445 /*! 446 ensures 447 - By default, try to use the member function .nr() to determine the number 448 of rows in an image. However, as stated at the top of this file, image 449 objects should provide their own overload of num_rows() if needed. 450 !*/ 451 452 template <typename image_type> 453 inline long num_columns( 454 const image_type& img 455 ) { return img.nc(); } 456 /*! 457 ensures 458 - By default, try to use the member function .nc() to determine the number 459 of columns in an image. However, as stated at the top of this file, image 460 objects should provide their own overload of num_rows() if needed. 461 !*/ 462 463 template <typename image_type1, typename image_type2> 464 typename std::enable_if<is_image_type<image_type1>::value&&is_image_type<image_type2>::value, bool>::type 465 have_same_dimensions ( 466 const image_type1& img1, 467 const image_type2& img2 468 ) { return num_rows(img1)==num_rows(img2) && num_columns(img1)==num_columns(img2); } 469 /*! 470 ensures 471 - returns true if and only if the two given images have the same dimensions. 472 !*/ 473 474 template <typename image_type1, typename image_type2, typename ...T> 475 typename std::enable_if<is_image_type<image_type1>::value&&is_image_type<image_type2>::value, bool>::type 476 have_same_dimensions ( 477 const image_type1& img1, 478 const image_type2& img2, 479 T&& ...args 480 ) { return have_same_dimensions(img1,img2) && have_same_dimensions(img1,args...); } 481 482 // ---------------------------------------------------------------------------------------- 483 // ---------------------------------------------------------------------------------------- 484 // Make the image views implement the generic image interface 485 // ---------------------------------------------------------------------------------------- 486 // ---------------------------------------------------------------------------------------- 487 488 template <typename T> 489 struct image_traits<image_view<T>> 490 { 491 typedef typename image_traits<T>::pixel_type pixel_type; 492 }; 493 template <typename T> 494 struct image_traits<const image_view<T>> 495 { 496 typedef typename image_traits<T>::pixel_type pixel_type; 497 }; 498 499 template <typename T> 500 inline long num_rows( const image_view<T>& img) { return img.nr(); } 501 template <typename T> 502 inline long num_columns( const image_view<T>& img) { return img.nc(); } 503 504 template <typename T> 505 inline void set_image_size( image_view<T>& img, long rows, long cols ) { img.set_size(rows,cols); } 506 507 template <typename T> 508 inline void* image_data( image_view<T>& img) 509 { 510 if (img.size() != 0) 511 return &img[0][0]; 512 else 513 return 0; 514 } 515 516 template <typename T> 517 inline const void* image_data( 518 const image_view<T>& img 519 ) 520 { 521 if (img.size() != 0) 522 return &img[0][0]; 523 else 524 return 0; 525 } 526 527 template <typename T> 528 inline long width_step( const image_view<T>& img) { return img.get_width_step(); } 529 530 // ---------------------------------------------------------------------------------------- 531 532 template <typename T> 533 struct image_traits<const_image_view<T>> 534 { 535 typedef typename image_traits<T>::pixel_type pixel_type; 536 }; 537 template <typename T> 538 struct image_traits<const const_image_view<T>> 539 { 540 typedef typename image_traits<T>::pixel_type pixel_type; 541 }; 542 543 template <typename T> 544 inline long num_rows( const const_image_view<T>& img) { return img.nr(); } 545 template <typename T> 546 inline long num_columns( const const_image_view<T>& img) { return img.nc(); } 547 548 template <typename T> 549 inline const void* image_data( 550 const const_image_view<T>& img 551 ) 552 { 553 if (img.size() != 0) 554 return &img[0][0]; 555 else 556 return 0; 557 } 558 559 template <typename T> 560 inline long width_step( const const_image_view<T>& img) { return img.get_width_step(); } 561 562 // ---------------------------------------------------------------------------------------- 563 564 } 565 566 #endif // DLIB_GeNERIC_IMAGE_Hh_ 567 568