Răsfoiți Sursa

PNMImage::gamma_correct()

David Rose 14 ani în urmă
părinte
comite
003aa9e3dd

+ 19 - 0
dtool/src/dtoolbase/cmath.I

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

+ 2 - 0
dtool/src/dtoolbase/cmath.h

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

+ 65 - 0
panda/src/pnmimage/pnmImage.I

@@ -834,6 +834,71 @@ gaussian_filter(double radius) {
   gaussian_filter_from(radius, *this);
   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
 //     Function: PNMImage::allocate_array

+ 116 - 20
panda/src/pnmimage/pnmImage.cxx

@@ -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
 //     Function: PNMImage::read
 //       Access: Published
 //       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
 //     Function: PNMImage::setup_rc
 //       Access: Private
 //       Access: Private

+ 8 - 2
panda/src/pnmimage/pnmImage.h

@@ -81,8 +81,6 @@ PUBLISHED:
   INLINE void fill(double red, double green, double blue);
   INLINE void fill(double red, double green, double blue);
   INLINE void fill(double gray = 0.0);
   INLINE void fill(double gray = 0.0);
 
 
-  void remix_channels(const LMatrix4 &conv);
-
   void fill_val(xelval red, xelval green, xelval blue);
   void fill_val(xelval red, xelval green, xelval blue);
   INLINE void fill_val(xelval gray = 0);
   INLINE void fill_val(xelval gray = 0);
 
 
@@ -236,6 +234,14 @@ PUBLISHED:
                          unsigned long seed = 0);
                          unsigned long seed = 0);
   void perlin_noise_fill(StackedPerlinNoise2 &perlin);
   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;
   LRGBColord get_average_xel() const;
   LColord get_average_xel_a() const;
   LColord get_average_xel_a() const;
   double get_average_gray() const;
   double get_average_gray() const;