Ejemplo n.º 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)
{
  dt_iop_lowlight_data_t *d = (dt_iop_lowlight_data_t *)(piece->data);
  const int ch = piece->colors;

  // empiric coefficient
  const float c = 0.5f;
  const float threshold = 0.01f;

  // scotopic white, blue saturated
  float Lab_sw[3] = { 100.0f, 0, -d->blueness };
  float XYZ_sw[3];

  dt_Lab_to_XYZ(Lab_sw, XYZ_sw);

#ifdef _OPENMP
#pragma omp parallel for default(none) schedule(static) shared(d, XYZ_sw)
#endif
  for(size_t k = 0; k < (size_t)roi_out->width * roi_out->height; k++)
  {
    float *in = (float *)i + ch * k;
    float *out = (float *)o + ch * k;
    float XYZ[3], XYZ_s[3];
    float V;
    float w;

    dt_Lab_to_XYZ(in, XYZ);

    // calculate scotopic luminance
    if(XYZ[0] > threshold)
    {
      // normal flow
      V = XYZ[1] * (1.33f * (1.0f + (XYZ[1] + XYZ[2]) / XYZ[0]) - 1.68f);
    }
    else
    {
      // low red flow, avoids "snow" on dark noisy areas
      V = XYZ[1] * (1.33f * (1.0f + (XYZ[1] + XYZ[2]) / threshold) - 1.68f);
    }

    // scale using empiric coefficient and fit inside limits
    V = fminf(1.0f, fmaxf(0.0f, c * V));

    // blending coefficient from curve
    w = lookup(d->lut, in[0] / 100.f);

    XYZ_s[0] = V * XYZ_sw[0];
    XYZ_s[1] = V * XYZ_sw[1];
    XYZ_s[2] = V * XYZ_sw[2];

    XYZ[0] = w * XYZ[0] + (1.0f - w) * XYZ_s[0];
    XYZ[1] = w * XYZ[1] + (1.0f - w) * XYZ_s[1];
    XYZ[2] = w * XYZ[2] + (1.0f - w) * XYZ_s[2];

    dt_XYZ_to_Lab(XYZ, out);

    out[3] = in[3];
  }
}
Ejemplo n.º 2
0
static inline void LCH_2_RGB(const float *LCH, float *RGB)
{
  float Lab[3], XYZ[3];
  LCH_2_Lab(LCH, Lab);
  dt_Lab_to_XYZ(Lab, XYZ);
  dt_XYZ_to_sRGB_clipped(XYZ, RGB);
}
Ejemplo n.º 3
0
int process_cl(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out,
               const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
{
  dt_iop_lowlight_data_t *d = (dt_iop_lowlight_data_t *)piece->data;
  dt_iop_lowlight_global_data_t *gd = (dt_iop_lowlight_global_data_t *)self->data;

  cl_mem dev_m = NULL;
  cl_int err = -999;
  const int devid = piece->pipe->devid;

  const int width = roi_out->width;
  const int height = roi_out->height;

  // scotopic white, blue saturated
  float Lab_sw[3] = { 100.0f, 0.0f, -d->blueness };
  float XYZ_sw[4];

  dt_Lab_to_XYZ(Lab_sw, XYZ_sw);

  dev_m = dt_opencl_copy_host_to_device(devid, d->lut, 256, 256, sizeof(float));
  if(dev_m == NULL) goto error;

  size_t sizes[2] = { ROUNDUPWD(width), ROUNDUPHT(height) };
  dt_opencl_set_kernel_arg(devid, gd->kernel_lowlight, 0, sizeof(cl_mem), &dev_in);
  dt_opencl_set_kernel_arg(devid, gd->kernel_lowlight, 1, sizeof(cl_mem), &dev_out);
  dt_opencl_set_kernel_arg(devid, gd->kernel_lowlight, 2, sizeof(int), &width);
  dt_opencl_set_kernel_arg(devid, gd->kernel_lowlight, 3, sizeof(int), &height);
  dt_opencl_set_kernel_arg(devid, gd->kernel_lowlight, 4, 4 * sizeof(float), &XYZ_sw);
  dt_opencl_set_kernel_arg(devid, gd->kernel_lowlight, 5, sizeof(cl_mem), &dev_m);
  err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_lowlight, sizes);
  if(err != CL_SUCCESS) goto error;

  dt_opencl_release_mem_object(dev_m);
  return TRUE;

error:
  dt_opencl_release_mem_object(dev_m);
  dt_print(DT_DEBUG_OPENCL, "[opencl_lowlight] couldn't enqueue kernel! %d\n", err);
  return FALSE;
}
Ejemplo n.º 4
0
void set_color(box_t *box, dt_colorspaces_color_profile_type_t color_space, float c0, float c1, float c2)
{
  box->color_space = color_space;
  box->color[0] = c0;
  box->color[1] = c1;
  box->color[2] = c2;

  float Lab[3] = { c0, c1, c2 };
  float XYZ[3] = { c0 * 0.01, c1 * 0.01, c2 * 0.01 };

  switch(color_space)
  {
    default:
    case DT_COLORSPACE_NONE:
      for(int c = 0; c < 3; c++) box->rgb[c] = 0.0;
      break;
    case DT_COLORSPACE_LAB:
      dt_Lab_to_XYZ(Lab, XYZ);
    case DT_COLORSPACE_XYZ:
      dt_XYZ_to_sRGB(XYZ, box->rgb);
      break;
  }
}
Ejemplo n.º 5
0
static inline void Lab_2_RGB(const float *Lab, float *RGB)
{
  float XYZ[3];
  dt_Lab_to_XYZ(Lab, XYZ);
  dt_XYZ_to_sRGB_clipped(XYZ, RGB);
}
Ejemplo n.º 6
0
// see http://www.brucelindbloom.com/Eqn_RGB_XYZ_Matrix.html for the transformation matrices
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)
{
  dt_iop_colorbalance_data_t *d = (dt_iop_colorbalance_data_t *)piece->data;
  const int ch = piece->colors;

  // these are RGB values!
  const float lift[3] = { 2.0 - (d->lift[CHANNEL_RED] * d->lift[CHANNEL_FACTOR]),
                          2.0 - (d->lift[CHANNEL_GREEN] * d->lift[CHANNEL_FACTOR]),
                          2.0 - (d->lift[CHANNEL_BLUE] * d->lift[CHANNEL_FACTOR]) },
              gamma[3] = { d->gamma[CHANNEL_RED] * d->gamma[CHANNEL_FACTOR],
                           d->gamma[CHANNEL_GREEN] * d->gamma[CHANNEL_FACTOR],
                           d->gamma[CHANNEL_BLUE] * d->gamma[CHANNEL_FACTOR] },
              gamma_inv[3] = { (gamma[0] != 0.0) ? 1.0 / gamma[0] : 1000000.0,
                               (gamma[1] != 0.0) ? 1.0 / gamma[1] : 1000000.0,
                               (gamma[2] != 0.0) ? 1.0 / gamma[2] : 1000000.0 },
              gain[3] = { d->gain[CHANNEL_RED] * d->gain[CHANNEL_FACTOR],
                          d->gain[CHANNEL_GREEN] * d->gain[CHANNEL_FACTOR],
                          d->gain[CHANNEL_BLUE] * d->gain[CHANNEL_FACTOR] };

  // sRGB -> XYZ matrix, D65
  const float srgb_to_xyz[3][3] = {
    { 0.4360747, 0.3850649, 0.1430804 },
    { 0.2225045, 0.7168786, 0.0606169 },
    { 0.0139322, 0.0971045, 0.7141733 }
    //     {0.4124564, 0.3575761, 0.1804375},
    //     {0.2126729, 0.7151522, 0.0721750},
    //     {0.0193339, 0.1191920, 0.9503041}
  };
  // XYZ -> sRGB matrix, D65
  const float xyz_to_srgb[3][3] = {
    { 3.1338561, -1.6168667, -0.4906146 },
    { -0.9787684, 1.9161415, 0.0334540 },
    { 0.0719453, -0.2289914, 1.4052427 }
    //     {3.2404542, -1.5371385, -0.4985314},
    //     {-0.9692660,  1.8760108,  0.0415560},
    //     {0.0556434, -0.2040259,  1.0572252}
  };

#ifdef _OPENMP
#pragma omp parallel for default(none) schedule(static) shared(i, o, roi_in, roi_out)
#endif
  for(int j = 0; j < roi_out->height; j++)
  {
    float *in = ((float *)i) + (size_t)ch * roi_in->width * j;
    float *out = ((float *)o) + (size_t)ch * roi_out->width * j;
    for(int i = 0; i < roi_out->width; i++)
    {
      // transform the pixel to sRGB:
      // Lab -> XYZ
      float XYZ[3];
      dt_Lab_to_XYZ(in, XYZ);
      // XYZ -> sRGB
      float rgb[3] = { 0, 0, 0 };
      for(int r = 0; r < 3; r++)
        for(int c = 0; c < 3; c++) rgb[r] += xyz_to_srgb[r][c] * XYZ[c];
      // linear sRGB -> gamma corrected sRGB
      for(int c = 0; c < 3; c++)
        rgb[c] = rgb[c] <= 0.0031308 ? 12.92 * rgb[c] : (1.0 + 0.055) * powf(rgb[c], 1.0 / 2.4) - 0.055;

      // do the calculation in RGB space
      for(int c = 0; c < 3; c++)
      {
        float tmp = (((rgb[c] - 1.0f) * lift[c]) + 1.0f) * gain[c];
        if(tmp < 0.0f) tmp = 0.0f;
        rgb[c] = powf(tmp, gamma_inv[c]);
      }

      // transform the result back to Lab
      // sRGB -> XYZ
      XYZ[0] = XYZ[1] = XYZ[2] = 0.0;
      // gamma corrected sRGB -> linear sRGB
      for(int c = 0; c < 3; c++)
        rgb[c] = rgb[c] <= 0.04045 ? rgb[c] / 12.92 : powf((rgb[c] + 0.055) / (1 + 0.055), 2.4);
      for(int r = 0; r < 3; r++)
        for(int c = 0; c < 3; c++) XYZ[r] += srgb_to_xyz[r][c] * rgb[c];
      // XYZ -> Lab
      dt_XYZ_to_Lab(XYZ, out);
      out[3] = in[3];

      in += ch;
      out += ch;
    }
  }
}