37 uint8_t *
const restrict image,
38 const int buf_width,
const int buf_height,
44 uint8_t *restrict focus_peaking = NULL;
52 const size_t npixels = (size_t)buf_height * buf_width;
55 for(
size_t index = 0; index < npixels; index++)
57 const size_t index_RGB = index * 4;
68 if(
fast_eigf_surface_blur(luma, buf_width, buf_height, 12, 0.00005f, 4,
DT_GF_BLENDING_LINEAR, 1, 0.0f, exp2f(-8.0f), 1.0f) != 0)
76 float x_integral = 0.f;
77 float y_integral = 0.f;
79 for(
size_t i = 0;
i < buf_height; ++
i)
80 for(
size_t j = 0; j < buf_width; ++j)
82 size_t index =
i * buf_width + j;
83 if(i < 8 || i >= buf_height - 8 || j < 8 || j > buf_width - 8)
86 luma_ds[index] = 0.0f;
91 static const float kernel[7][7]
92 = { { 0.00053449f, 0.00352729f, 0.00992912f, 0.01362207f, 0.00992912f, 0.00352729f, 0.00053449f },
93 { 0.00352729f, 0.01828379f, 0.03437727f, 0.03474665f, 0.03437727f, 0.01828379f, 0.00352729f },
94 { 0.00992912f, 0.03437727f, -0.00982925f, -0.09093110f, -0.00982925f, 0.03437727f, 0.00992912f },
95 { 0.01362207f, 0.03474665f, -0.09093110f, -0.26187433f, -0.09093110f, 0.03474665f, 0.01362207f },
96 { 0.00992912f, 0.03437727f, -0.00982925f, -0.09093110f, -0.00982925f, 0.03437727f, 0.00992912f },
97 { 0.00352729f, 0.01828379f, 0.03437727f, 0.03474665f, 0.03437727f, 0.01828379f, 0.00352729f },
98 { 0.00053449f, 0.00352729f, 0.00992912f, 0.01362207f, 0.00992912f, 0.00352729f, 0.00053449f } };
103 float laplacian_close = 0.f;
104 float laplacian_far = 0.f;
106 for(
int ii = 0; ii < 7; ii++)
107 for(
int jj = 0; jj < 7; jj++)
109 laplacian_close += luma[(
i - 3 + ii) * buf_width + (j - 3 + jj)] *
kernel[ii][jj];
110 laplacian_far += luma[(
i + (-3 + ii) * 2) * buf_width + (j + (-3 + jj) * 2)] *
kernel[ii][jj];
114 const float gradient_1_y = (luma[(
i - 2) * buf_width + (j)] - luma[(
i + 2) * buf_width + (j)]) / 4.f;
115 const float gradient_1_x = (luma[(
i) * buf_width + (j - 2)] - luma[(
i) * buf_width + (j + 2)]) / 4.f;
116 const float TV_1 = dt_fast_hypotf(gradient_1_x, gradient_1_y);
119 const float gradient_2_y = (luma[(
i - 2) * buf_width + (j - 2)] - luma[(
i + 2) * buf_width + (j + 2)]) / (2.f * sqrtf(2.f));
120 const float gradient_2_x = (luma[(
i - 2) * buf_width + (j + 2)] - luma[(
i + 2) * buf_width + (j - 2)]) / (2.f * sqrtf(2.f));
121 const float TV_2 = dt_fast_hypotf(gradient_2_x, gradient_2_y);
124 const float gradient_3_y = (luma[(
i - 1) * buf_width + (j)] - luma[(
i + 1) * buf_width + (j)]) / 2.f;
125 const float gradient_3_x = (luma[(
i) * buf_width + (j - 1)] - luma[(
i) * buf_width + (j + 1)]) / 2.f;
126 const float TV_3 = dt_fast_hypotf(gradient_3_x, gradient_3_y);
129 const float gradient_4_y = (luma[(
i - 1) * buf_width + (j - 1)] - luma[(
i + 1) * buf_width + (j + 1)]) / (sqrtf(2.f));
130 const float gradient_4_x = (luma[(
i - 1) * buf_width + (j + 1)] - luma[(
i + 1) * buf_width + (j - 1)]) / (sqrtf(2.f));
131 const float TV_4 = dt_fast_hypotf(gradient_4_x, gradient_4_y);
137 const float TV = 100.f * (TV_1 + TV_2 + TV_3 + TV_4) / 4.f;
138 luma_ds[index] = (laplacian_close > 1e-15f) ? fmaxf(fabsf(laplacian_close) - 0.5f * fabsf(laplacian_far), 0.f) / (TV + 1.f) : 0.f;
141 mass += luma_ds[index];
142 x_integral += ((float)j) * luma_ds[index];
143 y_integral += ((float)
i) * luma_ds[index];
148 if(
x) *
x = CLAMP(x_integral / mass, 0, buf_height);
149 if(y) *y = CLAMP(y_integral / mass, 0, buf_height);
160 sizeof(uint8_t) * buf_width * buf_height * 4,
170 for(
size_t i = 0;
i < buf_height; ++
i)
171 for(
size_t j = 0; j < buf_width; ++j)
173 size_t index =
i * buf_width + j;
174 if(i < 8 || i >= buf_height - 8 || j < 8 || j > buf_width - 8)
182 static const float kernel[3][3] = { { 1.f } };
184 for(
int ii = 0; ii < 3; ii++)
185 for(
int jj = 0; jj < 3; jj++)
186 luma[index] += luma_ds[(
i - 1 + ii) * buf_width + (j - 1 + jj)] *
kernel[ii][jj];
191 if(
dt_box_mean(luma, buf_height, buf_width, 1, 3, 1) != 0)
198 if(
fast_eigf_surface_blur(luma, buf_width, buf_height, 12, 0.000005f, 1,
DT_GF_BLENDING_LINEAR, 1, 0.0f, exp2f(-8.0f), 1.0f) != 0)
207 for(
size_t i = 8;
i < buf_height - 8; ++
i)
208 for(
size_t j = 8; j < buf_width - 8; ++j)
209 TV_sum += luma[
i * buf_width + j] / ((
float)(buf_height - 16) * (
float)(buf_width - 16));
214 for(
size_t i = 8;
i < buf_height - 8; ++
i)
215 for(
size_t j = 8; j < buf_width - 8; ++j)
216 sigma += sqf(luma[
i * buf_width + j] - TV_sum) / ((float)(buf_height - 16) * (float)(buf_width - 16));
221 const float six_sigma = TV_sum + 4.f *
sigma;
222 const float four_sigma = TV_sum + 3.f *
sigma;
223 const float two_sigma = TV_sum + 2.f *
sigma;
227 for(
size_t i = 0;
i < buf_height; ++
i)
228 for(
size_t j = 0; j < buf_width; ++j)
230 static const uint8_t yellow[4] = { 0, 255, 255, 255 };
231 static const uint8_t green[4] = { 0, 255, 0, 255 };
232 static const uint8_t blue[4] = { 255, 0, 0, 255 };
234 const size_t index = (
i * buf_width + j) * 4;
235 const float TV = luma[(
i * buf_width + j)];
242 else if(TV > four_sigma)
247 else if(TV > two_sigma)
261 cairo_rectangle(cr, 0, 0, buf_width, buf_height);
262 cairo_surface_t *surface = cairo_image_surface_create_for_data((
unsigned char *)focus_peaking,
264 buf_width, buf_height,
265 cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, buf_width));
266 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
267 cairo_set_source_surface(cr, surface, 0.0, 0.0);
273 cairo_surface_destroy(surface);