From f775b55cd9932b906aea3a1ad46cb06fa083ab0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Arrufat?= <1671644+arrufat@users.noreply.github.com> Date: Wed, 21 Feb 2024 20:44:15 +0900 Subject: [PATCH] Add color transform and inv color transform (#2914) * add color transform * simplify inv_color_transform * fix typo * Update dlib/image_transforms/random_color_transform.h * Update dlib/image_transforms/random_color_transform.h --------- Co-authored-by: Davis E. King --- .../image_transforms/random_color_transform.h | 111 +++++++++++++---- .../random_color_transform_abstract.h | 113 +++++++++++++++--- 2 files changed, 183 insertions(+), 41 deletions(-) diff --git a/dlib/image_transforms/random_color_transform.h b/dlib/image_transforms/random_color_transform.h index e6952ac8a..ff7ed42fe 100644 --- a/dlib/image_transforms/random_color_transform.h +++ b/dlib/image_transforms/random_color_transform.h @@ -7,34 +7,31 @@ #include "../image_processing/generic_image.h" #include "../pixel.h" #include "../rand.h" +#include "../matrix.h" namespace dlib { // ---------------------------------------------------------------------------------------- - class random_color_transform + class color_transform { public: - - random_color_transform ( - dlib::rand& rnd, - const double gamma_magnitude = 0.5, - const double color_magnitude = 0.2 - ) + color_transform( + const double gamma_ = 1, + const double red_scale_ = 1, + const double green_scale_ = 1, + const double blue_scale_ = 1 + ) : gamma(gamma_), red_scale(red_scale_), green_scale(green_scale_), blue_scale(blue_scale_) { - // pick a random gamma correction factor. - const double gamma = std::max(0.0, 1 + gamma_magnitude*(rnd.get_random_double() - 0.5)); - - // pick a random color balancing scheme. - double red_scale = 1 - rnd.get_random_double() * color_magnitude; - double green_scale = 1 - rnd.get_random_double() * color_magnitude; - double blue_scale = 1 - rnd.get_random_double() * color_magnitude; - const double m = 255 * std::max({red_scale, green_scale, blue_scale}); + DLIB_CASSERT(gamma_ >= 0) + DLIB_CASSERT(0 <= red_scale_ && red_scale_ <= 1) + DLIB_CASSERT(0 <= green_scale_ && green_scale_ <= 1) + DLIB_CASSERT(0 <= blue_scale_ && blue_scale_ <= 1) + const double m = 255 * std::max({red_scale_, green_scale_, blue_scale_}); red_scale /= m; green_scale /= m; blue_scale /= m; - // Now compute a lookup table for all the color channels. The table tells us // what the transform does. table.resize(256 * 3); @@ -61,14 +58,82 @@ namespace dlib return p; } + double get_gamma() const { return gamma; } + double get_red_scale() const { return red_scale; } + double get_green_scale() const { return green_scale; } + double get_blue_scale() const { return blue_scale; } + + private: + std::vector table; + double gamma; + double red_scale; + double green_scale; + double blue_scale; + }; + + class inv_color_transform + { + public: + inv_color_transform( + const color_transform& tform + ) + { + const auto gamma = tform.get_gamma(); + const auto red_scale = tform.get_red_scale(); + const auto green_scale = tform.get_green_scale(); + const auto blue_scale = tform.get_blue_scale(); + + // Now compute a lookup table for all the color channels. The table tells us + // what the transform does. + table.resize(256 * 3); + unsigned long i = 0; + for (int k = 0; k < 256; ++k) + { + table[i++] = static_cast(std::pow(k / 255.0, 1 / gamma) / red_scale + 0.5); + } + for (int k = 0; k < 256; ++k) + { + table[i++] = static_cast(std::pow(k / 255.0, 1 / gamma) / green_scale + 0.5); + } + for (int k = 0; k < 256; ++k) + { + table[i++] = static_cast(std::pow(k / 255.0, 1 / gamma) / blue_scale + 0.5); + } + } + + rgb_pixel operator()(rgb_pixel p) const + { + p.red = table[static_cast(p.red)]; + p.green = table[static_cast(p.green + 256)]; + p.blue = table[static_cast(p.blue + 512)]; + return p; + } + private: std::vector table; }; +// ---------------------------------------------------------------------------------------- + + inline color_transform random_color_transform ( + dlib::rand& rnd, + const double gamma_magnitude = 0.5, + const double color_magnitude = 0.2 + ) + { + // pick a random gamma correction factor. + const double gamma = std::max(0.0, 1 + gamma_magnitude * (rnd.get_random_double() - 0.5)); + // pick a random color balancing scheme. + const double red_scale = 1 - rnd.get_random_double() * color_magnitude; + const double green_scale = 1 - rnd.get_random_double() * color_magnitude; + const double blue_scale = 1 - rnd.get_random_double() * color_magnitude; + return color_transform(gamma, red_scale, green_scale, blue_scale); + } + // ---------------------------------------------------------------------------------------- template - void disturb_colors ( + color_transform disturb_colors ( image_type& img_, dlib::rand& rnd, const double gamma_magnitude = 0.5, @@ -76,10 +141,10 @@ namespace dlib ) { if (gamma_magnitude == 0 && color_magnitude == 0) - return; + return {}; image_view img(img_); - random_color_transform tform(rnd, gamma_magnitude, color_magnitude); + const auto tform = random_color_transform(rnd, gamma_magnitude, color_magnitude); for (long r = 0; r < img.nr(); ++r) { for (long c = 0; c < img.nc(); ++c) @@ -90,6 +155,7 @@ namespace dlib assign_pixel(img[r][c], temp); } } + return tform; } // ---------------------------------------------------------------------------------------- @@ -111,9 +177,9 @@ namespace dlib // Except that we used the square root of the eigenvalues (which I'm pretty sure is // what the authors intended). matrix tform; - tform = -66.379, 25.094, 6.79698, + tform = -66.379, 25.094, 6.79698, -68.0492, -0.302309, -13.9539, - -68.4907, -24.0199, 7.27653; + -68.4907, -24.0199, 7.27653; matrix v; v = rnd.get_random_gaussian(),rnd.get_random_gaussian(),rnd.get_random_gaussian(); v = round(tform*0.1*v); @@ -132,7 +198,7 @@ namespace dlib gtable[i] = put_in_range(0, 255, i+goffset); btable[i] = put_in_range(0, 255, i+boffset); } - + // now transform the image. image_view img(img_); for (long r = 0; r < img.nr(); ++r) @@ -154,4 +220,3 @@ namespace dlib } #endif // DLIB_RANDOM_cOLOR_TRANSFORM_Hh_ - diff --git a/dlib/image_transforms/random_color_transform_abstract.h b/dlib/image_transforms/random_color_transform_abstract.h index 5826e16a6..880ca0b2d 100644 --- a/dlib/image_transforms/random_color_transform_abstract.h +++ b/dlib/image_transforms/random_color_transform_abstract.h @@ -12,33 +12,96 @@ namespace dlib // ---------------------------------------------------------------------------------------- - class random_color_transform + class color_transform { /*! WHAT THIS OBJECT REPRESENTS - This object generates a random color balancing and gamma correction - transform. It then allows you to apply that specific transform to as many + This object generates a color balancing and gamma correction transform. + It then allows you to apply that specific transform to as many rgb_pixel objects as you like. !*/ public: - random_color_transform ( - dlib::rand& rnd, - const double gamma_magnitude = 0.5, - const double color_magnitude = 0.2 + color_transform ( + const double gamma = 1.0, + const double red_scale = 1.0, + const double green_scale = 1.0, + const double blue_scale = 1.0 ); /*! requires - - 0 <= gamma_magnitude - - 0 <= color_magnitude <= 1 + - 0 <= gamma + - 0 <= red_scale <= 1 + - 0 <= green_scale <= 1 + - 0 <= blue_scale <= 1 ensures - - This constructor generates a random color transform which can be applied - by calling this object's operator() method. + - This constructor generates a color transform which can be applied by + calling this object's operator() method. - The color transform is a gamma correction and color rebalancing. If - gamma_magnitude == 0 and color_magnitude == 0 then the transform doesn't - change any colors at all. However, the larger these parameters the more - noticeable the resulting transform. + gamma == 1, red_scale == 1, green_scale == 1 and blue_scale == 1 then + the transform doesn't change any colors at all. However, the farther + away from 1 these parameters are, the more noticeable the resulting + transform. + !*/ + + rgb_pixel operator()( + rgb_pixel p + ) const; + /*! + ensures + - returns the color transformed version of p. + !*/ + + double get_gamma() const; + /*! + ensures + - returns the gamma used in this color transform. + !*/ + + double get_red_scale() const; + /*! + ensures + - returns the red scale used in this color transform. + !*/ + + double get_green_scale() const; + /*! + ensures + - returns the green scale used in this color transform. + !*/ + + double get_blue_scale() const; + /*! + ensures + - returns the blue scale used in this color transform. + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + class inv_color_transform + { + /*! + WHAT THIS OBJECT REPRESENTS + This object generates a color balancing and gamma correction transform. + It then allows you to apply that specific transform to as many + rgb_pixel objects as you like. In particular, it generates the inverse + transform of the one constructed by color_transform with the same + parameters. + !*/ + + public: + + color_transform ( + const color_transform& tform + ); + /*! + ensures + - This constructor generates a color transform which can be applied by + calling this object's operator() method. + - The resulting transform is the inverse of tform, which can be used to + undo the effect of tform. !*/ rgb_pixel operator()( @@ -46,14 +109,28 @@ namespace dlib ) const; /*! ensures - - returns the color transformed version of p. + - returns the color transformed version of p. !*/ }; +// ---------------------------------------------------------------------------------------- + + inline color_transform random_color_transform ( + dlib::rand& rnd, + const double gamma_magnitude = 0.5, + const double color_magnitude = 0.2 + ); + /*! + ensures + - returns a random color balancing and gamma corection transform. It then + allows you to apply that specific transform to as many rgb_pixel objects as + you like. + !*/ + // ---------------------------------------------------------------------------------------- template - void disturb_colors ( + color_transform disturb_colors ( image_type& img, dlib::rand& rnd, const double gamma_magnitude = 0.5, @@ -62,11 +139,12 @@ namespace dlib /*! requires - image_type == an image object that implements the interface defined in - dlib/image_processing/generic_image.h + dlib/image_processing/generic_image.h ensures - Applies a random color transform to the given image. This is done by creating a random_color_transform with the given parameters and then transforming each pixel in the image with the resulting transform. + - Returns the color transform used to transform the given image. !*/ // ---------------------------------------------------------------------------------------- @@ -91,4 +169,3 @@ namespace dlib // ---------------------------------------------------------------------------------------- #endif // DLIB_RANDOM_cOLOR_TRANSFORM_ABSTRACT_Hh_ -