[gimp/metadata-browser] Bug 607928 - Switching from levels to curves does not result in same changes
- From: Roman Joost <romanofski src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/metadata-browser] Bug 607928 - Switching from levels to curves does not result in same changes
- Date: Wed, 12 Sep 2012 22:11:43 +0000 (UTC)
commit 9f52b4b33cf8873d1df761ba27fcb02bd3b40617
Author: Michael Natterer <mitch gimp org>
Date: Wed Nov 2 23:50:53 2011 +0100
Bug 607928 - Switching from levels to curves does not result in same changes
Apply patch from Alexis Wilhelm which nicely approximates the gamma
curve with GimpCurve segments.
app/gegl/gimplevelsconfig.c | 97 ++++++++++++++++++++++++++++++++++++++-----
1 files changed, 86 insertions(+), 11 deletions(-)
---
diff --git a/app/gegl/gimplevelsconfig.c b/app/gegl/gimplevelsconfig.c
index 3b638d1..d78240c 100644
--- a/app/gegl/gimplevelsconfig.c
+++ b/app/gegl/gimplevelsconfig.c
@@ -42,6 +42,7 @@
#include "gimpcurvesconfig.h"
#include "gimplevelsconfig.h"
+#include "gimpoperationlevels.h"
#include "gimp-intl.h"
@@ -598,6 +599,8 @@ gimp_levels_config_to_curves_config (GimpLevelsConfig *config)
{
GimpCurve *curve = curves->curve[channel];
const gint n_points = gimp_curve_get_n_points (curve);
+ static const gint n = 4;
+ gint point = -1;
gdouble gamma = config->gamma[channel];
gdouble delta_in;
gdouble delta_out;
@@ -613,25 +616,97 @@ gimp_levels_config_to_curves_config (GimpLevelsConfig *config)
x = config->low_input[channel];
y = config->low_output[channel];
- gimp_curve_set_point (curve,
- CLAMP (n_points * x, 0, n_points - 1), x, y);
+ point = CLAMP (n_points * x, point + 1, n_points - 1 - n);
+ gimp_curve_set_point (curve, point, x, y);
if (delta_out != 0 && gamma != 1.0)
{
- x = (config->low_input[channel] +
- pow (gamma, gamma / (1 - gamma)) * delta_in);
- y = (config->low_output[channel] +
- pow (gamma, 1.0 / (1 - gamma)) * delta_out);
-
- gimp_curve_set_point (curve,
- CLAMP (n_points * x, 0, n_points - 1), x, y);
+ /* The Levels tool performs gamma correction, which is a
+ * power law, while the Curves tool uses cubic BÃzier
+ * curves. Here we try to approximate this gamma correction
+ * with a BÃzier curve with 5 control points. Two of them
+ * must be (low_input, low_output) and (high_input,
+ * high_output), so we need to add 3 more control points in
+ * the middle.
+ */
+ gint i;
+
+ if (gamma > 1)
+ {
+ /* Case no. 1: Î > 1
+ *
+ * The curve should look like a horizontal
+ * parabola. Since its curvature is greatest when x is
+ * small, we add more control points there, so the
+ * approximation is more accurate. I decided to set the
+ * length of the consecutive segments to xâ, Îâxâ, ÎÂâxâ
+ * and ÎÂâxâ and I saw that the curves looked
+ * good. Still, this is completely arbitrary.
+ */
+ gdouble dx = 0;
+ gdouble x0;
+
+ for (i = 0; i < n; ++i)
+ dx = dx * gamma + 1;
+ x0 = delta_in / dx;
+
+ dx = 0;
+ for (i = 1; i < n; ++i)
+ {
+ dx = dx * gamma + x0;
+ x = config->low_input[channel] + dx;
+ y = config->low_output[channel] + delta_out *
+ gimp_operation_levels_map_input (config, channel, x);
+ point = CLAMP (n_points * x, point + 1, n_points - 1 - n + i);
+ gimp_curve_set_point (curve, point, x, y);
+ }
+ }
+ else
+ {
+ /* Case no. 2: Î < 1
+ *
+ * The curve is the same as the one in case no. 1,
+ * observed through a reflexion along the y = x axis. So
+ * if we invert Î and swap the x and y axes we can use
+ * the same method as in case no. 1.
+ */
+ GimpLevelsConfig *config_inv;
+ gdouble dy = 0;
+ gdouble y0;
+ const gdouble gamma_inv = 1 / gamma;
+
+ config_inv = gimp_config_duplicate (GIMP_CONFIG (config));
+
+ config_inv->gamma[channel] = gamma_inv;
+ config_inv->low_input[channel] = config->low_output[channel];
+ config_inv->low_output[channel] = config->low_input[channel];
+ config_inv->high_input[channel] = config->high_output[channel];
+ config_inv->high_output[channel] = config->high_input[channel];
+
+ for (i = 0; i < n; ++i)
+ dy = dy * gamma_inv + 1;
+ y0 = delta_out / dy;
+
+ dy = 0;
+ for (i = 1; i < n; ++i)
+ {
+ dy = dy * gamma_inv + y0;
+ y = config->low_output[channel] + dy;
+ x = config->low_input[channel] + delta_in *
+ gimp_operation_levels_map_input (config_inv, channel, y);
+ point = CLAMP (n_points * x, point + 1, n_points - 1 - n + i);
+ gimp_curve_set_point (curve, point, x, y);
+ }
+
+ g_object_unref (config_inv);
+ }
}
x = config->high_input[channel];
y = config->high_output[channel];
- gimp_curve_set_point (curve,
- CLAMP (n_points * x, 0, n_points - 1), x, y);
+ point = CLAMP (n_points * x, point + 1, n_points - 1);
+ gimp_curve_set_point (curve, point, x, y);
}
return curves;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]