Skip to content

Commit 3e216a4

Browse files
jenshannoschwalmTurboGit
authored andcommitted
Revert "Haze removal improvements"
This reverts commit 7e1c106.
1 parent bc9bcca commit 3e216a4

File tree

1 file changed

+132
-113
lines changed

1 file changed

+132
-113
lines changed

src/iop/hazeremoval.c

Lines changed: 132 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ typedef struct dt_iop_hazeremoval_gui_data_t
7979
rgb_pixel A0;
8080
float distance_max;
8181
dt_hash_t hash;
82-
gboolean redo;
8382
} dt_iop_hazeremoval_gui_data_t;
8483

8584
typedef struct dt_iop_hazeremoval_global_data_t
@@ -211,6 +210,20 @@ void cleanup_global(dt_iop_module_so_t *self)
211210
self->data = NULL;
212211
}
213212

213+
214+
void gui_update(dt_iop_module_t *self)
215+
{
216+
dt_iop_hazeremoval_gui_data_t *g = self->gui_data;
217+
218+
dt_iop_gui_enter_critical_section(self);
219+
g->distance_max = NAN;
220+
g->A0[0] = NAN;
221+
g->A0[1] = NAN;
222+
g->A0[2] = NAN;
223+
g->hash = 0;
224+
dt_iop_gui_leave_critical_section(self);
225+
}
226+
214227
void gui_changed(dt_iop_module_t *self,
215228
GtkWidget *w,
216229
void *previous)
@@ -224,8 +237,12 @@ void gui_init(dt_iop_module_t *self)
224237
{
225238
dt_iop_hazeremoval_gui_data_t *g = IOP_GUI_ALLOC(hazeremoval);
226239

240+
g->distance_max = NAN;
241+
g->A0[0] = NAN;
242+
g->A0[1] = NAN;
243+
g->A0[2] = NAN;
227244
g->hash = DT_INVALID_CACHEHASH;
228-
g->redo = FALSE;
245+
229246
g->strength = dt_bauhaus_slider_from_params(self, N_("strength"));
230247
gtk_widget_set_tooltip_text(g->strength, _("amount of haze reduction"));
231248

@@ -399,7 +416,7 @@ void _quick_select(float *first,
399416
}
400417
}
401418

402-
// calculate diffusive ambient light and the maximal depth in the image.
419+
// calculate diffusive ambient light and the maximal depth in the image
403420
// depth is estimated by the local amount of haze and given in units of the
404421
// characteristic haze depth, i.e., the distance over which object light is
405422
// reduced by the factor exp(-1)
@@ -513,12 +530,6 @@ static float _ambient_light(const const_rgb_image img,
513530
: logf(FLT_MAX) / 2; // return the maximal depth
514531
}
515532

516-
static inline void _restart_pipe(dt_dev_pixelpipe_t *pipe, dt_iop_module_t *self)
517-
{
518-
dt_atomic_set_int(&pipe->shutdown, self->iop_order);
519-
pipe->changed |= DT_DEV_PIPE_SYNCH;
520-
}
521-
522533
void process(dt_iop_module_t *self,
523534
dt_dev_pixelpipe_iop_t *piece,
524535
const void *const ivoid,
@@ -532,7 +543,6 @@ void process(dt_iop_module_t *self,
532543
return;
533544
dt_iop_hazeremoval_gui_data_t *const g = self->gui_data;
534545
dt_iop_hazeremoval_params_t *d = piece->data;
535-
dt_dev_pixelpipe_t *pipe = piece->pipe;
536546

537547
const int width = roi_in->width;
538548
const int height = roi_in->height;
@@ -551,64 +561,61 @@ void process(dt_iop_module_t *self,
551561
float *const restrict out = (float*)ovoid;
552562
const const_rgb_image img_in = (const_rgb_image){ in, width, height, 4 };
553563

554-
const dt_hash_t phash = dt_dev_pixelpipe_piece_hash(piece, NULL, TRUE);
555-
const gboolean fullpipe = pipe->type == DT_DEV_PIXELPIPE_FULL;
556-
const gboolean gui = self->dev->gui_attached && g;
557-
558-
/* hazeremoval needs the color and the haziness (which yields distance_max)
559-
of the most hazy region of the image.
560-
In pixelpipe DT_DEV_PIXELPIPE_FULL we can not reliably get this value as
561-
the pixelpipe sees only part of the image (region of interest).
562-
563-
To get consistent output in darkroom canvas and the exported image we don't
564-
use A0 and distance_max (A&D) calculated from the preview pipe but want data
565-
from a HQ pixelpipe.
566-
567-
So we
568-
a) ensure correct data by a hash calculated from all upstream modules.
569-
b) If we run a full pipe without validated A&D we enforce an immediate
570-
HQ pipe re-run, calculate A&D and again do an immediate re-run of the pipe.
571-
c) If we have valid A&D we always use them, other do the fallback via
572-
_ambient_light().
573-
*/
574-
if(gui && fullpipe && phash != g->hash)
564+
// estimate diffusive ambient light and image depth
565+
rgb_pixel A0 = { NAN, NAN, NAN, 0.0f };
566+
float distance_max = NAN;
567+
568+
// hazeremoval module needs the color and the haziness (which yields
569+
// distance_max) of the most hazy region of the image. In pixelpipe
570+
// FULL we can not reliably get this value as the pixelpipe might
571+
// only see part of the image (region of interest). Therefore, we
572+
// try to get A0 and distance_max from the PREVIEW pixelpipe which
573+
// luckily stores it for us.
574+
if(self->dev->gui_attached && g && (piece->pipe->type & DT_DEV_PIXELPIPE_FULL))
575575
{
576-
if(!darktable.develop->late_scaling.enabled)
577-
{
578-
dt_print_pipe(DT_DEBUG_PIPE | DT_DEBUG_VERBOSE, "HQ request", pipe, piece->module, pipe->devid, NULL, NULL);
579-
darktable.develop->late_scaling.enabled = TRUE;
580-
g->redo = TRUE;
581-
_restart_pipe(pipe, self);
582-
return;
583-
}
584-
else
585-
{
586-
g->distance_max = _ambient_light(img_in, w1, &g->A0, compatibility_mode);
587-
g->hash = phash;
588-
if(g->redo)
589-
{
590-
dt_print_pipe(DT_DEBUG_PIPE | DT_DEBUG_VERBOSE, "HQ done", pipe, piece->module, pipe->devid, NULL, NULL);
591-
darktable.develop->late_scaling.enabled = FALSE;
592-
g->redo = FALSE;
593-
_restart_pipe(pipe, self);
594-
return;
595-
}
596-
}
576+
dt_iop_gui_enter_critical_section(self);
577+
const dt_hash_t hash = g->hash;
578+
dt_iop_gui_leave_critical_section(self);
579+
// Note that the case 'hash == 0' on first invocation in a session
580+
// implies that g->distance_max is NAN, which initiates special
581+
// handling below to avoid inconsistent results. In all other
582+
// cases we make sure that the preview pipe has left us with
583+
// proper readings for distance_max and A0. If data are not yet
584+
// there we need to wait (with timeout).
585+
if(hash != DT_INVALID_CACHEHASH
586+
&& !dt_dev_sync_pixelpipe_hash(self->dev, piece->pipe, self->iop_order,
587+
DT_DEV_TRANSFORM_DIR_BACK_INCL,
588+
&self->gui_lock, &g->hash))
589+
dt_control_log(_("inconsistent output"));
590+
dt_iop_gui_enter_critical_section(self);
591+
A0[0] = g->A0[0];
592+
A0[1] = g->A0[1];
593+
A0[2] = g->A0[2];
594+
distance_max = g->distance_max;
595+
dt_iop_gui_leave_critical_section(self);
597596
}
598597

599-
// estimated diffusive ambient light and image depth
600-
rgb_pixel A0;
601-
float distance_max;
598+
// FIXME in pipe->type |= DT_DEV_PIXELPIPE_IMAGE mode we currently can't receive data from preview
599+
// so we at least leave a note to the user
600+
if(piece->pipe->type & DT_DEV_PIXELPIPE_IMAGE)
601+
dt_control_log(_("inconsistent output"));
602602

603-
const gboolean hashed = gui && phash == g->hash;
604-
if(hashed)
603+
// In all other cases we calculate distance_max and A0 here.
604+
if(dt_isnan(distance_max))
605+
distance_max = _ambient_light(img_in, w1, &A0, compatibility_mode);
606+
// PREVIEW pixelpipe stores values.
607+
if(self->dev->gui_attached && g && (piece->pipe->type & DT_DEV_PIXELPIPE_PREVIEW))
605608
{
606-
dt_print_pipe(DT_DEBUG_PIPE | DT_DEBUG_VERBOSE, "haze from HQ", pipe, piece->module, pipe->devid, NULL, NULL);
607-
for(int i = 0; i < 3; i++) A0[i] = g->A0[i];
608-
distance_max = g->distance_max;
609+
dt_hash_t hash = dt_dev_hash_plus(self->dev, piece->pipe,
610+
self->iop_order, DT_DEV_TRANSFORM_DIR_BACK_INCL);
611+
dt_iop_gui_enter_critical_section(self);
612+
g->A0[0] = A0[0];
613+
g->A0[1] = A0[1];
614+
g->A0[2] = A0[2];
615+
g->distance_max = distance_max;
616+
g->hash = hash;
617+
dt_iop_gui_leave_critical_section(self);
609618
}
610-
else // In all other cases we calculate distance_max and A0 here.
611-
distance_max = _ambient_light(img_in, w1, &A0, compatibility_mode);
612619

613620
// calculate the transition map
614621
gray_image trans_map = new_gray_image(width, height);
@@ -621,15 +628,15 @@ void process(dt_iop_module_t *self,
621628
guided_filter(img_in.data, trans_map.data, trans_map_filtered.data,
622629
width, height, 4, w2, eps, 1.f, -FLT_MAX, FLT_MAX);
623630

624-
// finally, calculate the haze-free image
631+
// finally, calculate the haze-free image, minimum allowed value for transition map
625632
const float t_min = CLAMP(expf(-distance * distance_max), 1.0f / 1024.0f, 1.0f);
626633

627634
const dt_aligned_pixel_t c_A0 = { A0[0], A0[1], A0[2], A0[3] };
628635
const gray_image c_trans_map_filtered = trans_map_filtered;
629636
DT_OMP_FOR()
630637
for(size_t i = 0; i < size; i++)
631638
{
632-
const float t = MAX(c_trans_map_filtered.data[i], t_min);
639+
float t = MAX(c_trans_map_filtered.data[i], t_min);
633640
dt_aligned_pixel_t res;
634641
for_each_channel(c, aligned(in))
635642
res[c] = (in[4*i + c] - c_A0[c]) / t + c_A0[c];
@@ -659,24 +666,19 @@ static float _ambient_light_cl(dt_iop_module_t *self,
659666
const int width = dt_opencl_get_image_width(img);
660667
const int height = dt_opencl_get_image_height(img);
661668
const int element_size = dt_opencl_get_image_element_size(img);
662-
663-
cl_int err = DT_OPENCL_SYSMEM_ALLOCATION;
664-
float max_depth = 0.0f;
665-
666669
float *in = dt_alloc_aligned((size_t)width * height * element_size);
667-
if(in == NULL) goto error;
668-
669-
err = dt_opencl_read_host_from_device(devid, in, img, width, height, element_size);
670+
cl_int err = dt_opencl_read_host_from_device(devid, in, img, width, height, element_size);
670671
if(err != CL_SUCCESS) goto error;
671-
672672
const const_rgb_image img_in = (const_rgb_image)
673673
{ in, width, height, element_size / sizeof(float) };
674674

675-
max_depth = _ambient_light(img_in, w1, pA0, compatibility_mode);
676-
677-
error:
675+
const float max_depth = _ambient_light(img_in, w1, pA0, compatibility_mode);
678676
dt_free_align(in);
679677
return max_depth;
678+
error:
679+
dt_print(DT_DEBUG_OPENCL, "[hazeremoval, ambient_light_cl] unknown error: %d", err);
680+
dt_free_align(in);
681+
return 0.f;
680682
}
681683

682684
static int _box_min_cl(dt_iop_module_t *self,
@@ -797,10 +799,9 @@ int process_cl(dt_iop_module_t *self,
797799
{
798800
dt_iop_hazeremoval_gui_data_t *const g = (dt_iop_hazeremoval_gui_data_t*)self->gui_data;
799801
dt_iop_hazeremoval_params_t *d = piece->data;
800-
dt_dev_pixelpipe_t *pipe = piece->pipe;
801802

802803
const int ch = piece->colors;
803-
const int devid = pipe->devid;
804+
const int devid = piece->pipe->devid;
804805
const int width = roi_in->width;
805806
const int height = roi_in->height;
806807
const int w1 = 6; // window size (positive integer) for determining
@@ -813,50 +814,68 @@ int process_cl(dt_iop_module_t *self,
813814
const float eps = sqrtf(0.025f); // regularization parameter for guided filter
814815
const gboolean compatibility_mode = d->compatibility_mode;
815816

816-
const dt_hash_t phash = dt_dev_pixelpipe_piece_hash(piece, NULL, TRUE);
817-
const gboolean fullpipe = pipe->type == DT_DEV_PIXELPIPE_FULL;
818-
const gboolean gui = self->dev->gui_attached && g;
819-
820-
// For "how this works" see cpu code
821-
if(gui && fullpipe && phash != g->hash)
817+
// estimate diffusive ambient light and image depth
818+
rgb_pixel A0 = { NAN, NAN, NAN, 0.0f };
819+
float distance_max = NAN;
820+
821+
// hazeremoval module needs the color and the haziness (which yields
822+
// distance_max) of the most hazy region of the image. In pixelpipe
823+
// FULL we can not reliably get this value as the pixelpipe might
824+
// only see part of the image (region of interest). Therefore, we
825+
// try to get A0 and distance_max from the PREVIEW pixelpipe which
826+
// luckily stores it for us.
827+
if(self->dev->gui_attached
828+
&& g
829+
&& (piece->pipe->type & DT_DEV_PIXELPIPE_FULL))
822830
{
823-
if(!darktable.develop->late_scaling.enabled)
831+
dt_iop_gui_enter_critical_section(self);
832+
const dt_hash_t hash = g->hash;
833+
dt_iop_gui_leave_critical_section(self);
834+
// Note that the case 'hash == 0' on first invocation in a session
835+
// implies that g->distance_max is NAN, which initiates special
836+
// handling below to avoid inconsistent results. In all other
837+
// cases we make sure that the preview pipe has left us with
838+
// proper readings for distance_max and A0. If data are not yet
839+
// there we need to wait (with timeout).
840+
if(hash != DT_INVALID_CACHEHASH
841+
&& !dt_dev_sync_pixelpipe_hash(self->dev, piece->pipe,
842+
self->iop_order, DT_DEV_TRANSFORM_DIR_BACK_INCL,
843+
&self->gui_lock, &g->hash))
824844
{
825-
dt_print_pipe(DT_DEBUG_PIPE | DT_DEBUG_VERBOSE, "HQ request", pipe, piece->module, devid, NULL, NULL);
826-
darktable.develop->late_scaling.enabled = TRUE;
827-
g->redo = TRUE;
828-
_restart_pipe(pipe, self);
829-
return CL_SUCCESS;
830-
}
831-
else
832-
{
833-
g->distance_max = _ambient_light_cl(self, devid, img_in, w1, &g->A0, compatibility_mode);
834-
g->hash = phash;
835-
if(g->redo)
836-
{
837-
dt_print_pipe(DT_DEBUG_PIPE | DT_DEBUG_VERBOSE, "HQ done", pipe, piece->module, devid, NULL, NULL);
838-
darktable.develop->late_scaling.enabled = FALSE;
839-
g->redo = FALSE;
840-
_restart_pipe(pipe, self);
841-
return CL_SUCCESS;
842-
}
845+
dt_control_log(_("inconsistent output"));
843846
}
847+
848+
dt_iop_gui_enter_critical_section(self);
849+
A0[0] = g->A0[0];
850+
A0[1] = g->A0[1];
851+
A0[2] = g->A0[2];
852+
distance_max = g->distance_max;
853+
dt_iop_gui_leave_critical_section(self);
844854
}
845855

846-
// estimated diffusive ambient light and image depth
847-
rgb_pixel A0;
848-
float distance_max;
856+
// FIXME in pipe->type |= DT_DEV_PIXELPIPE_IMAGE mode we currently can't receive data from preview
857+
// so we at least leave a note to the user
858+
if(piece->pipe->type & DT_DEV_PIXELPIPE_IMAGE)
859+
dt_control_log(_("inconsistent output"));
849860

850-
const gboolean hashed = gui && phash == g->hash;
851-
if(hashed)
861+
// In all other cases we calculate distance_max and A0 here.
862+
if(dt_isnan(distance_max))
863+
distance_max = _ambient_light_cl(self, devid, img_in, w1, &A0, compatibility_mode);
864+
// PREVIEW pixelpipe stores values.
865+
if(self->dev->gui_attached
866+
&& g
867+
&& (piece->pipe->type & DT_DEV_PIXELPIPE_PREVIEW))
852868
{
853-
dt_print_pipe(DT_DEBUG_PIPE | DT_DEBUG_VERBOSE, "haze from HQ", pipe, piece->module, pipe->devid, NULL, NULL);
854-
for(int i = 0; i < 3; i++) A0[i] = g->A0[i];
855-
distance_max = g->distance_max;
869+
dt_hash_t hash = dt_dev_hash_plus(self->dev, piece->pipe,
870+
self->iop_order, DT_DEV_TRANSFORM_DIR_BACK_INCL);
871+
dt_iop_gui_enter_critical_section(self);
872+
g->A0[0] = A0[0];
873+
g->A0[1] = A0[1];
874+
g->A0[2] = A0[2];
875+
g->distance_max = distance_max;
876+
g->hash = hash;
877+
dt_iop_gui_leave_critical_section(self);
856878
}
857-
else
858-
distance_max = _ambient_light_cl(self, devid, img_in, w1, &A0, compatibility_mode);
859-
860879
cl_mem trans_map = NULL;
861880
cl_mem trans_map_filtered = NULL;
862881
cl_int err = CL_MEM_OBJECT_ALLOCATION_FAILURE;

0 commit comments

Comments
 (0)