PNMImage::gamma_correct()

This commit is contained in:
David Rose 2011-11-05 01:37:36 +00:00
parent 425fa2608e
commit 003aa9e3dd
5 changed files with 210 additions and 22 deletions

View File

@ -145,6 +145,16 @@ cmod(float x, float y) {
return x - cfloor(x / y) * y;
}
////////////////////////////////////////////////////////////////////
// Function: cpow
// Description:
////////////////////////////////////////////////////////////////////
INLINE float
cpow(float x, float y) {
return powf(x, y);
}
////////////////////////////////////////////////////////////////////
// Function: cfloor
// Description:
@ -317,6 +327,15 @@ cmod(double x, double y) {
return x - cfloor(x / y) * y;
}
////////////////////////////////////////////////////////////////////
// Function: cpow
// Description:
////////////////////////////////////////////////////////////////////
INLINE double
cpow(double x, double y) {
return pow(x, y);
}
////////////////////////////////////////////////////////////////////
// Function: cnan
// Description:

View File

@ -43,6 +43,7 @@ INLINE float catan2(float y, float x);
INLINE float casin(float v);
INLINE float cacos(float v);
INLINE float cmod(float x, float y);
INLINE float cpow(float x, float y);
INLINE double cfloor(double f);
INLINE double cceil(double f);
@ -58,6 +59,7 @@ INLINE double catan2(double y, double x);
INLINE double casin(double v);
INLINE double cacos(double v);
INLINE double cmod(double x, double y);
INLINE double cpow(double x, double y);
// Returns true if the number is nan, false if it's a genuine number
// or infinity.

View File

@ -834,6 +834,71 @@ gaussian_filter(double radius) {
gaussian_filter_from(radius, *this);
}
////////////////////////////////////////////////////////////////////
// Function: PNMImage::gamma_correct
// Access: Published
// Description: Assuming the image was constructed with a gamma curve
// of from_gamma in the RGB channels, converts it to an
// image with a gamma curve of to_gamma in the RGB
// channels. Does not affect the alpha channel.
////////////////////////////////////////////////////////////////////
INLINE void PNMImage::
gamma_correct(double from_gamma, double to_gamma) {
apply_exponent(from_gamma / to_gamma);
}
////////////////////////////////////////////////////////////////////
// Function: PNMImage::gamma_correct_alpha
// Access: Published
// Description: Assuming the image was constructed with a gamma curve
// of from_gamma in the alpha channel, converts it to an
// image with a gamma curve of to_gamma in the alpha
// channel. Does not affect the RGB channels.
////////////////////////////////////////////////////////////////////
INLINE void PNMImage::
gamma_correct_alpha(double from_gamma, double to_gamma) {
apply_exponent(1.0, from_gamma / to_gamma);
}
////////////////////////////////////////////////////////////////////
// Function: PNMImage::apply_exponent
// Access: Published
// Description: Adjusts each channel of the image by raising the
// corresponding component value to the indicated
// exponent, such that L' = L ^ exponent.
////////////////////////////////////////////////////////////////////
INLINE void PNMImage::
apply_exponent(double gray_exponent) {
apply_exponent(gray_exponent, gray_exponent, gray_exponent, 1.0);
}
////////////////////////////////////////////////////////////////////
// Function: PNMImage::apply_exponent
// Access: Published
// Description: Adjusts each channel of the image by raising the
// corresponding component value to the indicated
// exponent, such that L' = L ^ exponent.
////////////////////////////////////////////////////////////////////
INLINE void PNMImage::
apply_exponent(double gray_exponent, double alpha_exponent) {
apply_exponent(gray_exponent, gray_exponent, gray_exponent, alpha_exponent);
}
////////////////////////////////////////////////////////////////////
// Function: PNMImage::apply_exponent
// Access: Published
// Description: Adjusts each channel of the image by raising the
// corresponding component value to the indicated
// exponent, such that L' = L ^ exponent. For a
// grayscale image, the blue_exponent value is used for
// the grayscale value, and red_exponent and
// green_exponent are unused.
////////////////////////////////////////////////////////////////////
INLINE void PNMImage::
apply_exponent(double red_exponent, double green_exponent, double blue_exponent) {
apply_exponent(red_exponent, green_exponent, blue_exponent, 1.0);
}
////////////////////////////////////////////////////////////////////
// Function: PNMImage::allocate_array

View File

@ -226,26 +226,6 @@ alpha_fill_val(xelval alpha) {
}
}
////////////////////////////////////////////////////////////////////
// Function: PNMImage::remix_channels
// Access: Published
// Description: Transforms every pixel using the operation
// (Ro,Go,Bo) = conv.xform_point(Ri,Gi,Bi);
// Input must be a color image.
////////////////////////////////////////////////////////////////////
void PNMImage::
remix_channels(const LMatrix4 &conv) {
int nchannels = get_num_channels();
nassertv((nchannels >= 3) && (nchannels <= 4));
for (int y = 0; y < get_y_size(); y++) {
for (int x = 0; x < get_x_size(); x++) {
LVector3 inv(get_red(x,y),get_green(x,y),get_blue(x,y));
LVector3 outv(conv.xform_point(inv));
set_xel(x,y,outv[0],outv[1],outv[2]);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: PNMImage::read
// Access: Published
@ -1296,6 +1276,122 @@ perlin_noise_fill(StackedPerlinNoise2 &perlin) {
}
}
////////////////////////////////////////////////////////////////////
// Function: PNMImage::remix_channels
// Access: Published
// Description: Transforms every pixel using the operation
// (Ro,Go,Bo) = conv.xform_point(Ri,Gi,Bi);
// Input must be a color image.
////////////////////////////////////////////////////////////////////
void PNMImage::
remix_channels(const LMatrix4 &conv) {
int nchannels = get_num_channels();
nassertv((nchannels >= 3) && (nchannels <= 4));
for (int y = 0; y < get_y_size(); y++) {
for (int x = 0; x < get_x_size(); x++) {
LVector3 inv(get_red(x,y), get_green(x,y), get_blue(x,y));
LVector3 outv(conv.xform_point(inv));
set_xel(x, y, outv[0], outv[1], outv[2]);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: PNMImage::apply_exponent
// Access: Published
// Description: Adjusts each channel of the image by raising the
// corresponding component value to the indicated
// exponent, such that L' = L ^ exponent. For a
// grayscale image, the blue_exponent value is used for
// the grayscale value, and red_exponent and
// green_exponent are unused.
////////////////////////////////////////////////////////////////////
void PNMImage::
apply_exponent(double red_exponent, double green_exponent, double blue_exponent,
double alpha_exponent) {
int num_channels = _num_channels;
if (has_alpha() && alpha_exponent == 1.0) {
// If the alpha_exponent is 1, don't bother to apply it.
--num_channels;
}
int x, y;
if (red_exponent == 1.0 && green_exponent == 1.0 && blue_exponent == 1.0) {
// If the RGB components are all 1, apply only to the alpha channel.
switch (num_channels) {
case 1:
case 3:
break;
case 2:
case 4:
for (y = 0; y < _y_size; ++y) {
for (x = 0; x < _x_size; ++x) {
double alpha = get_alpha(x, y);
alpha = cpow(alpha, blue_exponent);
set_alpha(x, y, alpha);
}
}
break;
}
} else {
// Apply to the color and/or alpha channels.
switch (num_channels) {
case 1:
for (y = 0; y < _y_size; ++y) {
for (x = 0; x < _x_size; ++x) {
double gray = get_gray(x, y);
gray = cpow(gray, blue_exponent);
set_gray(x, y, gray);
}
}
break;
case 2:
for (y = 0; y < _y_size; ++y) {
for (x = 0; x < _x_size; ++x) {
double gray = get_gray(x, y);
gray = cpow(gray, blue_exponent);
set_gray(x, y, gray);
double alpha = get_alpha(x, y);
alpha = cpow(alpha, blue_exponent);
set_alpha(x, y, alpha);
}
}
break;
case 3:
for (y = 0; y < _y_size; ++y) {
for (x = 0; x < _x_size; ++x) {
LRGBColord color = get_xel(x, y);
color[0] = cpow(color[0], red_exponent);
color[1] = cpow(color[1], green_exponent);
color[2] = cpow(color[2], blue_exponent);
set_xel(x, y, color);
}
}
break;
case 4:
for (y = 0; y < _y_size; ++y) {
for (x = 0; x < _x_size; ++x) {
LColord color = get_xel_a(x, y);
color[0] = cpow(color[0], red_exponent);
color[1] = cpow(color[1], green_exponent);
color[2] = cpow(color[2], blue_exponent);
color[3] = cpow(color[3], alpha_exponent);
set_xel_a(x, y, color);
}
}
break;
}
}
}
////////////////////////////////////////////////////////////////////
// Function: PNMImage::setup_rc
// Access: Private

View File

@ -81,8 +81,6 @@ PUBLISHED:
INLINE void fill(double red, double green, double blue);
INLINE void fill(double gray = 0.0);
void remix_channels(const LMatrix4 &conv);
void fill_val(xelval red, xelval green, xelval blue);
INLINE void fill_val(xelval gray = 0);
@ -236,6 +234,14 @@ PUBLISHED:
unsigned long seed = 0);
void perlin_noise_fill(StackedPerlinNoise2 &perlin);
void remix_channels(const LMatrix4 &conv);
INLINE void gamma_correct(double from_gamma, double to_gamma);
INLINE void gamma_correct_alpha(double from_gamma, double to_gamma);
INLINE void apply_exponent(double gray_exponent);
INLINE void apply_exponent(double gray_exponent, double alpha_exponent);
INLINE void apply_exponent(double red_exponent, double green_exponent, double blue_exponent);
void apply_exponent(double red_exponent, double green_exponent, double blue_exponent, double alpha_exponent);
LRGBColord get_average_xel() const;
LColord get_average_xel_a() const;
double get_average_gray() const;