[Rawstudio-dev] [PATCH 3 of 3] Use the curve as a luminance curve only

Edouard Gomez ed.gomez at free.fr
Fri Aug 24 00:11:05 CEST 2007


Oops... this was an old version that suffered some underflows/overflows
and didn't update histogram to use the new curve usage.

Here is an updated patch... still no SIMD... might come later.

# HG changeset patch
# User Edouard Gomez <ed.gomez at free.fr>
# Date 1187906807 -7200
# Node ID 801212054acbc71bafb82042eea1d1310c4c3c1e
# Parent  46d39ed470f675b7426169ee931a3c88feafbf96
Use the curve as a luminance curve only

diff --git a/src/rs-color-transform.c b/src/rs-color-transform.c
--- a/src/rs-color-transform.c
+++ b/src/rs-color-transform.c
@@ -25,6 +25,13 @@ static void make_tables(RS_COLOR_TRANSFO
 static void make_tables(RS_COLOR_TRANSFORM *rct);
 static gboolean select_render(RS_COLOR_TRANSFORM *rct);
 
+#define LUM_PRECISION 15
+#define RLUMF ((gint)(0.212671f*(1<<LUM_PRECISION)))
+#define GLUMF ((gint)(0.715160f*(1<<LUM_PRECISION)))
+#define BLUMF ((gint)(0.072169f*(1<<LUM_PRECISION)))
+#define HALFF (1<<(LUM_PRECISION-1))
+#define LUM_FIXED(a) ((guint)((a)*(1<<LUM_PRECISION)))
+
 /* Function pointers - initialized by arch binders */
 COLOR_TRANSFORM(*transform_nocms8);
 COLOR_TRANSFORM(*transform_cms8);
@@ -50,6 +57,7 @@ struct _RS_COLOR_TRANSFORM_PRIVATE {
 	gint nknots;
 	gfloat *knots;
 	gfloat curve_samples[65536];
+	guint luminance[65536];
 	void *transform;
 };
 
@@ -308,8 +316,43 @@ make_tables(RS_COLOR_TRANSFORM *rct)
 		nd = ((gdouble) n) * rec65535;
 		nd = pow(nd, gammavalue);
 
-		if (likely(rct->priv->curve_samples))
-			nd = (gdouble) rct->priv->curve_samples[((gint) (nd*65535.0f))];
+		if (likely(rct->priv->curve_samples)) {
+			float Y;
+
+			n = (n>0) ? n : 1;
+
+			/* The idea is to use the curve to boost/dcrease
+			 * luminance only.
+			 * So we have to compute Y, map it to its new value
+			 * and then compute a factor that would keep this
+			 * new luminance if applied to the RGB triplet.
+			 *
+			 * Quite straight forward; let's do it quick...
+			 * Y  = a.R + b.G + c.B
+			 *
+			 * We map Y to Y' according to the curve:
+			 * Y' = curve(Y)
+			 *
+			 * let's compute a real 'd' such that:
+			 * Y' = d.Y
+			 *
+			 * Then we have
+			 * Y' = d.(a.R + b.G + c.B)
+			 * or written a bit differently:
+			 * Y' = a.(d.R) + b.(d.G) + c.(d.B)
+			 *
+			 * So the RGB triplet we are looking for is (d.R, d.G, d.B)
+			 *
+			 * The luminance LUT stores curve(Y)/Y as a fixed point
+			 * value so that it becomes very easy to compute d.(R,G,B)
+			 * even on SIMD CPUs
+			 *
+			 * NB: luminance curve is applied in linear space before
+			 * any gamma */
+			Y = rct->priv->curve_samples[n];
+			Y = Y < 0.f ? 0.f : (Y > 65535.f) ? 65535.f : Y;
+			rct->priv->luminance[n] = LUM_FIXED(Y*65535.f/(float)n);
+		}
 
 		nd = nd*contrast+postadd;
 
@@ -901,6 +944,8 @@ COLOR_TRANSFORM(transform_cms_c)
 		srcoffset = y * in_rowstride;
 		for(x=0 ; x<width ; x++)
 		{
+			guint Y;
+
 			rr = (in[srcoffset+R]*pre_muli[R])>>7;
 			gg = (in[srcoffset+G]*pre_muli[G])>>7;
 			bb = (in[srcoffset+B]*pre_muli[B])>>7;
@@ -915,6 +960,20 @@ COLOR_TRANSFORM(transform_cms_c)
 				+ gg*mati.coeff[2][1]
 				+ bb*mati.coeff[2][2])>>MATRIX_RESOLUTION;
 			_CLAMP65535_TRIPLET(r,g,b);
+
+			// Compute luminance
+			Y = (RLUMF*r + GLUMF*g + BLUMF*b + HALFF)>>LUM_PRECISION;
+
+			// Find the factor to apply to the RGB triplet
+			Y = rct->priv->luminance[Y];
+
+			// Multiplythe RGB triplet using fixed point arithmetic
+			r = (r*Y)>>LUM_PRECISION;
+			g = (g*Y)>>LUM_PRECISION;
+			b = (b*Y)>>LUM_PRECISION;
+
+			_CLAMP65535_TRIPLET(r,g,b);
+
 			buffer[destoffset++] = rct->priv->table16[r];
 			buffer[destoffset++] = rct->priv->table16[g];
 			buffer[destoffset++] = rct->priv->table16[b];
@@ -945,6 +1004,8 @@ COLOR_TRANSFORM(transform_nocms_c)
 		srcoffset = y * in_rowstride;
 		for(x=0 ; x<width ; x++)
 		{
+			guint Y;
+
 			rr = (in[srcoffset+R]*pre_muli[R]+64)>>7;
 			gg = (in[srcoffset+G]*pre_muli[G]+64)>>7;
 			bb = (in[srcoffset+B]*pre_muli[B]+64)>>7;
@@ -959,6 +1020,20 @@ COLOR_TRANSFORM(transform_nocms_c)
 				+ gg*mati.coeff[2][1]
 				+ bb*mati.coeff[2][2])>>MATRIX_RESOLUTION;
 			_CLAMP65535_TRIPLET(r,g,b);
+
+			// Compute luminance
+			Y = (RLUMF*r + GLUMF*g + BLUMF*b + HALFF)>>LUM_PRECISION;
+
+			// Find the factor to apply to the RGB triplet
+			Y = rct->priv->luminance[Y];
+
+			// Multiplythe RGB triplet using fixed point arithmetic
+			r = (r*Y)>>LUM_PRECISION;
+			g = (g*Y)>>LUM_PRECISION;
+			b = (b*Y)>>LUM_PRECISION;
+
+			_CLAMP65535_TRIPLET(r,g,b);
+				
 			d[destoffset++] = rct->priv->table8[r];
 			d[destoffset++] = rct->priv->table8[g];
 			d[destoffset++] = rct->priv->table8[b];
@@ -1005,6 +1080,8 @@ rs_color_transform_make_histogram(RS_COL
 		srcoffset = y * input->rowstride;
 		for(x=0 ; x<input->w ; x++)
 		{
+			guint Y;
+
 			rr = (in[srcoffset+R]*pre_muli[R])>>7;
 			gg = (in[srcoffset+G]*pre_muli[G])>>7;
 			bb = (in[srcoffset+B]*pre_muli[B])>>7;
@@ -1020,6 +1097,19 @@ rs_color_transform_make_histogram(RS_COL
 				+ bb*mati.coeff[2][2])>>MATRIX_RESOLUTION;
 			_CLAMP65535_TRIPLET(r,g,b);
 
+			// Compute luminance
+			Y = (RLUMF*r + GLUMF*g + BLUMF*b + HALFF)>>LUM_PRECISION;
+
+			// Find the factor to apply to the RGB triplet
+			Y = rct->priv->luminance[Y];
+
+			// Multiplythe RGB triplet using fixed point arithmetic
+			r = (r*Y)>>LUM_PRECISION;
+			g = (g*Y)>>LUM_PRECISION;
+			b = (b*Y)>>LUM_PRECISION;
+
+			_CLAMP65535_TRIPLET(r,g,b);
+
 			if (rct->priv->transform != NULL)
 			{
 				buffer16[x*3+R] = r;


-- 
Edouard Gomez



More information about the Rawstudio-dev mailing list