1
/* ============================================================
3
* This file is a part of digiKam project
4
* http://www.digikam.org
7
* Description : refocus deconvolution matrix implementation.
9
* Copyright (C) 2005-2010 by Gilles Caulier <caulier dot gilles at gmail dot com>
11
* Original implementation from Refocus Gimp plug-in
12
* Copyright (C) 1999-2003 Ernst Lippe
14
* This program is free software; you can redistribute it
15
* and/or modify it under the terms of the GNU General
16
* Public License as published by the Free Software Foundation;
17
* either version 2, or (at your option)
20
* This program is distributed in the hope that it will be useful,
21
* but WITHOUT ANY WARRANTY; without even the implied warranty of
22
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
* GNU General Public License for more details.
25
* ============================================================ */
27
// Uncomment this line to debug matrix computation.
31
#define SQR(x) ((x) * (x))
58
Mat *RefocusMatrix::allocate_matrix (int nrows, int ncols)
60
Mat *result = new Mat;
61
memset (result, 0, sizeof(result));
65
result->data = new double [nrows * ncols];
66
memset (result->data, 0, nrows * ncols * sizeof(double));
71
void RefocusMatrix::finish_matrix (Mat * mat)
76
void RefocusMatrix::finish_and_free_matrix (Mat * mat)
82
double *RefocusMatrix::mat_eltptr (Mat * mat, const int r, const int c)
84
Q_ASSERT ((r >= 0) && (r < mat->rows));
85
Q_ASSERT ((c >= 0) && (c < mat->rows));
86
return (&(mat->data[mat->rows * c + r]));
89
double RefocusMatrix::mat_elt (const Mat * mat, const int r, const int c)
91
Q_ASSERT ((r >= 0) && (r < mat->rows));
92
Q_ASSERT ((c >= 0) && (c < mat->rows));
93
return (mat->data[mat->rows * c + r]);
96
void RefocusMatrix::init_c_mat (CMat * mat, const int radius)
99
mat->row_stride = 2 * radius + 1;
100
mat->data = new double [SQR (mat->row_stride)];
101
memset (mat->data, 0, SQR (mat->row_stride) * sizeof(double));
102
mat->center = mat->data + mat->row_stride * mat->radius + mat->radius;
105
CMat *RefocusMatrix::allocate_c_mat (const int radius)
107
CMat *result = new CMat;
108
memset(result, 0, sizeof(result));
109
init_c_mat (result, radius);
113
void RefocusMatrix::finish_c_mat (CMat * mat)
119
inline double *RefocusMatrix::c_mat_eltptr (CMat * mat, const int col, const int row)
121
Q_ASSERT ((qAbs (row) <= mat->radius) && (qAbs (col) <= mat->radius));
122
return (mat->center + mat->row_stride * row + col);
125
inline double RefocusMatrix::c_mat_elt (const CMat * const mat, const int col, const int row)
127
Q_ASSERT ((qAbs (row) <= mat->radius) && (qAbs (col) <= mat->radius));
128
return (mat->center[mat->row_stride * row + col]);
131
void RefocusMatrix::convolve_mat (CMat * result, const CMat * const mata, const CMat * const matb)
133
register int xr, yr, xa, ya;
135
for (yr = -result->radius; yr <= result->radius; ++yr)
137
for (xr = -result->radius; xr <= result->radius; ++xr)
139
const int ya_low = qMax (-mata->radius, yr - matb->radius);
140
const int ya_high = qMin (mata->radius, yr + matb->radius);
141
const int xa_low = qMax (-mata->radius, xr - matb->radius);
142
const int xa_high = qMin (mata->radius, xr + matb->radius);
143
register double val = 0.0;
145
for (ya = ya_low; ya <= ya_high; ++ya)
147
for (xa = xa_low; xa <= xa_high; ++xa)
149
val += c_mat_elt (mata, xa, ya) *
150
c_mat_elt (matb, xr - xa, yr - ya);
154
*c_mat_eltptr (result, xr, yr) = val;
159
void RefocusMatrix::convolve_star_mat (CMat * result, const CMat * const mata, const CMat * const matb)
161
register int xr, yr, xa, ya;
163
for (yr = -result->radius; yr <= result->radius; ++yr)
165
for (xr = -result->radius; xr <= result->radius; ++xr)
167
const int ya_low = qMax (-mata->radius, -matb->radius - yr);
168
const int ya_high = qMin (mata->radius, matb->radius - yr);
169
const int xa_low = qMax (-mata->radius, -matb->radius - xr);
170
const int xa_high = qMin (mata->radius, matb->radius - xr);
171
register double val = 0.0;
173
for (ya = ya_low; ya <= ya_high; ++ya)
175
for (xa = xa_low; xa <= xa_high; ++xa)
177
val += c_mat_elt (mata, xa, ya) *
178
c_mat_elt (matb, xr + xa, yr + ya);
182
*c_mat_eltptr (result, xr, yr) = val;
187
void RefocusMatrix::convolve_mat_fun (CMat * result, const CMat * const mata, double (f) (int, int))
189
register int xr, yr, xa, ya;
191
for (yr = -result->radius; yr <= result->radius; ++yr)
193
for (xr = -result->radius; xr <= result->radius; ++xr)
195
register double val = 0.0;
197
for (ya = -mata->radius; ya <= mata->radius; ++ya)
199
for (xa = -mata->radius; xa <= mata->radius; ++xa)
201
val += c_mat_elt (mata, xa, ya) * f (xr - xa, yr - ya);
205
*c_mat_eltptr (result, xr, yr) = val;
210
int RefocusMatrix::as_idx (const int k, const int l, const int m)
212
return ((k + m) * (2 * m + 1) + (l + m));
215
int RefocusMatrix::as_cidx (const int k, const int l)
217
const int a = qMax (qAbs (k), qAbs (l));
218
const int b = qMin (qAbs (k), qAbs (l));
219
return ((a * (a + 1)) / 2 + b);
222
void RefocusMatrix::print_c_mat (const CMat * const mat)
226
for (y = -mat->radius; y <= mat->radius; ++y)
230
for (x = -mat->radius; x <= mat->radius; ++x)
232
output.append( num.setNum( c_mat_elt (mat, x, y) ) );
239
void RefocusMatrix::print_matrix (Mat * matrix)
241
int col_idx, row_idx;
243
for (row_idx = 0; row_idx < matrix->rows; ++row_idx)
247
for (col_idx = 0; col_idx < matrix->cols; ++col_idx)
249
output.append( num.setNum( mat_elt (matrix, row_idx, col_idx) ) );
256
Mat *RefocusMatrix::make_s_matrix (CMat * mat, int m, double noise_factor)
258
const int mat_size = SQR (2 * m + 1);
259
Mat *result = allocate_matrix (mat_size, mat_size);
260
register int yr, yc, xr, xc;
262
for (yr = -m; yr <= m; ++yr)
264
for (xr = -m; xr <= m; ++xr)
266
for (yc = -m; yc <= m; ++yc)
268
for (xc = -m; xc <= m; ++xc)
270
*mat_eltptr (result, as_idx (xr, yr, m),
271
as_idx (xc, yc, m)) =
272
c_mat_elt (mat, xr - xc, yr - yc);
273
if ((xr == xc) && (yr == yc))
275
*mat_eltptr (result, as_idx (xr, yr, m),
276
as_idx (xc, yc, m)) += noise_factor;
286
Mat *RefocusMatrix::make_s_cmatrix (CMat * mat, int m, double noise_factor)
288
const int mat_size = as_cidx (m + 1, 0);
289
Mat *result = allocate_matrix (mat_size, mat_size);
290
register int yr, yc, xr, xc;
292
for (yr = 0; yr <= m; ++yr)
294
for (xr = 0; xr <= yr; ++xr)
296
for (yc = -m; yc <= m; ++yc)
298
for (xc = -m; xc <= m; ++xc)
300
*mat_eltptr (result, as_cidx (xr, yr), as_cidx (xc, yc)) +=
301
c_mat_elt (mat, xr - xc, yr - yc);
302
if ((xr == xc) && (yr == yc))
304
*mat_eltptr (result, as_cidx (xr, yr),
305
as_cidx (xc, yc)) += noise_factor;
315
double RefocusMatrix::correlation (const int x, const int y, const double gamma, const double musq)
317
return (musq + pow ((double)gamma, (double)sqrt (SQR (x) + SQR (y))));
320
Mat *RefocusMatrix::copy_vec (const CMat * const mat, const int m)
322
Mat *result = allocate_matrix (SQR (2 * m + 1), 1);
323
register int x, y, index = 0;
325
for (y = -m; y <= m; ++y)
327
for (x = -m; x <= m; ++x)
329
*mat_eltptr (result, index, 0) = c_mat_elt (mat, x, y);
334
Q_ASSERT (index == SQR (2 * m + 1));
338
Mat *RefocusMatrix::copy_cvec (const CMat * const mat, const int m)
340
Mat *result = allocate_matrix (as_cidx (m + 1, 0), 1);
341
register int x, y, index = 0;
343
for (y = 0; y <= m; ++y)
345
for (x = 0; x <= y; ++x)
347
*mat_eltptr (result, index, 0) = c_mat_elt (mat, x, y);
352
Q_ASSERT (index == as_cidx (m + 1, 0));
356
CMat *RefocusMatrix::copy_cvec2mat (const Mat * const cvec, const int m)
358
CMat *result = allocate_c_mat (m);
361
for (y = -m; y <= m; ++y)
363
for (x = -m; x <= m; ++x)
365
*c_mat_eltptr (result, x, y) = mat_elt (cvec, as_cidx (x, y), 0);
372
CMat *RefocusMatrix::copy_vec2mat (const Mat * const cvec, const int m)
374
CMat *result = allocate_c_mat (m);
377
for (y = -m; y <= m; ++y)
379
for (x = -m; x <= m; ++x)
381
*c_mat_eltptr (result, x, y) = mat_elt (cvec, as_idx (x, y, m), 0);
388
CMat *RefocusMatrix::compute_g (const CMat * const convolution, const int m, const double gamma,
389
const double noise_factor, const double musq, const bool symmetric)
391
CMat h_conv_ruv, a, corr;
397
init_c_mat (&h_conv_ruv, 3 * m);
398
fill_matrix2 (&corr, 4 * m, correlation, gamma, musq);
399
convolve_mat (&h_conv_ruv, convolution, &corr);
400
init_c_mat (&a, 2 * m);
401
convolve_star_mat (&a, convolution, &h_conv_ruv);
405
s = make_s_cmatrix (&a, m, noise_factor);
406
b = copy_cvec (&h_conv_ruv, m);
410
s = make_s_matrix (&a, m, noise_factor);
411
b = copy_vec (&h_conv_ruv, m);
415
kDebug() << "Convolution:";
416
print_c_mat (convolution);
417
kDebug() << "h_conv_ruv:";
418
print_c_mat (&h_conv_ruv);
419
kDebug() << "Value of s:";
423
Q_ASSERT (s->cols == s->rows);
424
Q_ASSERT (s->rows == b->rows);
425
status = dgesv (s->rows, 1, s->data, s->rows, b->data, b->rows);
429
result = copy_cvec2mat (b, m);
433
result = copy_vec2mat (b, m);
437
kDebug() << "Deconvolution:";
438
print_c_mat (result);
442
finish_c_mat (&h_conv_ruv);
443
finish_c_mat (&corr);
444
finish_and_free_matrix (s);
445
finish_and_free_matrix (b);
449
CMat *RefocusMatrix::compute_g_matrix (const CMat * const convolution, const int m,
450
const double gamma, const double noise_factor,
451
const double musq, const bool symmetric)
454
kDebug() << "matrix size: " << m;
455
kDebug() << "correlation: " << gamma;
456
kDebug() << "noise: " << noise_factor;
459
CMat *g = compute_g (convolution, m, gamma, noise_factor, musq, symmetric);
463
/* Determine sum of array */
464
for (r = -g->radius; r <= g->radius; ++r)
466
for (c = -g->radius; c <= g->radius; ++c)
468
sum += c_mat_elt (g, r, c);
472
for (r = -g->radius; r <= g->radius; ++r)
474
for (c = -g->radius; c <= g->radius; ++c)
476
*c_mat_eltptr (g, r, c) /= sum;
483
void RefocusMatrix::fill_matrix (CMat * matrix, const int m,
484
double f (const int, const int, const double),
485
const double fun_arg)
488
init_c_mat (matrix, m);
490
for (y = -m; y <= m; ++y)
492
for (x = -m; x <= m; ++x)
494
*c_mat_eltptr (matrix, x, y) = f (x, y, fun_arg);
499
void RefocusMatrix::fill_matrix2 (CMat * matrix, const int m,
500
double f (const int, const int, const double, const double),
501
const double fun_arg1, const double fun_arg2)
504
init_c_mat (matrix, m);
506
for (y = -m; y <= m; ++y)
508
for (x = -m; x <= m; ++x)
510
*c_mat_eltptr (matrix, x, y) = f (x, y, fun_arg1, fun_arg2);
515
void RefocusMatrix::make_gaussian_convolution (const double gradius, CMat * convolution, const int m)
520
kDebug() << "gauss: " << gradius;
523
init_c_mat (convolution, m);
525
if (SQR (gradius) <= 1.0e10F / 3.40282347e28F)
527
for (y = -m; y <= m; ++y)
529
for (x = -m; x <= m; ++x)
531
*c_mat_eltptr (convolution, x, y) = 0;
535
*c_mat_eltptr (convolution, 0, 0) = 1;
539
const double alpha = log (2.0) / SQR (gradius);
541
for (y = -m; y <= m; ++y)
543
for (x = -m; x <= m; ++x)
545
*c_mat_eltptr (convolution, x, y) =
546
exp (-alpha * (SQR (x) + SQR (y)));
552
/** Return the integral of sqrt(radius^2 - z^2) for z = 0 to x. */
554
double RefocusMatrix::circle_integral (const double x, const double radius)
558
// Perhaps some epsilon must be added here.
563
const double sin = x / radius;
564
const double sq_diff = SQR (radius) - SQR (x);
565
// From a mathematical point of view the following is redundant.
566
// Numerically they are not equivalent!
568
if ((sq_diff < 0.0) || (sin < -1.0) || (sin > 1.0))
572
return (-0.25 * SQR (radius) * M_PI);
576
return (0.25 * SQR (radius) * M_PI);
581
return (0.5 * x * sqrt (sq_diff) + 0.5 * SQR (radius) * asin (sin));
586
double RefocusMatrix::circle_intensity (const int x, const int y, const double radius)
590
return (((x == 0) && (y == 0)) ? 1 : 0);
594
register double xlo = qAbs (x) - 0.5, xhi = qAbs (x) + 0.5,
595
ylo = qAbs (y) - 0.5, yhi = qAbs (y) + 0.5;
596
register double symmetry_factor = 1, xc1, xc2;
601
symmetry_factor *= 2;
607
symmetry_factor *= 2;
610
if (SQR (xlo) + SQR (yhi) > SQR (radius))
614
else if (SQR (xhi) + SQR (yhi) > SQR (radius))
616
xc1 = sqrt (SQR (radius) - SQR (yhi));
623
if (SQR (xlo) + SQR (ylo) > SQR (radius))
627
else if (SQR (xhi) + SQR (ylo) > SQR (radius))
629
xc2 = sqrt (SQR (radius) - SQR (ylo));
636
return (((yhi - ylo) * (xc1 - xlo) +
637
circle_integral (xc2, radius) - circle_integral (xc1, radius) -
638
(xc2 - xc1) * ylo) * symmetry_factor / (M_PI * SQR (radius)));
642
void RefocusMatrix::make_circle_convolution (const double radius, CMat * convolution, const int m)
645
kDebug() << "radius: " << radius;
648
fill_matrix (convolution, m, circle_intensity, radius);
651
int RefocusMatrix::dgesv (const int N, const int NRHS, double *A, const int lda, double *B, const int ldb)
654
integer i_N = N, i_NHRS = NRHS, i_lda = lda, i_ldb = ldb, info;
655
integer *ipiv = new integer[N];
658
dgesv_ (&i_N, &i_NHRS, A, &i_lda, ipiv, B, &i_ldb, &info);
665
} // namespace Digikam