Hi.

The calculation used to calculate the spot hue for lightness adjustment
assumes a fixed input RGB profile in its calculations.  This leads to
inaccuracies in the calculation of the hue, causing the adjustment to
apply to the wrong colors.  Typically, this inaccuracy will not be
large, but I have a test image where the current code will not adjust
the selected color spot.

The attached patch calculates a more accurate LCh value for the spot by
running the raw pixel through a CMS transform using the actual input
profile.  This produces noticeably more accurate spots, which results in
more effective adjustments.

-- 
Bruce Guenter <[email protected]>                http://untroubled.org/
diff --git a/ufraw.h b/ufraw.h
index 7a833fb..ce54b14 100644
--- a/ufraw.h
+++ b/ufraw.h
@@ -100,6 +100,7 @@ typedef struct {
     Intent intent[profile_types];
     gboolean updateTransform;
     void *colorTransform;
+    void *rgbtolabTransform;
     double saturation;
 #ifdef UFRAW_CONTRAST
     double contrast;
@@ -389,6 +390,8 @@ int ufraw_process_args(int *argc, char ***argv, conf_data 
*cmd, conf_data *rc);
 void uf_rgb_to_cielch(gint64 rgb[3], float lch[3]);
 // Convert CIE-LCh to linear RGB
 void uf_cielch_to_rgb(float lch[3], gint64 rgb[3]);
+void uf_raw_to_cielch(const developer_data *d,
+                     const guint16 raw[4], float lch[3]);
 developer_data *developer_init();
 void developer_destroy(developer_data *d);
 void developer_profile(developer_data *d, int type, profile_data *p);
diff --git a/ufraw_developer.c b/ufraw_developer.c
index c6d1f77..2b3bffb 100644
--- a/ufraw_developer.c
+++ b/ufraw_developer.c
@@ -65,6 +65,7 @@ developer_data *developer_init()
     d->intent[display_profile] = -1;
     d->updateTransform = TRUE;
     d->colorTransform = NULL;
+    d->rgbtolabTransform = NULL;
     d->grayscaleMode = -1;
     d->grayscaleMixer[0] = d->grayscaleMixer[1] = d->grayscaleMixer[2] = -1;
     cmsSetErrorHandler(lcms_message);
@@ -84,6 +85,8 @@ void developer_destroy(developer_data *d)
     cmsCloseProfile(d->adjustmentProfile);
     if (d->colorTransform!=NULL)
        cmsDeleteTransform(d->colorTransform);
+    if (d->rgbtolabTransform!=NULL)
+       cmsDeleteTransform(d->rgbtolabTransform);
     g_free(d);
 }
 
@@ -322,6 +325,8 @@ static void developer_create_transform(developer_data *d, 
DeveloperMode mode)
     d->updateTransform = FALSE;
     if (d->colorTransform!=NULL)
        cmsDeleteTransform(d->colorTransform);
+    if (d->rgbtolabTransform!=NULL)
+       cmsDeleteTransform(d->rgbtolabTransform);
 
     int targetProfile;
     if ( mode==file_developer || mode==auto_developer ) {
@@ -403,6 +408,11 @@ static void developer_create_transform(developer_data *d, 
DeveloperMode mode)
                    cmsFLAGS_SOFTPROOFING);
        }
     }
+    d->rgbtolabTransform = cmsCreateTransform(d->profile[in_profile], 
+                                             TYPE_RGB_16,
+                                             cmsCreateLabProfile(cmsD50_xyY()),
+                                             TYPE_Lab_16,
+                                             INTENT_ABSOLUTE_COLORIMETRIC, 0);
 }
 
 static gboolean test_adjustments(const lightness_adjustment 
values[max_adjustments],
@@ -623,6 +633,30 @@ void developer_prepare(developer_data *d, conf_data *conf,
     developer_create_transform(d, mode);
 }
 
+static void apply_matrix(const developer_data *d,
+                        const gint64 in[4],
+                        gint64 out[3])
+{
+    gint64 tmp;
+    unsigned c, cc;
+    for (cc=0; cc<3; cc++) {
+       tmp = 0;
+       for (c=0; c<d->colors; c++)
+           tmp += in[c] * d->colorMatrix[cc][c];
+       out[cc] = MAX(tmp/0x10000, 0);
+    }
+}
+
+static void cond_apply_matrix(const developer_data *d,
+                             const gint64 in[4],
+                             gint64 out[3])
+{
+    if (d->useMatrix)
+       apply_matrix(d, in, out);
+    else
+       memcpy(out, in, 3 * sizeof out[0]);
+}
+
 extern const double xyz_rgb[3][3];
 static const double rgb_xyz[3][3] = {                  /* RGB from XYZ */
     { 3.24048, -1.53715, -0.498536 },
@@ -690,6 +724,32 @@ void uf_cielch_to_rgb(float lch[3], gint64 rgb[3])
     }
 }
 
+void uf_raw_to_cielch(const developer_data *d,
+                     const guint16 raw[4],
+                     float lch[3])
+{
+    gint64 tmp[4];
+    guint16 rgbpixel[3];
+    guint16 labpixel[3];
+    cmsCIELab Lab;
+    cmsCIELCh LCh;
+    unsigned int c;
+
+    for (c = 0; c < d->colors; ++c)
+       tmp[c] = (guint64)raw[c] * d->rgbWB[c] / 0x10000;
+    cond_apply_matrix(d, tmp, tmp);
+    for (c = 0; c < 3; ++c)
+       rgbpixel[c] = tmp[c];
+
+    cmsDoTransform(d->rgbtolabTransform, rgbpixel, labpixel, 1);
+
+    cmsLabEncoded2Float(&Lab, labpixel);
+    cmsLab2LCh(&LCh, &Lab);
+    lch[0] = LCh.L;
+    lch[1] = LCh.C;
+    lch[2] = LCh.h;
+}
+
 static void MaxMidMin(const gint64 p[3], int *maxc, int *midc, int *minc)
 {
     gint64 a = p[0];
@@ -802,8 +862,8 @@ static void develop_grayscale(guint16 *pixel, const 
developer_data *d)
 
 void develop_linear(guint16 in[4], guint16 out[3], developer_data *d)
 {
-    unsigned c, cc;
-    gint64 tmppix[4], tmp;
+    unsigned c;
+    gint64 tmppix[4];
     gboolean clipped = FALSE;
     for (c=0; c<d->colors; c++) {
        /* Set WB, normalizing tmppix[c]<0x10000 */
@@ -826,25 +886,9 @@ void develop_linear(guint16 in[4], guint16 out[3], 
developer_data *d)
         * to "1.0" (full exposure). Still the maximal value can be
         * d->exposure * 0x10000 / d->max */
        gint64 unclippedPix[3], clippedPix[3];
-       if ( d->useMatrix ) {
-           for (cc=0; cc<3; cc++) {
-               for (c=0, tmp=0; c<d->colors; c++)
-                   tmp += tmppix[c] * d->colorMatrix[cc][c];
-               unclippedPix[cc] = MAX(tmp/0x10000, 0);
-           }
-       } else {
-           for (c=0; c<3; c++) unclippedPix[c] = tmppix[c];
-       }
+       cond_apply_matrix(d, tmppix, unclippedPix);
        for (c=0; c<3; c++) tmppix[c] = MIN(tmppix[c], d->exposure);
-       if ( d->useMatrix ) {
-           for (cc=0; cc<3; cc++) {
-               for (c=0, tmp=0; c<d->colors; c++)
-                   tmp += tmppix[c] * d->colorMatrix[cc][c];
-               clippedPix[cc] = MAX(tmp/0x10000, 0);
-           }
-       } else {
-           for (c=0; c<3; c++) clippedPix[c] = tmppix[c];
-       }
+       cond_apply_matrix(d, tmppix, clippedPix);
        if ( d->restoreDetails==restore_lch_details ) {
            float lch[3], clippedLch[3], unclippedLch[3];
            uf_rgb_to_cielch(unclippedPix, unclippedLch);
@@ -899,14 +943,8 @@ void develop_linear(guint16 in[4], guint16 out[3], 
developer_data *d)
            tmppix[midc] = lum * (0x10000-sat + sat*hue/0x10000) / 0x10000;
        }
     } else { /* !clipped */
-       if (d->useMatrix) {
-           gint64 tmp[3];
-           for (cc=0; cc<3; cc++) {
-               for (c=0, tmp[cc]=0; c<d->colors; c++)
-                   tmp[cc] += tmppix[c] * d->colorMatrix[cc][c];
-           }
-           for (c=0; c<3; c++) tmppix[c] = MAX(tmp[c]/0x10000, 0);
-       }
+       if (d->useMatrix)
+           apply_matrix(d, tmppix, tmppix);
        gint64 max = tmppix[0];
        for (c=1; c<3; c++) max = MAX(tmppix[c], max);
        if (max > 0xFFFF) {
diff --git a/ufraw_preview.c b/ufraw_preview.c
index ca1af2c..1487ba1 100644
--- a/ufraw_preview.c
+++ b/ufraw_preview.c
@@ -1238,10 +1238,10 @@ static gboolean render_spot(preview_data *data)
      * The RGB color space is approximately linearized sRGB as it is not
      * affected from the ICC profile.
      */
-    guint16 rawChannels[4], linearChannels[3];
+    guint16 linearChannels[3];
     for (c=0; c<data->UF->colors; c++)
-       rawChannels[c] = rawSum[c] / (spotWidth * spotHeight);
-    develop_linear(rawChannels, linearChannels, Developer);
+       data->SpotRaw[c] = rawSum[c] / (spotWidth * spotHeight);
+    develop_linear(data->SpotRaw, linearChannels, Developer);
     double yValue = 0.5;
     extern const double xyz_rgb[3][3];
     for (c=0; c<3; c++)
@@ -1261,14 +1261,6 @@ static gboolean render_spot(preview_data *data)
     if ( data->PageNum!=data->PageNumCrop )
        draw_spot(data, TRUE);
 
-    // Calculate hue for future use
-    gint64 rgb64[3];
-    for (c=0; c<3; c++) rgb64[c] = linearChannels[c];
-    float lch[3];
-    uf_rgb_to_cielch(rgb64, lch);
-    data->SpotHue = lch[2] * 180 / M_PI;
-    if (data->SpotHue < 0.0) data->SpotHue += 360;
-
     return FALSE;
 }
 
@@ -1278,7 +1270,6 @@ static void close_spot(GtkWidget *widget, gpointer 
user_data)
     preview_data *data = get_preview_data(widget);
     draw_spot(data, FALSE);
     data->SpotX1 = -1;
-    data->SpotHue = -1.0;
     gtk_widget_hide(GTK_WIDGET(data->SpotTable));
 }
 
@@ -1545,9 +1536,12 @@ static void select_hue_event(GtkWidget *widget, gpointer 
user_data)
 {
     preview_data *data = get_preview_data(widget);
     long i = (long)user_data;
+    float lch[3];
 
     if (data->FreezeDialog) return;
-    if (data->SpotHue < 0.0) return;
+    if (data->SpotX1 == -1) return;
+
+    uf_raw_to_cielch(Developer, data->SpotRaw, lch);
 
     if (i < 0) {
        if (CFG->lightnessAdjustmentCount >= max_adjustments) {
@@ -1557,10 +1551,10 @@ static void select_hue_event(GtkWidget *widget, 
gpointer user_data)
        i = CFG->lightnessAdjustmentCount++;
     }
 
-    CFG->lightnessAdjustment[i].hue = data->SpotHue;
+    CFG->lightnessAdjustment[i].hue = lch[2];
     CFG->lightnessAdjustment[i].hueWidth = 60;
 
-    widget_set_hue(data->LightnessHueSelectButton[i], data->SpotHue);
+    widget_set_hue(data->LightnessHueSelectButton[i], lch[2]);
     gtk_widget_show_all(GTK_WIDGET(data->LightnessAdjustmentTable[i]));
 
     preview_invalidate_layer (data, ufraw_develop_phase);
@@ -4991,7 +4985,6 @@ int ufraw_preview(ufraw_data *uf, conf_data *rc, int 
plugin,
     data->SpotX2 = -1;
     data->SpotY1 = -1;
     data->SpotY2 = -1;
-    data->SpotHue = -1.0;
     data->SpotDraw = FALSE;
     data->FreezeDialog = TRUE;
     data->DrawnCropX1 = 0;
diff --git a/ufraw_ui.h b/ufraw_ui.h
index 2307d74..49c1a47 100644
--- a/ufraw_ui.h
+++ b/ufraw_ui.h
@@ -158,7 +158,7 @@ typedef struct {
     /* Since the event-box can be larger than the preview pixbuf we need: */
     gboolean PreviewButtonPressed, SpotDraw;
     int SpotX1, SpotY1, SpotX2, SpotY2;
-    double SpotHue;
+    guint16 SpotRaw[4];
     CursorType CropMotionType;
     int DrawnCropX1, DrawnCropX2, DrawnCropY1, DrawnCropY2;
     double unnormalized_angle;

Attachment: pgp7rY7q3tSrd.pgp
Description: PGP signature

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
ufraw-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ufraw-devel

Reply via email to