Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
focus.h
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2013-2020 darktable developers.
4 darktable is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 darktable is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with darktable. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#pragma once
19
20#include "common/image_cache.h"
21#include "develop/develop.h"
22
23typedef struct dt_focus_cluster_t
24{
25 int64_t n;
26 float x, y, x2, y2;
27 float thrs;
29
30#define gbuf(BUF, A, B) ((BUF)[4 * (width * ((B)) + ((A))) + ch])
31#define FOCUS_THRS 10
32#define CHANNEL 1
33
34static inline uint8_t _to_uint8(int i)
35{
36 return (uint8_t)CLAMP(i + 127, 0, 255);
37}
38static inline int _from_uint8(uint8_t i)
39{
40 return i - 127;
41}
42static inline void _dt_focus_cdf22_wtf(uint8_t *buf, const int l, const int width, const int height)
43{
44 const int ch = CHANNEL;
45
46 const int step = 1 << l;
47 const int st = step / 2;
48
49#ifdef _OPENMP
50#pragma omp parallel for default(none) \
51 dt_omp_firstprivate(height, st, step, width, ch) \
52 shared(buf) \
53 schedule(static)
54#endif
55 for(int j = 0; j < height; j++)
56 {
57 // rows
58 // predict, get detail
59 int i = st;
60 for(; i < width - st; i += step) /*for(ch=0; ch<3; ch++)*/
61 gbuf(buf, i, j)
62 = _to_uint8((int)gbuf(buf, i, j) - ((int)gbuf(buf, i - st, j) + (int)gbuf(buf, i + st, j)) / 2);
63 if(i < width) /*for(ch=0; ch<3; ch++)*/
64 gbuf(buf, i, j) = _to_uint8(gbuf(buf, i, j) - gbuf(buf, i - st, j));
65 // update coarse
66 /*for(ch=0; ch<3; ch++)*/ gbuf(buf, 0, j) += _from_uint8(gbuf(buf, st, j)) / 2;
67 for(i = step; i < width - st; i += step) /*for(ch=0; ch<3; ch++)*/
68 gbuf(buf, i, j) += (_from_uint8(gbuf(buf, i - st, j)) + _from_uint8(gbuf(buf, i + st, j))) / 4;
69 if(i < width) /*for(ch=0; ch<3; ch++)*/
70 gbuf(buf, i, j) += _from_uint8(gbuf(buf, i - st, j)) / 2;
71 }
72#ifdef _OPENMP
73#pragma omp parallel for default(none) \
74 dt_omp_firstprivate(height, st, step, width, ch) \
75 shared(buf) \
76 schedule(static)
77#endif
78 for(int i = 0; i < width; i++)
79 {
80 // cols
81 int j = st;
82 // predict, get detail
83 for(; j < height - st; j += step) /*for(ch=0; ch<3; ch++)*/
84 gbuf(buf, i, j)
85 = _to_uint8((int)gbuf(buf, i, j) - ((int)gbuf(buf, i, j - st) + (int)gbuf(buf, i, j + st)) / 2);
86 if(j < height) /*for(int ch=0; ch<3; ch++)*/
87 gbuf(buf, i, j) = _to_uint8((int)gbuf(buf, i, j) - (int)gbuf(buf, i, j - st));
88 // update
89 /*for(ch=0; ch<3; ch++)*/ gbuf(buf, i, 0) += _from_uint8(gbuf(buf, i, st)) / 2;
90 for(j = step; j < height - st; j += step) /*for(ch=0; ch<3; ch++)*/
91 gbuf(buf, i, j) += (_from_uint8(gbuf(buf, i, j - st)) + _from_uint8(gbuf(buf, i, j + st))) / 4;
92 if(j < height) /*for(int ch=0; ch<3; ch++)*/
93 gbuf(buf, i, j) += _from_uint8(gbuf(buf, i, j - st)) / 2;
94 }
95}
96
97static void _dt_focus_update(dt_focus_cluster_t *f, int frows, int fcols, int i, int j, int wd, int ht,
98 int diff)
99{
100 const int32_t thrs = FOCUS_THRS;
101 if(diff > thrs)
102 {
103 int fx = i / (float)wd * fcols;
104 int fy = j / (float)ht * frows;
105 int fi = fcols * fy + fx;
106#ifdef _OPENMP
107#pragma omp atomic
108#endif
109 f[fi].x += i;
110#ifdef _OPENMP
111#pragma omp atomic
112#endif
113 f[fi].y += j;
114#ifdef _OPENMP
115#pragma omp atomic
116#endif
117 f[fi].x2 += (float)i * i;
118#ifdef _OPENMP
119#pragma omp atomic
120#endif
121 f[fi].y2 += (float)j * j;
122#ifdef _OPENMP
123#pragma omp atomic
124#endif
125 f[fi].n++;
126#ifdef _OPENMP
127#pragma omp atomic
128#endif
129 f[fi].thrs += diff;
130 }
131}
132
133
134// read 8-bit buffer and create focus clusters from it
135static void dt_focus_create_clusters(dt_focus_cluster_t *focus, int frows, int fcols, uint8_t *buffer,
136 int buffer_width, int buffer_height)
137{
138 // mark in-focus pixels:
139 const int wd = buffer_width;
140 const int ht = buffer_height;
141 const int fs = frows * fcols;
142 // two-stage cdf 2/2 wavelet transform, use HH1 and HH2 to detect very sharp and sharp spots:
143 // pretend we already did the first step (coarse will stay in place, maybe even where the pre-demosaic
144 // sample was at)
145 _dt_focus_cdf22_wtf(buffer, 2, wd, ht);
146 // go through HH1 and detect sharp clusters:
147 memset(focus, 0, sizeof(dt_focus_cluster_t) * fcols * frows);
148#ifdef _OPENMP
149#pragma omp parallel for schedule(static) default(shared)
150#endif
151 for(int j = 0; j < ht - 1; j += 4)
152 for(int i = 0; i < wd - 1; i += 4)
153 {
154 _dt_focus_update(focus, frows, fcols, i, j, wd, ht,
155 abs(_from_uint8(buffer[4 * ((j + 2) * wd + i) + CHANNEL])));
156 _dt_focus_update(focus, frows, fcols, i, j, wd, ht,
157 abs(_from_uint8(buffer[4 * (j * wd + i + 2) + CHANNEL])));
158 }
159
160#if 1 // second pass, HH2
161 int num_clusters = 0;
162 for(int k = 0; k < fs; k++)
163 if(focus[k].n * 4 > wd * ht / (float)fs * 0.01f) num_clusters++;
164 if(num_clusters < 1)
165 {
166 memset(focus, 0, sizeof(dt_focus_cluster_t) * fs);
167 _dt_focus_cdf22_wtf(buffer, 3, wd, ht);
168#ifdef _OPENMP
169#pragma omp parallel for schedule(static) default(shared)
170#endif
171 for(int j = 0; j < ht - 1; j += 8)
172 {
173 for(int i = 0; i < wd - 1; i += 8)
174 {
175 _dt_focus_update(focus, frows, fcols, i, j, wd, ht,
176 1.5 * abs(_from_uint8(buffer[4 * ((j + 4) * wd + i) + CHANNEL])));
177 _dt_focus_update(focus, frows, fcols, i, j, wd, ht,
178 1.5 * abs(_from_uint8(buffer[4 * (j * wd + i + 4) + CHANNEL])));
179 }
180 }
181 num_clusters = 0;
182 for(int k = 0; k < fs; k++)
183 {
184 if(focus[k].n * 6.0f > wd * ht / (float)fs * 0.01f)
185 {
186 focus[k].n *= -1;
187 num_clusters++;
188 }
189 }
190 }
191#endif
192#undef CHANNEL
193
194#if 0 // simple high pass filter, doesn't work on slightly unsharp/high iso images
195 memset(focus, 0, sizeof(dt_focus_cluster_t)*fs);
196#ifdef _OPENMP
197#pragma omp parallel for schedule(static) default(shared)
198#endif
199 for(int j=1;j<ht-1;j++)
200 {
201 int index = 4*j*wd+4;
202 for(int i=1;i<wd-1;i++)
203 {
204 int32_t diff = 4*buffer[index+1]
205 - buffer[index-4+1]
206 - buffer[index+4+1]
207 - buffer[index-4*wd+1]
208 - buffer[index+4*wd+1];
209 _dt_focus_update(focus, frows, fcols, i, j, wd, ht, abs(diff));
210 index += 4;
211 }
212 }
213#endif
214 // normalize data in clusters:
215 for(int k = 0; k < fs; k++)
216 {
217 focus[k].thrs /= fabsf((float)focus[k].n);
218 focus[k].x /= fabsf((float)focus[k].n);
219 focus[k].x2 /= fabsf((float)focus[k].n);
220 focus[k].y /= fabsf((float)focus[k].n);
221 focus[k].y2 /= fabsf((float)focus[k].n);
222 }
223}
224
225static void dt_focus_draw_clusters(cairo_t *cr, int width, int height, int32_t imgid, int buffer_width,
226 int buffer_height, dt_focus_cluster_t *focus, int frows, int fcols,
227 float full_zoom, float full_x, float full_y)
228{
229 const int fs = frows * fcols;
230 cairo_save(cr);
231 cairo_translate(cr, width / 2.0, height / 2.0f);
232
233 const dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r');
234 dt_image_t image = *img;
236
237 // FIXME: get those from rawprepare IOP somehow !!!
238 int wd = buffer_width + image.crop_x;
239 int ht = buffer_height + image.crop_y;
240
241 // array with cluster positions
242 float *pos = malloc(fs * 6 * sizeof(float));
243 float *offx = pos + fs * 2, *offy = pos + fs * 4;
244
245 for(int k = 0; k < fs; k++)
246 {
247 const float stddevx = sqrtf(focus[k].x2 - focus[k].x * focus[k].x);
248 const float stddevy = sqrtf(focus[k].y2 - focus[k].y * focus[k].y);
249
250 // FIXME: get those from rawprepare IOP somehow !!!
251 const float x = focus[k].x + image.crop_x;
252 const float y = focus[k].y + image.crop_y;
253
254 pos[2 * k + 0] = x;
255 pos[2 * k + 1] = y;
256 offx[2 * k + 0] = x + stddevx;
257 offx[2 * k + 1] = y;
258 offy[2 * k + 0] = x;
259 offy[2 * k + 1] = y + stddevy;
260 }
261
262 // could use dt_image_altered() here, but it ignores flip module
263 {
264 dt_develop_t dev;
265 dt_dev_init(&dev, 0);
266 dt_dev_load_image(&dev, imgid);
268 const int res = dt_dev_pixelpipe_init_dummy(&pipe, wd, ht);
269 if(res)
270 {
271 // set mem pointer to 0, won't be used.
272 dt_dev_pixelpipe_set_input(&pipe, &dev, UNKNOWN_IMAGE, wd, ht, 1.0f, DT_MIPMAP_NONE);
274 dt_dev_pixelpipe_synch_all(&pipe, &dev);
275 dt_dev_pixelpipe_get_roi_out(&pipe, &dev, pipe.iwidth, pipe.iheight, &pipe.processed_width,
276 &pipe.processed_height);
277 dt_dev_distort_transform_plus(&dev, &pipe, 0.f, DT_DEV_TRANSFORM_DIR_ALL, pos, fs * 3);
279 wd = pipe.processed_width;
280 ht = pipe.processed_height;
281 }
282 dt_dev_cleanup(&dev);
283 }
284
285 const int32_t tb = darktable.develop->border_size;
286 const float scale = fminf((width - 2 * tb) / (float)wd, (height - 2 * tb) / (float)ht) * full_zoom;
287 cairo_scale(cr, scale, scale);
288 float fx = 0.0f;
289 float fy = 0.0f;
290 if(full_zoom > 1.0f)
291 {
292 // we want to be sure the image stay in the window
293 fx = fminf((wd * scale - width) / 2, fabsf(full_x));
294 if(full_x < 0) fx = -fx;
295 if(wd * scale <= width) fx = 0;
296 fy = fminf((ht * scale - height) / 2, fabsf(full_y));
297 if(full_y < 0) fy = -fy;
298 if(ht * scale <= height) fy = 0;
299 }
300
301 cairo_translate(cr, -wd / 2.0f + fx / scale * darktable.gui->ppd, -ht / 2.0f + fy / scale * darktable.gui->ppd);
302
303 cairo_rectangle(cr, 0, 0, wd, ht);
304 cairo_clip(cr);
305
306 double dashes[] = { DT_PIXEL_APPLY_DPI(5.), DT_PIXEL_APPLY_DPI(5.) };
307 const int ndash = sizeof(dashes) / sizeof(dashes[0]);
308 double offset = 0.0f;
309 cairo_set_dash(cr, dashes, ndash, offset);
310
311 // draw clustered focus regions
312 for(int k = 0; k < fs; k++)
313 {
314 const float intens = (focus[k].thrs - FOCUS_THRS) / FOCUS_THRS;
315 const float col = fminf(1.0f, intens);
316 int draw = 0;
317 if(focus[k].n * 4.0f > buffer_width * buffer_height / (float)fs * 0.01f)
318 draw = 1;
319 else if(-focus[k].n * 6.0f > buffer_width * buffer_height / (float)fs * 0.01f)
320 draw = 2;
321 if(draw)
322 {
323 for(int i = 0; i < 2; i++)
324 {
325 if(i)
326 {
327 if(draw == 2)
328 cairo_set_source_rgb(cr, .1f, .1f, col);
329 else
330 cairo_set_source_rgb(cr, col, .1f, .1f);
331 cairo_set_dash(cr, dashes, ndash, dashes[0]);
332 }
333 else
334 {
335 cairo_set_source_rgb(cr, .1f, .1f, .1f);
336 cairo_set_dash(cr, dashes, ndash, 0);
337 }
338 cairo_move_to(cr, offx[2 * k + 0], offx[2 * k + 1]);
339 cairo_curve_to(cr, -pos[2 * k + 0] + offx[2 * k + 0] + offy[2 * k + 0],
340 -pos[2 * k + 1] + offx[2 * k + 1] + offy[2 * k + 1],
341 -pos[2 * k + 0] + offx[2 * k + 0] + offy[2 * k + 0],
342 -pos[2 * k + 1] + offx[2 * k + 1] + offy[2 * k + 1], offy[2 * k + 0], offy[2 * k + 1]);
343 cairo_curve_to(cr, pos[2 * k + 0] - offx[2 * k + 0] + offy[2 * k + 0],
344 pos[2 * k + 1] - offx[2 * k + 1] + offy[2 * k + 1],
345 pos[2 * k + 0] - offx[2 * k + 0] + offy[2 * k + 0],
346 pos[2 * k + 1] - offx[2 * k + 1] + offy[2 * k + 1],
347 2 * pos[2 * k + 0] - offx[2 * k + 0], 2 * pos[2 * k + 1] - offx[2 * k + 1]);
348 cairo_curve_to(cr, 3 * pos[2 * k + 0] - offx[2 * k + 0] - offy[2 * k + 0],
349 3 * pos[2 * k + 1] - offx[2 * k + 1] - offy[2 * k + 1],
350 3 * pos[2 * k + 0] - offx[2 * k + 0] - offy[2 * k + 0],
351 3 * pos[2 * k + 1] - offx[2 * k + 1] - offy[2 * k + 1],
352 2 * pos[2 * k + 0] - offy[2 * k + 0], 2 * pos[2 * k + 1] - offy[2 * k + 1]);
353 cairo_curve_to(cr, pos[2 * k + 0] + offx[2 * k + 0] - offy[2 * k + 0],
354 pos[2 * k + 1] + offx[2 * k + 1] - offy[2 * k + 1],
355 pos[2 * k + 0] + offx[2 * k + 0] - offy[2 * k + 0],
356 pos[2 * k + 1] + offx[2 * k + 1] - offy[2 * k + 1], offx[2 * k + 0], offx[2 * k + 1]);
357
358 cairo_save(cr);
359 cairo_scale(cr, 1. / scale, 1. / scale);
360 cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2));
361 cairo_stroke(cr);
362 cairo_restore(cr);
363 }
364 }
365 }
366 cairo_restore(cr);
367 free(pos);
368}
369#undef CHANNEL
370#undef gbuf
371#undef FOCUS_THRS
372
373// clang-format off
374// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
375// vim: shiftwidth=2 expandtab tabstop=2 cindent
376// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
377// clang-format on
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
const double thrs
Definition chart/main.c:41
darktable_t darktable
Definition darktable.c:111
#define UNKNOWN_IMAGE
Definition darktable.h:139
void dt_dev_cleanup(dt_develop_t *dev)
Definition develop.c:150
void dt_dev_init(dt_develop_t *dev, int32_t gui_attached)
Definition develop.c:52
int dt_dev_distort_transform_plus(dt_develop_t *dev, dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction, float *points, size_t points_count)
Definition develop.c:1234
int dt_dev_load_image(dt_develop_t *dev, const int32_t imgid)
Definition develop.c:738
@ DT_DEV_TRANSFORM_DIR_ALL
Definition develop.h:72
static void dt_focus_draw_clusters(cairo_t *cr, int width, int height, int32_t imgid, int buffer_width, int buffer_height, dt_focus_cluster_t *focus, int frows, int fcols, float full_zoom, float full_x, float full_y)
Definition focus.h:225
static void dt_focus_create_clusters(dt_focus_cluster_t *focus, int frows, int fcols, uint8_t *buffer, int buffer_width, int buffer_height)
Definition focus.h:135
#define gbuf(BUF, A, B)
Definition focus.h:30
static void _dt_focus_cdf22_wtf(uint8_t *buf, const int l, const int width, const int height)
Definition focus.h:42
static void _dt_focus_update(dt_focus_cluster_t *f, int frows, int fcols, int i, int j, int wd, int ht, int diff)
Definition focus.h:97
#define CHANNEL
Definition focus.h:32
#define FOCUS_THRS
Definition focus.h:31
static int _from_uint8(uint8_t i)
Definition focus.h:38
static uint8_t _to_uint8(int i)
Definition focus.h:34
static float f(const float t, const float c, const float x)
Definition graduatednd.c:173
#define DT_PIXEL_APPLY_DPI(value)
Definition gtk.h:38
static gboolean draw(GtkWidget *widget, cairo_t *cr, dt_iop_module_t *self)
Definition hotpixels.c:358
void dt_image_cache_read_release(dt_image_cache_t *cache, const dt_image_t *img)
Definition image_cache.c:239
dt_image_t * dt_image_cache_get(dt_image_cache_t *cache, const int32_t imgid, char mode)
Definition image_cache.c:217
@ DT_MIPMAP_NONE
Definition mipmap_cache.h:42
void dt_dev_pixelpipe_get_roi_out(dt_dev_pixelpipe_t *pipe, struct dt_develop_t *dev, const int width_in, const int height_in, int *width, int *height)
Definition pixelpipe_hb.c:2114
void dt_dev_pixelpipe_create_nodes(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev)
Definition pixelpipe_hb.c:352
int dt_dev_pixelpipe_init_dummy(dt_dev_pixelpipe_t *pipe, int32_t width, int32_t height)
Definition pixelpipe_hb.c:152
void dt_dev_pixelpipe_set_input(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, int32_t imgid, int width, int height, float iscale, dt_mipmap_size_t size)
Definition pixelpipe_hb.c:230
void dt_dev_pixelpipe_cleanup(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:253
#define dt_dev_pixelpipe_synch_all(pipe, dev)
Definition pixelpipe_hb.h:289
struct dt_gui_gtk_t * gui
Definition darktable.h:541
struct dt_image_cache_t * image_cache
Definition darktable.h:543
struct dt_develop_t * develop
Definition darktable.h:536
Definition pixelpipe_hb.h:127
int iwidth
Definition pixelpipe_hb.h:133
int processed_width
Definition pixelpipe_hb.h:137
int processed_height
Definition pixelpipe_hb.h:137
int iheight
Definition pixelpipe_hb.h:133
Definition develop.h:143
int32_t border_size
Definition develop.h:200
Definition focus.h:24
float y
Definition focus.h:26
float x
Definition focus.h:26
float y2
Definition focus.h:26
float x2
Definition focus.h:26
int64_t n
Definition focus.h:25
float thrs
Definition focus.h:27
double ppd
Definition gtk.h:117
Definition common/image.h:195
int32_t crop_y
Definition common/image.h:224
int32_t crop_x
Definition common/image.h:224