void process(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, const void *const i, void *const o, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out) { // this is called for preview and full pipe separately, each with its own pixelpipe piece. // get our data struct: dt_iop_bilat_data_t *d = (dt_iop_bilat_data_t *)piece->data; // the total scale is composed of scale before input to the pipeline (iscale), // and the scale of the roi. const float scale = piece->iscale / roi_in->scale; const float sigma_r = d->sigma_r; // does not depend on scale const float sigma_s = d->sigma_s / scale; if(d->mode == s_mode_bilateral) { dt_bilateral_t *b = dt_bilateral_init(roi_in->width, roi_in->height, sigma_s, sigma_r); dt_bilateral_splat(b, (float *)i); dt_bilateral_blur(b); dt_bilateral_slice(b, (float *)i, (float *)o, d->detail); dt_bilateral_free(b); } else // s_mode_local_laplacian { local_laplacian(i, o, roi_in->width, roi_in->height, d->midtone, d->sigma_s, d->sigma_r, d->detail, 0); } if(piece->pipe->mask_display & DT_DEV_PIXELPIPE_DISPLAY_MASK) dt_iop_alpha_copy(i, o, roi_in->width, roi_in->height); }
void process (struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, void *ivoid, void *ovoid, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out) { dt_iop_lowpass_data_t *data = (dt_iop_lowpass_data_t *)piece->data; float *in = (float *)ivoid; float *out = (float *)ovoid; const int width = roi_in->width; const int height = roi_in->height; const int ch = piece->colors; const int use_bilateral = data->radius < 0 ? 1 : 0; const float radius = fmax(0.1f, fabs(data->radius)); const float sigma = radius * roi_in->scale / piece ->iscale; const int order = data->order; const float Labmax[] = { 100.0f, 128.0f, 128.0f, 1.0f }; const float Labmin[] = { 0.0f, -128.0f, -128.0f, 0.0f }; if(!use_bilateral) { dt_gaussian_t *g = dt_gaussian_init(width, height, ch, Labmax, Labmin, sigma, order); if(!g) return; dt_gaussian_blur_4c(g, in, out); dt_gaussian_free(g); } else { const float sigma_r = 100.0f;// d->sigma_r; // does not depend on scale const float sigma_s = sigma; const float detail = -1.0f; // we want the bilateral base layer dt_bilateral_t *b = dt_bilateral_init(width, height, sigma_s, sigma_r); if(!b) return; dt_bilateral_splat(b, in); dt_bilateral_blur(b); dt_bilateral_slice(b, in, out, detail); dt_bilateral_free(b); } // some aliased pointers for compilers that don't yet understand operators on __m128 const float *const Labminf = (float *)&Labmin; const float *const Labmaxf = (float *)&Labmax; #ifdef _OPENMP #pragma omp parallel for default(none) shared(in,out,data,roi_out) schedule(static) #endif for(int k=0; k<roi_out->width*roi_out->height; k++) { out[k*ch+0] = (out[k*ch+0] < 100.0f) ? data->table[CLAMP((int)(out[k*ch+0]/100.0f*0x10000ul), 0, 0xffff)] : dt_iop_eval_exp(data->unbounded_coeffs, out[k*ch+0]/100.0f); out[k*ch+1] = CLAMPF(out[k*ch+1]*data->saturation, Labminf[1], Labmaxf[1]); out[k*ch+2] = CLAMPF(out[k*ch+2]*data->saturation, Labminf[2], Labmaxf[2]); out[k*ch+3] = in[k*ch+3]; } }
void process(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, const void *const i, void *const o, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out) { dt_iop_monochrome_data_t *d = (dt_iop_monochrome_data_t *)piece->data; const float sigma2 = (d->size * 128.0) * (d->size * 128.0f); // first pass: evaluate color filter: #ifdef _OPENMP #pragma omp parallel for default(none) shared(d) schedule(static) #endif for(int k = 0; k < roi_out->height; k++) { const float *in = ((float *)i) + (size_t)4 * k * roi_out->width; float *out = ((float *)o) + (size_t)4 * k * roi_out->width; for(int j = 0; j < roi_out->width; j++, in += 4, out += 4) { out[0] = 100.0f * color_filter(in[1], in[2], d->a, d->b, sigma2); out[1] = out[2] = 0.0f; out[3] = in[3]; } } // second step: blur filter contribution: const float scale = piece->iscale / roi_in->scale; const float sigma_r = 250.0f; // does not depend on scale const float sigma_s = 20.0f / scale; const float detail = -1.0f; // bilateral base layer dt_bilateral_t *b = dt_bilateral_init(roi_in->width, roi_in->height, sigma_s, sigma_r); dt_bilateral_splat(b, (float *)o); dt_bilateral_blur(b); dt_bilateral_slice(b, (float *)o, (float *)o, detail); dt_bilateral_free(b); #ifdef _OPENMP #pragma omp parallel for default(none) shared(d) schedule(static) #endif for(int k = 0; k < roi_out->height; k++) { const float *in = ((float *)i) + (size_t)4 * k * roi_out->width; float *out = ((float *)o) + (size_t)4 * k * roi_out->width; for(int j = 0; j < roi_out->width; j++, in += 4, out += 4) { const float tt = envelope(in[0]); const float t = tt + (1.0f - tt) * (1.0f - d->highlights); out[0] = (1.0f - t) * in[0] + t * out[0] * (1.0f / 100.0f) * in[0]; // normalized filter * input brightness } } }
/** process, all real work is done here. */ void process(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, void *i, void *o, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out) { // this is called for preview and full pipe separately, each with its own pixelpipe piece. // get our data struct: dt_iop_bilat_data_t *d = (dt_iop_bilat_data_t *)piece->data; // the total scale is composed of scale before input to the pipeline (iscale), // and the scale of the roi. const float scale = piece->iscale/roi_in->scale; const float sigma_r = d->sigma_r; // does not depend on scale const float sigma_s = d->sigma_s / scale; // TODO: better memory management. dt_bilateral_t *b = dt_bilateral_init(roi_in->width, roi_in->height, sigma_s, sigma_r); dt_bilateral_splat(b, (float *)i); dt_bilateral_blur(b); dt_bilateral_slice(b, (float *)i, (float *)o, d->detail); dt_bilateral_free(b); }
void process_sse2(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, const void *const i, void *const o, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out) { // this is called for preview and full pipe separately, each with its own pixelpipe piece. // get our data struct: dt_iop_bilat_data_t *d = (dt_iop_bilat_data_t *)piece->data; dt_iop_bilat_gui_data_t *g = self->gui_data; // the total scale is composed of scale before input to the pipeline (iscale), // and the scale of the roi. const float scale = piece->iscale / roi_in->scale; const float sigma_r = d->sigma_r; // does not depend on scale const float sigma_s = d->sigma_s / scale; if(d->mode == s_mode_bilateral) { dt_bilateral_t *b = dt_bilateral_init(roi_in->width, roi_in->height, sigma_s, sigma_r); dt_bilateral_splat(b, (float *)i); dt_bilateral_blur(b); dt_bilateral_slice(b, (float *)i, (float *)o, d->detail); dt_bilateral_free(b); } else // s_mode_local_laplacian { local_laplacian_boundary_t b = {0}; if(self->dev->gui_attached && g && piece->pipe->type == DT_DEV_PIXELPIPE_PREVIEW) { b.mode = 1; } else if(self->dev->gui_attached && g && piece->pipe->type == DT_DEV_PIXELPIPE_FULL) { // full pipeline working on ROI needs boundary conditions from preview pipe // only do this if roi covers less than 90% of full width if(MIN(roi_in->width/roi_in->scale / piece->buf_in.width, roi_in->height/roi_in->scale / piece->buf_in.height) < 0.9) { dt_pthread_mutex_lock(&g->lock); const uint64_t hash = g->hash; dt_pthread_mutex_unlock(&g->lock); if(hash != 0 && !dt_dev_sync_pixelpipe_hash(self->dev, piece->pipe, 0, self->priority, &g->lock, &g->hash)) { // TODO: remove this debug output at some point: dt_control_log(_("local laplacian: inconsistent output")); } else { dt_pthread_mutex_lock(&g->lock); // grab preview pipe buffers here: b = g->ll_boundary; dt_pthread_mutex_unlock(&g->lock); if(b.wd > 0 && b.ht > 0) b.mode = 2; } } } b.roi = roi_in; b.buf = &piece->buf_in; // also lock the ll_boundary in case we're using it. // could get away without this if the preview pipe didn't also free the data below. const int lockit = self->dev->gui_attached && g && piece->pipe->type == DT_DEV_PIXELPIPE_FULL; if(lockit) { dt_pthread_mutex_lock(&g->lock); local_laplacian_sse2(i, o, roi_in->width, roi_in->height, d->midtone, d->sigma_s, d->sigma_r, d->detail, &b); dt_pthread_mutex_unlock(&g->lock); } else local_laplacian_sse2(i, o, roi_in->width, roi_in->height, d->midtone, d->sigma_s, d->sigma_r, d->detail, &b); // preview pixelpipe stores values. if(self->dev->gui_attached && g && piece->pipe->type == DT_DEV_PIXELPIPE_PREVIEW) { uint64_t hash = dt_dev_hash_plus(self->dev, piece->pipe, 0, self->priority); dt_pthread_mutex_lock(&g->lock); // store buffer pointers on gui struct. maybe need to swap/free old ones local_laplacian_boundary_free(&g->ll_boundary); g->ll_boundary = b; g->hash = hash; dt_pthread_mutex_unlock(&g->lock); } } if(piece->pipe->mask_display & DT_DEV_PIXELPIPE_DISPLAY_MASK) dt_iop_alpha_copy(i, o, roi_in->width, roi_in->height); }