Skip to content

Commit d6a1049

Browse files
Gamma corrected pipe input scaling
Non-raw images can have gamma corrected data as input possibly leading to bad results while we do the initial scaling. This scaling happens when generating the mipmap via `_init_f` and when inserting data into the pixelpipes. What we do now: - we test for the image having exif data as sRGB or AdobeRGB. - the colorin module does a much better check than exif data and possibly sets the profile type to any RGB mode. We keep track on this when setting the input profile and possibly change the image->colorspace (making sure to leave the exif checked data as they are). - dt_iop_clip_and_zoom() got an extra gboolean parameter `gamma`, if that is true the interpolation is encapsulated in rgb->linear and linear->rgb conversions. This results in improved data visualizing for all pipes and data taken from the preview pipe. Reminder: 1. As this is only effective for non-raw images we should likely stay in linear space and let colorin module handle this. 2. Should we avoid the conversions for upscaling?
1 parent 5a83bb9 commit d6a1049

File tree

7 files changed

+79
-17
lines changed

7 files changed

+79
-17
lines changed

src/common/image.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ typedef enum dt_image_colorspace_t
107107
{
108108
DT_IMAGE_COLORSPACE_NONE,
109109
DT_IMAGE_COLORSPACE_SRGB,
110-
DT_IMAGE_COLORSPACE_ADOBE_RGB
110+
DT_IMAGE_COLORSPACE_ADOBE_RGB,
111+
DT_IMAGE_COLORSPACE_USER_RGB
111112
} dt_image_colorspace_t;
112113

113114
typedef struct dt_image_raw_parameters_t

src/common/iop_profile.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "common/debug.h"
2323
#include "common/imagebuf.h"
2424
#include "common/matrices.h"
25+
#include "common/image_cache.h"
2526
#include "control/control.h"
2627
#include "develop/imageop.h"
2728
#include "develop/imageop_math.h"
@@ -920,8 +921,25 @@ dt_ioppr_set_pipe_input_profile_info(struct dt_develop_t *dev,
920921
profile_info = dt_ioppr_add_profile_info_to_list(dev, DT_COLORSPACE_LIN_REC2020, "", intent);
921922
}
922923

923-
if(profile_info->type >= DT_COLORSPACE_EMBEDDED_ICC
924-
&& profile_info->type <= DT_COLORSPACE_ALTERNATE_MATRIX)
924+
const dt_imgid_t imgid = dev->image_storage.id;
925+
const dt_image_t *cimg = dt_image_cache_get(imgid, 'r');
926+
const dt_image_colorspace_t ocsp = cimg->colorspace;
927+
dt_image_cache_read_release(cimg);
928+
929+
const dt_colorspaces_color_profile_type_t ptype = profile_info->type;
930+
const gboolean exif_rgb = ocsp == DT_IMAGE_COLORSPACE_SRGB || ocsp == DT_IMAGE_COLORSPACE_ADOBE_RGB;
931+
const gboolean new_rgb = ptype == DT_COLORSPACE_SRGB || ptype == DT_COLORSPACE_ADOBERGB;
932+
const gboolean user_rgb = ocsp == DT_IMAGE_COLORSPACE_USER_RGB;
933+
if(!exif_rgb // don't fiddle with existing exif data
934+
&& ((new_rgb && !user_rgb) || (!new_rgb && user_rgb)))
935+
{
936+
dt_image_t *wimg = dt_image_cache_get(imgid, 'w');
937+
wimg->colorspace = new_rgb ? DT_IMAGE_COLORSPACE_USER_RGB : DT_IMAGE_COLORSPACE_NONE;
938+
dt_image_cache_write_release_info(wimg, DT_IMAGE_CACHE_RELAXED, NULL);
939+
}
940+
941+
if(ptype >= DT_COLORSPACE_EMBEDDED_ICC
942+
&& ptype <= DT_COLORSPACE_ALTERNATE_MATRIX)
925943
{
926944
/* We have a camera input matrix, these are not generated from files but in colorin,
927945
* so we need to fetch and replace them from somewhere.

src/common/mipmap_cache.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,10 +1379,12 @@ static void _init_f(dt_mipmap_buffer_t *mipmap_buf,
13791379
}
13801380
else
13811381
{
1382-
// downsample
1382+
// scale
1383+
const gboolean gamma = image->colorspace != DT_IMAGE_COLORSPACE_NONE;
13831384
dt_print_pipe(DT_DEBUG_PIPE,
1384-
"mipmap clip and zoom", NULL, NULL, DT_DEVICE_CPU, &roi_in, &roi_out);
1385-
dt_iop_clip_and_zoom(out, (const float *)buf.buf, &roi_out, &roi_in);
1385+
"mipmap clip&zoom", NULL, NULL, DT_DEVICE_NONE, &roi_in, &roi_out, "%s",
1386+
gamma ? "gamma corrected" : "");
1387+
dt_iop_clip_and_zoom(out, (const float *)buf.buf, &roi_out, &roi_in, gamma);
13861388
}
13871389

13881390
dt_mipmap_cache_release(&buf);

src/develop/imageop_math.c

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,15 +144,55 @@ void dt_iop_clip_and_zoom_8(const uint8_t *i,
144144
}
145145
}
146146

147-
// apply clip and zoom on parts of a supplied full image.
148-
// roi_in and roi_out define which part to work on.
147+
/* apply clip and zoom on parts of a supplied full image, roi_in and roi_out define which part to work on.
148+
gamma correction around scaling supported.
149+
full RGB->linear and backwards transformation is provided with a performance
150+
penalty without doing significant quality improvements as we only down/upscale.
151+
To do so requires commenting the #define JUST_GAMMA
152+
*/
153+
#define JUST_GAMMA
149154
void dt_iop_clip_and_zoom(float *out,
150155
const float *const in,
151156
const dt_iop_roi_t *const roi_out,
152-
const dt_iop_roi_t *const roi_in)
157+
const dt_iop_roi_t *const roi_in,
158+
const gboolean gamma)
153159
{
154160
const dt_interpolation_t *itor = dt_interpolation_new(DT_INTERPOLATION_USERPREF);
155-
dt_interpolation_resample(itor, out, roi_out, in, roi_in);
161+
float *linear = gamma ? dt_alloc_align_float((size_t)roi_in->width * roi_in->height * 4) : NULL;
162+
if(!linear)
163+
return dt_interpolation_resample(itor, out, roi_out, in, roi_in);
164+
165+
#ifdef JUST_GAMMA
166+
static const dt_aligned_pixel_t two_point_four = { 2.4f, 2.4f, 2.4f, 2.4f };
167+
#endif
168+
static const dt_aligned_pixel_t rev_two_point_four = { 1.0f / 2.4f, 1.0f / 2.4f, 1.0f / 2.4f, 1.0f / 2.4f };
169+
170+
DT_OMP_SIMD(aligned(in, linear : 16))
171+
for(size_t k = 0; k < (size_t)roi_in->width * roi_in->height*4; k += 4)
172+
#ifdef JUST_GAMMA
173+
dt_vector_powf(&in[k], two_point_four, &linear[k]);
174+
#else
175+
dt_sRGB_to_linear_sRGB(&in[k], &linear[k]);
176+
#endif
177+
178+
dt_interpolation_resample(itor, out, roi_out, linear, roi_in);
179+
dt_free_align(linear);
180+
181+
DT_OMP_SIMD(aligned(out : 16))
182+
for(size_t k = 0; k < (size_t)roi_out->width * roi_out->height * 4; k += 4)
183+
#ifdef JUST_GAMMA
184+
dt_vector_powf(&out[k], rev_two_point_four, &out[k]);
185+
#else
186+
{
187+
dt_aligned_pixel_t toe;
188+
dt_aligned_pixel_t curved;
189+
for_each_channel(c)
190+
toe[c] = 12.92f * out[k+c];
191+
dt_vector_powf(&out[k], rev_two_point_four, curved);
192+
for_each_channel(c)
193+
out[k+c] = (out[k+c] <= 0.0031308f) ? toe[c] : (1.055f * curved[c] - 0.055f);
194+
}
195+
#endif
156196
}
157197

158198
// apply clip and zoom on the image region supplied in the input buffer.

src/develop/imageop_math.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ void dt_iop_flip_and_zoom_8(const uint8_t *in, int32_t iw, int32_t ih, uint8_t *
3434

3535
/** for homebrew pixel pipe: zoom pixel array. */
3636
void dt_iop_clip_and_zoom(float *out, const float *const in, const struct dt_iop_roi_t *const roi_out,
37-
const struct dt_iop_roi_t *const roi_in);
37+
const struct dt_iop_roi_t *const roi_in, const gboolean gamma);
3838

3939
/** zoom pixel array for roi buffers. */
4040
void dt_iop_clip_and_zoom_roi(float *out, const float *const in, const struct dt_iop_roi_t *const roi_out,

src/develop/pixelpipe_hb.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,15 +1724,16 @@ static gboolean _dev_pixelpipe_process_rec(dt_dev_pixelpipe_t *pipe,
17241724
roi_in.height = pipe->iheight;
17251725
roi_in.scale = 1.0f;
17261726
const gboolean valid_bpp = (bpp == 4 * sizeof(float));
1727-
1727+
const gboolean gamma = dev->image_storage.colorspace != DT_IMAGE_COLORSPACE_NONE;
17281728
dt_print_pipe(DT_DEBUG_PIPE,
17291729
"pipe data: clip&zoom",
1730-
pipe, module, DT_DEVICE_CPU, &roi_in, roi_out, "%s%s",
1731-
valid_bpp ? "" : "requires 4 floats data",
1732-
aligned_input ? "" : "non-aligned input buffer");
1730+
pipe, module, DT_DEVICE_CPU, &roi_in, roi_out, "%s%s%s",
1731+
valid_bpp ? "" : "requires 4 floats data ",
1732+
aligned_input ? "" : "non-aligned input buffer ",
1733+
gamma ? "gamma corrected" : "");
17331734

17341735
if(valid_bpp && aligned_input)
1735-
dt_iop_clip_and_zoom(*output, pipe->input, roi_out, &roi_in);
1736+
dt_iop_clip_and_zoom(*output, pipe->input, roi_out, &roi_in, gamma);
17361737
else
17371738
{
17381739
memset(*output, 0, (size_t)roi_out->width * roi_out->height * bpp);

src/iop/finalscale.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ void process(dt_iop_module_t *self,
186186
if(exporting)
187187
dt_iop_clip_and_zoom_roi((float *)ovoid, (float *)ivoid, roi_out, roi_in);
188188
else
189-
dt_iop_clip_and_zoom((float *)ovoid, (float *)ivoid, roi_out, roi_in);
189+
dt_iop_clip_and_zoom((float *)ovoid, (float *)ivoid, roi_out, roi_in, FALSE);
190190
}
191191

192192
void commit_params(dt_iop_module_t *self,

0 commit comments

Comments
 (0)