1 // NOTE: Throughout, we use the symbol ⊙ for convolution.
2 // Since all of our signals are symmetrical, discrete correlation and convolution
3 // is the same operation, and so we won't make a difference in notation.
6 #include <Eigen/Cholesky>
15 #include "deconvolution_sharpen_effect.h"
16 #include "effect_util.h"
19 using namespace Eigen;
24 DeconvolutionSharpenEffect::DeconvolutionSharpenEffect()
27 gaussian_radius(0.0f),
31 last_circle_radius(-1.0f),
32 last_gaussian_radius(-1.0f),
33 last_correlation(-1.0f),
37 register_int("matrix_size", &R);
38 register_float("circle_radius", &circle_radius);
39 register_float("gaussian_radius", &gaussian_radius);
40 register_float("correlation", &correlation);
41 register_float("noise", &noise);
44 DeconvolutionSharpenEffect::~DeconvolutionSharpenEffect()
46 delete[] uniform_samples;
49 string DeconvolutionSharpenEffect::output_fragment_shader()
52 sprintf(buf, "#define R %u\n", R);
55 assert(R <= 25); // Same limit as Refocus.
57 uniform_samples = new float[4 * (R + 1) * (R + 1)];
58 register_uniform_vec4_array("samples", uniform_samples, (R + 1) * (R + 1));
61 return buf + read_file("deconvolution_sharpen_effect.frag");
66 // Integral of sqrt(r² - x²) dx over x=0..a.
67 float circle_integral(float a, float r)
74 return 0.25f * M_PI * r * r;
76 return 0.5f * (a * sqrt(r*r - a*a) + r*r * asin(a / r));
79 // Yields the impulse response of a circular blur with radius r.
80 // We basically look at each element as a square centered around (x,y),
81 // and figure out how much of its area is covered by the circle.
82 float circle_impulse_response(int x, int y, float r)
85 // Degenerate case: radius = 0 yields the impulse response.
86 return (x == 0 && y == 0) ? 1.0f : 0.0f;
89 // Find the extents of this cell. Due to symmetry, we can cheat a bit
90 // and pretend we're always in the upper-right quadrant, except when
91 // we're right at an axis crossing (x = 0 or y = 0), in which case we
92 // simply use the evenness of the function; shrink the cell, make
93 // the calculation, and down below we'll normalize by the cell's area.
94 float min_x, max_x, min_y, max_y;
99 min_x = abs(x) - 0.5f;
100 max_x = abs(x) + 0.5f;
106 min_y = abs(y) - 0.5f;
107 max_y = abs(y) + 0.5f;
109 assert(min_x >= 0.0f && max_x >= 0.0f);
110 assert(min_y >= 0.0f && max_y >= 0.0f);
112 float cell_height = max_y - min_y;
113 float cell_width = max_x - min_x;
115 if (min_x * min_x + min_y * min_y > r * r) {
116 // Lower-left corner is outside the circle, so the entire cell is.
119 if (max_x * max_x + max_y * max_y < r * r) {
120 // Upper-right corner is inside the circle, so the entire cell is.
124 // OK, so now we know the cell is partially covered by the circle:
134 // The edge of the circle is defined by x² + y² = r²,
135 // or x = sqrt(r² - y²) (since x is nonnegative).
136 // Find out where the curve crosses our given y values.
137 float mid_x1 = (max_y >= r) ? min_x : sqrt(r * r - max_y * max_y);
138 float mid_x2 = sqrt(r * r - min_y * min_y);
139 if (mid_x1 < min_x) {
142 if (mid_x2 > max_x) {
145 assert(mid_x1 >= min_x);
146 assert(mid_x2 >= mid_x1);
147 assert(max_x >= mid_x2);
149 // The area marked A in the figure above.
150 float covered_area = cell_height * (mid_x1 - min_x);
152 // The area marked B in the figure above. Note that the integral gives the entire
153 // shaded space down to zero, so we need to subtract the rectangle that does not
154 // belong to our cell.
155 covered_area += circle_integral(mid_x2, r) - circle_integral(mid_x1, r);
156 covered_area -= min_y * (mid_x2 - mid_x1);
158 assert(covered_area <= cell_width * cell_height);
159 return covered_area / (cell_width * cell_height);
162 // Compute a ⊙ b. Note that we compute the “full” convolution,
163 // ie., our matrix will be big enough to hold every nonzero element of the result.
164 MatrixXf convolve(const MatrixXf &a, const MatrixXf &b)
166 MatrixXf result(a.rows() + b.rows() - 1, a.cols() + b.cols() - 1);
167 for (int yr = 0; yr < result.rows(); ++yr) {
168 for (int xr = 0; xr < result.cols(); ++xr) {
171 // Given that x_b = x_r - x_a, find the values of x_a where
172 // x_a is in [0, a_cols> and x_b is in [0, b_cols>. (y is similar.)
174 // The second demand gives:
176 // 0 <= x_r - x_a < b_cols
177 // 0 >= x_a - x_r > -b_cols
178 // x_r >= x_a > x_r - b_cols
179 int ya_min = yr - b.rows() + 1;
181 int xa_min = xr - b.rows() + 1;
184 // Now fit to the first demand.
185 ya_min = max<int>(ya_min, 0);
186 ya_max = min<int>(ya_max, a.rows() - 1);
187 xa_min = max<int>(xa_min, 0);
188 xa_max = min<int>(xa_max, a.cols() - 1);
190 assert(ya_max >= ya_min);
191 assert(xa_max >= xa_min);
193 for (int ya = ya_min; ya <= ya_max; ++ya) {
194 for (int xa = xa_min; xa <= xa_max; ++xa) {
195 sum += a(ya, xa) * b(yr - ya, xr - xa);
199 result(yr, xr) = sum;
205 // Similar to convolve(), but instead of assuming every element outside
206 // of b is zero, we make no such assumption and instead return only the
207 // elements where we know the right answer. (This is the only difference
209 // This is the same as conv2(a, b, 'valid') in Octave.
211 // a must be the larger matrix of the two.
212 MatrixXf central_convolve(const MatrixXf &a, const MatrixXf &b)
214 assert(a.rows() >= b.rows());
215 assert(a.cols() >= b.cols());
216 MatrixXf result(a.rows() - b.rows() + 1, a.cols() - b.cols() + 1);
217 for (int yr = b.rows() - 1; yr < result.rows() + b.rows() - 1; ++yr) {
218 for (int xr = b.cols() - 1; xr < result.cols() + b.cols() - 1; ++xr) {
221 // Given that x_b = x_r - x_a, find the values of x_a where
222 // x_a is in [0, a_cols> and x_b is in [0, b_cols>. (y is similar.)
224 // The second demand gives:
226 // 0 <= x_r - x_a < b_cols
227 // 0 >= x_a - x_r > -b_cols
228 // x_r >= x_a > x_r - b_cols
229 int ya_min = yr - b.rows() + 1;
231 int xa_min = xr - b.rows() + 1;
234 // Now fit to the first demand.
235 ya_min = max<int>(ya_min, 0);
236 ya_max = min<int>(ya_max, a.rows() - 1);
237 xa_min = max<int>(xa_min, 0);
238 xa_max = min<int>(xa_max, a.cols() - 1);
240 assert(ya_max >= ya_min);
241 assert(xa_max >= xa_min);
243 for (int ya = ya_min; ya <= ya_max; ++ya) {
244 for (int xa = xa_min; xa <= xa_max; ++xa) {
245 sum += a(ya, xa) * b(yr - ya, xr - xa);
249 result(yr - b.rows() + 1, xr - b.cols() + 1) = sum;
257 void DeconvolutionSharpenEffect::update_deconvolution_kernel()
259 // Figure out the impulse response for the circular part of the blur.
260 MatrixXf circ_h(2 * R + 1, 2 * R + 1);
261 for (int y = -R; y <= R; ++y) {
262 for (int x = -R; x <= R; ++x) {
263 circ_h(y + R, x + R) = circle_impulse_response(x, y, circle_radius);
267 // Same, for the Gaussian part of the blur. We make this a lot larger
268 // since we're going to convolve with it soon, and it has infinite support
269 // (see comments for central_convolve()).
270 MatrixXf gaussian_h(4 * R + 1, 4 * R + 1);
271 for (int y = -2 * R; y <= 2 * R; ++y) {
272 for (int x = -2 * R; x <= 2 * R; ++x) {
274 if (gaussian_radius < 1e-3) {
275 val = (x == 0 && y == 0) ? 1.0f : 0.0f;
277 val = exp(-(x*x + y*y) / (2.0 * gaussian_radius * gaussian_radius));
279 gaussian_h(y + 2 * R, x + 2 * R) = val;
283 // h, the (assumed) impulse response that we're trying to invert.
284 MatrixXf h = central_convolve(gaussian_h, circ_h);
285 assert(h.rows() == 2 * R + 1);
286 assert(h.cols() == 2 * R + 1);
288 // Normalize the impulse response.
290 for (int y = 0; y < 2 * R + 1; ++y) {
291 for (int x = 0; x < 2 * R + 1; ++x) {
295 for (int y = 0; y < 2 * R + 1; ++y) {
296 for (int x = 0; x < 2 * R + 1; ++x) {
301 // r_uu, the (estimated/assumed) autocorrelation of the input signal (u).
302 // The signal is modelled a standard autoregressive process with the
303 // given correlation coefficient.
305 // We have to take a bit of care with the size of this matrix.
306 // The pow() function naturally has an infinite support (except for the
307 // degenerate case of correlation=0), but we have to chop it off
308 // somewhere. Since we convolve it with a 4*R+1 large matrix below,
309 // we need to make it twice as big as that, so that we have enough
310 // data to make r_vv valid. (central_convolve() effectively enforces
311 // that we get at least the right size.)
312 MatrixXf r_uu(8 * R + 1, 8 * R + 1);
313 for (int y = -4 * R; y <= 4 * R; ++y) {
314 for (int x = -4 * R; x <= 4 * R; ++x) {
315 r_uu(x + 4 * R, y + 4 * R) = pow(double(correlation), hypot(x, y));
319 // Estimate r_vv, the autocorrelation of the output signal v.
320 // Since we know that v = h ⊙ u and both are symmetrical,
321 // convolution and correlation are the same, and
322 // r_vv = v ⊙ v = (h ⊙ u) ⊙ (h ⊙ u) = (h ⊙ h) ⊙ r_uu.
323 MatrixXf r_vv = central_convolve(r_uu, convolve(h, h));
324 assert(r_vv.rows() == 4 * R + 1);
325 assert(r_vv.cols() == 4 * R + 1);
327 // Similarly, r_uv = u ⊙ v = u ⊙ (h ⊙ u) = h ⊙ r_uu.
328 MatrixXf r_uu_center = r_uu.block(2 * R, 2 * R, 4 * R + 1, 4 * R + 1);
329 MatrixXf r_uv = central_convolve(r_uu_center, h);
330 assert(r_uv.rows() == 2 * R + 1);
331 assert(r_uv.cols() == 2 * R + 1);
333 // Add the noise term (we assume the noise is uncorrelated,
334 // so it only affects the central element).
335 r_vv(2 * R, 2 * R) += noise;
337 // Now solve the Wiener-Hopf equations to find the deconvolution kernel g.
338 // Most texts show this only for the simpler 1D case:
340 // [ r_vv(0) r_vv(1) r_vv(2) ... ] [ g(0) ] [ r_uv(0) ]
341 // [ r_vv(-1) r_vv(0) ... ] [ g(1) ] = [ r_uv(1) ]
342 // [ r_vv(-2) ... ] [ g(2) ] [ r_uv(2) ]
343 // [ ... ] [ g(3) ] [ r_uv(3) ]
345 // (Since r_vv is symmetrical, we can drop the minus signs.)
347 // Generally, row i of the matrix contains (dropping _vv for brevity):
349 // [ r(0-i) r(1-i) r(2-i) ... ]
351 // However, we have the 2D case. We flatten the vectors out to
352 // 1D quantities; this means we must think of the row number
353 // as a pair instead of as a scalar. Row (i,j) then contains:
355 // [ r(0-i,0-j) r(1-i,0-j) r(2-i,0-j) ... r(0-i,1-j) r_(1-i,1-j) r(2-i,1-j) ... ]
357 // g and r_uv are flattened in the same fashion.
359 // Note that even though this matrix is block Toeplitz, it is _not_ Toeplitz,
360 // and thus can not be inverted through the standard Levinson-Durbin method.
361 // There exists a block Levinson-Durbin method, which we may or may not
362 // want to use later. (Eigen's solvers are fast enough that for big matrices,
363 // the convolution operation and not the matrix solving is the bottleneck.)
365 // One thing we definitely want to use, though, is the symmetry properties.
366 // Since we know that g(i, j) = g(|i|, |j|), we can reduce the amount of
367 // unknowns to about 1/4th of the total size. The method is quite simple,
368 // as can be seen from the following toy equation system:
370 // A x0 + B x1 + C x2 = y0
371 // D x0 + E x1 + F x2 = y1
372 // G x0 + H x1 + I x2 = y2
374 // If we now know that e.g. x0=x1 and y0=y1, we can rewrite this to
376 // (A+B+D+E) x0 + (C+F) x2 = 2 y0
377 // (G+H) x0 + I x2 = y2
379 // This both increases accuracy and provides us with a very nice speed
381 MatrixXf M(MatrixXf::Zero((R + 1) * (R + 1), (R + 1) * (R + 1)));
382 MatrixXf r_uv_flattened(MatrixXf::Zero((R + 1) * (R + 1), 1));
383 for (int outer_i = 0; outer_i < 2 * R + 1; ++outer_i) {
384 int folded_outer_i = abs(outer_i - R);
385 for (int outer_j = 0; outer_j < 2 * R + 1; ++outer_j) {
386 int folded_outer_j = abs(outer_j - R);
387 int row = folded_outer_i * (R + 1) + folded_outer_j;
388 for (int inner_i = 0; inner_i < 2 * R + 1; ++inner_i) {
389 int folded_inner_i = abs(inner_i - R);
390 for (int inner_j = 0; inner_j < 2 * R + 1; ++inner_j) {
391 int folded_inner_j = abs(inner_j - R);
392 int col = folded_inner_i * (R + 1) + folded_inner_j;
393 M(row, col) += r_vv((inner_i - R) - (outer_i - R) + 2 * R,
394 (inner_j - R) - (outer_j - R) + 2 * R);
397 r_uv_flattened(row) += r_uv(outer_i, outer_j);
401 LLT<MatrixXf> llt(M);
402 MatrixXf g_flattened = llt.solve(r_uv_flattened);
403 assert(g_flattened.rows() == (R + 1) * (R + 1)),
404 assert(g_flattened.cols() == 1);
406 // Normalize and de-flatten the deconvolution matrix.
407 g = MatrixXf(R + 1, R + 1);
409 for (int i = 0; i < g_flattened.rows(); ++i) {
412 if (y == 0 && x == 0) {
413 sum += g_flattened(i);
414 } else if (y == 0 || x == 0) {
415 sum += 2.0f * g_flattened(i);
417 sum += 4.0f * g_flattened(i);
420 for (int i = 0; i < g_flattened.rows(); ++i) {
423 g(y, x) = g_flattened(i) / sum;
426 last_circle_radius = circle_radius;
427 last_gaussian_radius = gaussian_radius;
428 last_correlation = correlation;
432 void DeconvolutionSharpenEffect::set_gl_state(GLuint glsl_program_num, const string &prefix, unsigned *sampler_num)
434 Effect::set_gl_state(glsl_program_num, prefix, sampler_num);
438 if (fabs(circle_radius - last_circle_radius) > 1e-3 ||
439 fabs(gaussian_radius - last_gaussian_radius) > 1e-3 ||
440 fabs(correlation - last_correlation) > 1e-3 ||
441 fabs(noise - last_noise) > 1e-3) {
442 update_deconvolution_kernel();
444 // Now encode it as uniforms, and pass it on to the shader.
445 for (int y = 0; y <= R; ++y) {
446 for (int x = 0; x <= R; ++x) {
447 int i = y * (R + 1) + x;
448 uniform_samples[i * 4 + 0] = x / float(width);
449 uniform_samples[i * 4 + 1] = y / float(height);
450 uniform_samples[i * 4 + 2] = g(y, x);
451 uniform_samples[i * 4 + 3] = 0.0f;