Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
tonemap.cc
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010-2011 Bruce Guenter.
4 Copyright (C) 2010-2012 Henrik Andersson.
5 Copyright (C) 2010-2013, 2016 johannes hanika.
6 Copyright (C) 2010 Thierry Leconte.
7 Copyright (C) 2011 Jérémy Rosen.
8 Copyright (C) 2011 Olivier Tribout.
9 Copyright (C) 2011 Robert Bieber.
10 Copyright (C) 2011-2014, 2016, 2019 Tobias Ellinghaus.
11 Copyright (C) 2012 John Sheu.
12 Copyright (C) 2012 Richard Wonka.
13 Copyright (C) 2012, 2014 Ulrich Pegelow.
14 Copyright (C) 2013 Simon Spannagel.
15 Copyright (C) 2014-2016 Roman Lebedev.
16 Copyright (C) 2017 Heiko Bauke.
17 Copyright (C) 2018, 2020, 2023, 2025-2026 Aurélien PIERRE.
18 Copyright (C) 2018 Edgardo Hoszowski.
19 Copyright (C) 2018 Maurizio Paglia.
20 Copyright (C) 2018, 2020-2021 Pascal Obry.
21 Copyright (C) 2018 rawfiner.
22 Copyright (C) 2019 luzpaz.
23 Copyright (C) 2020 Aldric Renaudin.
24 Copyright (C) 2020, 2022 Diederik Ter Rahe.
25 Copyright (C) 2020 Ralf Brown.
26 Copyright (C) 2021 Chris Elston.
27 Copyright (C) 2022 Martin Bařinka.
28 Copyright (C) 2022 Philipp Lutz.
29 Copyright (C) 2025 Alynx Zhou.
30
31 darktable is free software: you can redistribute it and/or modify
32 it under the terms of the GNU General Public License as published by
33 the Free Software Foundation, either version 3 of the License, or
34 (at your option) any later version.
35
36 darktable is distributed in the hope that it will be useful,
37 but WITHOUT ANY WARRANTY; without even the implied warranty of
38 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39 GNU General Public License for more details.
40
41 You should have received a copy of the GNU General Public License
42 along with darktable. If not, see <http://www.gnu.org/licenses/>.
43*/
44
45//
46// A tonemapping module using Durand's process :
47// <http://graphics.lcs.mit.edu/~fredo/PUBLI/Siggraph2002/>
48//
49// Use andrew adams et al.'s permutohedral lattice, for fast bilateral filtering
50// See Permutohedral.h
51//
52
53#define __STDC_FORMAT_MACROS
54
55#include "glib.h"
56
57#ifdef HAVE_CONFIG_H
58#include "config.h"
59#endif
60#include <assert.h>
61#include <math.h>
62#include <stdlib.h>
63#include <string.h>
64
65#include "bauhaus/bauhaus.h"
66#include "control/control.h"
67#include "develop/develop.h"
68#include "develop/imageop.h"
69#include "develop/imageop_gui.h"
70
71#include "gui/gtk.h"
72#include "iop/iop_api.h"
73#include <gtk/gtk.h>
74#include <inttypes.h>
75
76
77#include "iop/Permutohedral.h"
78
79extern "C" {
81
83{
84 float contrast; // $MIN: 1.0 $MAX: 5.0 $DEFAULT: 2.5 $DESCRIPTION: "contrast compression"
85 float Fsize; // $MIN: 0.0 $MAX: 100.0 $DEFAULT: 30 $DESCRIPTION: "spatial extent"
87
92
97
98const char *name()
99{
100 return _("tone mapping");
101}
102
103
105{
106 return IOP_GROUP_TONES;
107}
108
113
114const char *deprecated_msg()
115{
116 return _("this module is deprecated. please use the local contrast or tone equalizer module instead.");
117}
118
120{
121 return IOP_CS_RGB;
122}
123
126{
127 default_output_format(self, pipe, piece, dsc);
128}
129
131int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
132 void *const ovoid)
133{
134 const dt_iop_roi_t *const roi_in = &piece->roi_in;
135 const dt_iop_roi_t *const roi_out = &piece->roi_out;
137 const int ch = piece->dsc_in.channels;
138
139 int width, height;
140 float inv_sigma_s;
141 const float inv_sigma_r = 1.0 / 0.4;
142
143 width = roi_in->width;
144 height = roi_in->height;
145 const size_t size = (size_t)width * height;
146 const float iw = piece->buf_in.width * roi_out->scale;
147 const float ih = piece->buf_in.height * roi_out->scale;
148
149 inv_sigma_s = (data->Fsize / 100.0) * fminf(iw, ih);
150 if(inv_sigma_s < 3.0) inv_sigma_s = 3.0;
151 inv_sigma_s = 1.0 / inv_sigma_s;
152
154
155// Build I=log(L)
156// and splat into the lattice
157#ifdef _OPENMP
158#pragma omp parallel for shared(lattice)
159#endif
160 for(int j = 0; j < height; j++)
161 {
162 size_t index = (size_t)j * width;
163 const int thread = omp_get_thread_num();
164 const float *in = (const float *)ivoid + (size_t)j * width * ch;
165 for(int i = 0; i < width; i++, index++, in += ch)
166 {
167 float L = 0.2126 * in[0] + 0.7152 * in[1] + 0.0722 * in[2];
168 if(L <= 0.0) L = 1e-6;
169 L = logf(L);
170 float pos[3] = { i * inv_sigma_s, j * inv_sigma_s, L * inv_sigma_r };
171 float val[2] = { L, 1.0 };
172 lattice.splat(pos, val, index, thread);
173 }
174 }
175
176 lattice.merge_splat_threads();
177
178 // blur the lattice
179 lattice.blur();
180
181 //
182 // Durand process :
183 // r=R/(input intensity), g=G/input intensity, B=B/input intensity
184 // log(base)=Bilateral(log(input intensity))
185 // log(detail)=log(input intensity)-log(base)
186 // log (output intensity)=log(base)*compressionfactor+log(detail)
187 // R output = r*exp(log(output intensity)), etc.
188 //
189 // Simplyfing :
190 // R output = R/(input intensity)*exp(log(output intensity))
191 // = R*exp(log(output intensity)-log(input intensity))
192 // = R*exp(log(base)*compressionfactor+log(input intensity)-log(base)-log(input intensity))
193 // = R*exp(log(base)*(compressionfactor-1))
194 //
195 // Plus :
196 // Before compressing the base intensity , we remove average base intensity in order to not have
197 // variable average intensity when varying compression factor.
198 // after compression we subtract 2.0 to have an average intensity at middle tone.
199 //
200
201 const float contr = 1. / data->contrast;
202#ifdef _OPENMP
203#pragma omp parallel for
204#endif
205 for(int j = 0; j < height; j++)
206 {
207 size_t index = (size_t)j * width;
208 const float *in = (const float *)ivoid + (size_t)j * width * ch;
209 float *out = (float *)ovoid + (size_t)j * width * ch;
210 for(int i = 0; i < width; i++, index++, in += ch, out += ch)
211 {
212 float val[2];
213 lattice.slice(val, index);
214 float L = 0.2126 * in[0] + 0.7152 * in[1] + 0.0722 * in[2];
215 if(L <= 0.0) L = 1e-6;
216 L = logf(L);
217 const float B = val[0] / val[1];
218 const float detail = L - B;
219 const float Ln = expf(B * (contr - 1.0f) + detail - 1.0f);
220
221 out[0] = in[0] * Ln;
222 out[1] = in[1] * Ln;
223 out[2] = in[2] * Ln;
224 out[3] = in[3];
225 }
226 }
227 return 0;
228}
229
230
231// GUI
232//
235{
238 d->contrast = p->contrast;
239 d->Fsize = p->Fsize;
240
241 const float contr = 1.0f / d->contrast;
242 float L = 0.2126f * piece->dsc_in.processed_maximum[0]
243 + 0.7152f * piece->dsc_in.processed_maximum[1]
244 + 0.0722f * piece->dsc_in.processed_maximum[2];
245 if(L <= 0.0f) L = 1e-6f;
246 L = logf(L);
247
248 const float Ln = expf(L * (contr - 1.0f) - 1.0f);
249 for(int k = 0; k < 3; k++) piece->dsc_out.processed_maximum[k] = piece->dsc_in.processed_maximum[k] * Ln;
250}
251
253{
255 piece->data_size = sizeof(dt_iop_tonemapping_data_t);
256}
257
259{
260 dt_free_align(piece->data);
261 piece->data = NULL;
262}
263
264void gui_init(struct dt_iop_module_t *self)
265{
267
268 g->contrast = dt_bauhaus_slider_from_params(self, "contrast");
269
270 g->Fsize = dt_bauhaus_slider_from_params(self, "Fsize");
271 dt_bauhaus_slider_set_format(g->Fsize, "%");
272}
273}
274
275// clang-format off
276// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
277// vim: shiftwidth=2 expandtab tabstop=2 cindent
278// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
279// clang-format on
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
Definition bauhaus.c:3598
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
void slice(float *col, size_t replay_index) const
void splat(float *position, float *value, size_t replay_index, int thread_index=0) const
@ IOP_CS_RGB
#define B(y, x)
const dt_colormatrix_t dt_aligned_pixel_t out
#define dt_free_align(ptr)
Definition darktable.h:481
static void * dt_calloc_align(size_t size)
Definition darktable.h:488
#define omp_get_max_threads()
Definition darktable.h:254
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
Definition darktable.h:151
#define omp_get_thread_num()
Definition darktable.h:255
#define __DT_CLONE_TARGETS__
Definition darktable.h:367
void dt_iop_params_t
Definition dev_history.h:41
void default_output_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
Definition format.c:75
@ IOP_FLAGS_DEPRECATED
Definition imageop.h:168
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:167
@ IOP_GROUP_TONES
Definition imageop.h:137
#define IOP_GUI_ALLOC(module)
Definition imageop.h:599
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
Definition imageop_gui.c:77
void *const ovoid
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
size_t size
Definition mipmap_cache.c:3
struct _GtkWidget GtkWidget
Definition splash.h:29
dt_iop_buffer_dsc_t dsc_out
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
unsigned int channels
Definition format.h:54
dt_aligned_pixel_t processed_maximum
Definition format.h:85
Region of interest passed through the pixelpipe.
Definition imageop.h:72
double scale
Definition imageop.h:74
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition tonemap.cc:233
int default_group()
Definition tonemap.cc:104
__DT_CLONE_TARGETS__ int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid)
Definition tonemap.cc:131
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition tonemap.cc:252
const char * name()
Definition tonemap.cc:98
void output_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
Definition tonemap.cc:124
void gui_init(struct dt_iop_module_t *self)
Definition tonemap.cc:264
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition tonemap.cc:119
int flags()
Definition tonemap.cc:109
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition tonemap.cc:258
const char * deprecated_msg()
Definition tonemap.cc:114