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]; } }
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 *roi_in, const dt_iop_roi_t *roi_out) { dt_iop_colorize_data_t *data = (dt_iop_colorize_data_t *)piece->data; dt_iop_colorize_global_data_t *gd = (dt_iop_colorize_global_data_t *)self->data; cl_int err = -999; const int devid = piece->pipe->devid; const int width = roi_in->width; const int height = roi_in->height; /* create Lab */ float rgb[3]={0}, XYZ[3]={0}, Lab[3]={0}; hsl2rgb(rgb,data->hue, data->saturation, data->lightness/100.0); XYZ[0] = (rgb[0] * 0.5767309) + (rgb[1] * 0.1855540) + (rgb[2] * 0.1881852); XYZ[1] = (rgb[0] * 0.2973769) + (rgb[1] * 0.6273491) + (rgb[2] * 0.0752741); XYZ[2] = (rgb[0] * 0.0270343) + (rgb[1] * 0.0706872) + (rgb[2] * 0.9911085); dt_XYZ_to_Lab(XYZ,Lab); /* a/b components */ const float L = Lab[0]; const float a = Lab[1]; const float b = Lab[2]; const float mix = data->source_lightness_mix/100.0f; size_t sizes[] = { ROUNDUPWD(width), ROUNDUPHT(height), 1}; dt_opencl_set_kernel_arg(devid, gd->kernel_colorize, 0, sizeof(cl_mem), (void *)&dev_in); dt_opencl_set_kernel_arg(devid, gd->kernel_colorize, 1, sizeof(cl_mem), (void *)&dev_out); dt_opencl_set_kernel_arg(devid, gd->kernel_colorize, 2, sizeof(int), (void *)&width); dt_opencl_set_kernel_arg(devid, gd->kernel_colorize, 3, sizeof(int), (void *)&height); dt_opencl_set_kernel_arg(devid, gd->kernel_colorize, 4, sizeof(float), (void *)&mix); dt_opencl_set_kernel_arg(devid, gd->kernel_colorize, 5, sizeof(float), (void *)&L); dt_opencl_set_kernel_arg(devid, gd->kernel_colorize, 6, sizeof(float), (void *)&a); dt_opencl_set_kernel_arg(devid, gd->kernel_colorize, 7, sizeof(float), (void *)&b); err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_colorize, sizes); if(err != CL_SUCCESS) goto error; return TRUE; error: dt_print(DT_DEBUG_OPENCL, "[opencl_colorize] couldn't enqueue kernel! %d\n", err); return FALSE; }
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) { float *in, *out; dt_iop_colorize_data_t *d = (dt_iop_colorize_data_t *)piece->data; const int ch = piece->colors; /* create Lab */ float rgb[3]={0}, XYZ[3]={0}, Lab[3]={0}; hsl2rgb(rgb,d->hue, d->saturation, d->lightness/100.0); XYZ[0] = (rgb[0] * 0.5767309) + (rgb[1] * 0.1855540) + (rgb[2] * 0.1881852); XYZ[1] = (rgb[0] * 0.2973769) + (rgb[1] * 0.6273491) + (rgb[2] * 0.0752741); XYZ[2] = (rgb[0] * 0.0270343) + (rgb[1] * 0.0706872) + (rgb[2] * 0.9911085); dt_XYZ_to_Lab(XYZ,Lab); /* a/b components */ const float L = Lab[0]; const float a = Lab[1]; const float b = Lab[2]; const float mix = d->source_lightness_mix/100.0; #ifdef _OPENMP #pragma omp parallel for default(none) shared(ivoid,ovoid,roi_out) private(in,out) schedule(static) #endif for(int k=0; k<roi_out->height; k++) { float lmix=(mix*100.0)/2.0; int stride = ch*roi_out->width; in = (float *)ivoid+(k*stride); out = (float *)ovoid+(k*stride); for(int l=0; l < stride; l+=ch) { out[l+0] = L-lmix + in[l+0]*mix; out[l+1] = a; out[l+2] = b; out[l+3] = in[l+3]; } } }
// 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; } } }