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 <davis685@gmail.com>
This commit is contained in:
Adrià Arrufat 2024-02-21 20:44:15 +09:00 committed by GitHub
parent 631c47c7fd
commit f775b55cd9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 183 additions and 41 deletions

View File

@ -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<unsigned char> 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<unsigned char>(std::pow(k / 255.0, 1 / gamma) / red_scale + 0.5);
}
for (int k = 0; k < 256; ++k)
{
table[i++] = static_cast<unsigned char>(std::pow(k / 255.0, 1 / gamma) / green_scale + 0.5);
}
for (int k = 0; k < 256; ++k)
{
table[i++] = static_cast<unsigned char>(std::pow(k / 255.0, 1 / gamma) / blue_scale + 0.5);
}
}
rgb_pixel operator()(rgb_pixel p) const
{
p.red = table[static_cast<unsigned int>(p.red)];
p.green = table[static_cast<unsigned int>(p.green + 256)];
p.blue = table[static_cast<unsigned int>(p.blue + 512)];
return p;
}
private:
std::vector<unsigned char> 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 <typename image_type>
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<image_type> 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<double,3,3> 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<double,3,1> 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<image_type> img(img_);
for (long r = 0; r < img.nr(); ++r)
@ -154,4 +220,3 @@ namespace dlib
}
#endif // DLIB_RANDOM_cOLOR_TRANSFORM_Hh_

View File

@ -12,33 +12,37 @@ 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()(
@ -46,14 +50,87 @@ namespace dlib
) const;
/*!
ensures
- returns the color transformed version of p.
- 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()(
rgb_pixel p
) const;
/*!
ensures
- 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 <typename image_type>
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_