Beispiel #1
0
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);
}
Beispiel #2
0
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];
  }
}
Beispiel #3
0
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
    }
  }
}
Beispiel #4
0
/** 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);
}
Beispiel #5
0
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_global_tonemap_data_t *data = (dt_iop_global_tonemap_data_t *)piece->data;
  const float scale = piece->iscale/roi_in->scale;
  const float sigma_r = 8.0f; // does not depend on scale
  const float iw = piece->buf_in.width /scale;
  const float ih = piece->buf_in.height/scale;
  const float sigma_s = fminf(iw, ih)*0.03f;
  dt_bilateral_t *b = NULL;
  if(data->detail != 0.0f)
  {
    b = dt_bilateral_init(roi_in->width, roi_in->height, sigma_s, sigma_r);
    // get detail from unchanged input buffer
    dt_bilateral_splat(b, (float *)ivoid);
  }

  switch(data->operator)
  {
    case OPERATOR_REINHARD:
      process_reinhard(self, piece, ivoid, ovoid, roi_in, roi_out, data);
      break;
    case OPERATOR_DRAGO:
      process_drago(self, piece, ivoid, ovoid, roi_in, roi_out, data);
      break;
    case OPERATOR_FILMIC:
      process_filmic(self, piece, ivoid, ovoid, roi_in, roi_out, data);
      break;
  }

  if(data->detail != 0.0f)
  {
    dt_bilateral_blur(b);
    // and apply it to output buffer after logscale
    dt_bilateral_slice_to_output(b, (float *)ivoid, (float *)ovoid, data->detail);
    dt_bilateral_free(b);
  }

  if(piece->pipe->mask_display)
    dt_iop_alpha_copy(ivoid, ovoid, roi_out->width, roi_out->height);
}
Beispiel #6
0
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);
}