summaryrefslogtreecommitdiffstats
path: root/src/imageplugins/coreplugin/sharpnesseditor/matrix.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/imageplugins/coreplugin/sharpnesseditor/matrix.cpp')
-rw-r--r--src/imageplugins/coreplugin/sharpnesseditor/matrix.cpp663
1 files changed, 663 insertions, 0 deletions
diff --git a/src/imageplugins/coreplugin/sharpnesseditor/matrix.cpp b/src/imageplugins/coreplugin/sharpnesseditor/matrix.cpp
new file mode 100644
index 00000000..cfb8afe4
--- /dev/null
+++ b/src/imageplugins/coreplugin/sharpnesseditor/matrix.cpp
@@ -0,0 +1,663 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2005-04-29
+ * Description : refocus deconvolution matrix implementation.
+ *
+ * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ *
+ * Original implementation from Refocus Gimp plug-in
+ * Copyright (C) 1999-2003 Ernst Lippe
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation;
+ * either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * ============================================================ */
+
+// Uncomment this line to debug matrix computation.
+//#define RF_DEBUG 1
+
+// Square
+#define SQR(x) ((x) * (x))
+
+// C++ includes.
+
+#include <cmath>
+
+extern "C"
+{
+#include "f2c.h"
+#include "clapack.h"
+}
+
+// TQt includes.
+
+#include <tqglobal.h>
+#include <tqstring.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "matrix.h"
+
+namespace DigikamImagesPluginCore
+{
+
+Mat *RefocusMatrix::allocate_matrix (int nrows, int ncols)
+{
+ Mat *result = new Mat;
+ memset (result, 0, sizeof(result));
+
+ result->cols = ncols;
+ result->rows = nrows;
+ result->data = new double [nrows * ncols];
+ memset (result->data, 0, nrows * ncols * sizeof(double));
+
+ return (result);
+}
+
+void RefocusMatrix::finish_matrix (Mat * mat)
+{
+ delete [] mat->data;
+}
+
+void RefocusMatrix::finish_and_free_matrix (Mat * mat)
+{
+ delete [] mat->data;
+ delete mat;
+}
+
+double *RefocusMatrix::mat_eltptr (Mat * mat, const int r, const int c)
+{
+ Q_ASSERT ((r >= 0) && (r < mat->rows));
+ Q_ASSERT ((c >= 0) && (c < mat->rows));
+ return (&(mat->data[mat->rows * c + r]));
+}
+
+double RefocusMatrix::mat_elt (const Mat * mat, const int r, const int c)
+{
+ Q_ASSERT ((r >= 0) && (r < mat->rows));
+ Q_ASSERT ((c >= 0) && (c < mat->rows));
+ return (mat->data[mat->rows * c + r]);
+}
+
+void RefocusMatrix::init_c_mat (CMat * mat, const int radius)
+{
+ mat->radius = radius;
+ mat->row_stride = 2 * radius + 1;
+ mat->data = new double [SQR (mat->row_stride)];
+ memset (mat->data, 0, SQR (mat->row_stride) * sizeof(double));
+ mat->center = mat->data + mat->row_stride * mat->radius + mat->radius;
+}
+
+CMat *RefocusMatrix::allocate_c_mat (const int radius)
+{
+ CMat *result = new CMat;
+ memset(result, 0, sizeof(result));
+ init_c_mat (result, radius);
+ return (result);
+}
+
+void RefocusMatrix::finish_c_mat (CMat * mat)
+{
+ delete [] mat->data;
+ mat->data = NULL;
+}
+
+inline double *RefocusMatrix::c_mat_eltptr (CMat * mat, const int col, const int row)
+{
+ Q_ASSERT ((TQABS (row) <= mat->radius) && (TQABS (col) <= mat->radius));
+ return (mat->center + mat->row_stride * row + col);
+}
+
+inline double RefocusMatrix::c_mat_elt (const CMat * const mat, const int col, const int row)
+{
+ Q_ASSERT ((TQABS (row) <= mat->radius) && (TQABS (col) <= mat->radius));
+ return (mat->center[mat->row_stride * row + col]);
+}
+
+void RefocusMatrix::convolve_mat (CMat * result, const CMat * const mata, const CMat * const matb)
+{
+ int xr, yr, xa, ya;
+
+ for (yr = -result->radius; yr <= result->radius; yr++)
+ {
+ for (xr = -result->radius; xr <= result->radius; xr++)
+ {
+ const int ya_low = TQMAX (-mata->radius, yr - matb->radius);
+ const int ya_high = TQMIN (mata->radius, yr + matb->radius);
+ const int xa_low = TQMAX (-mata->radius, xr - matb->radius);
+ const int xa_high = TQMIN (mata->radius, xr + matb->radius);
+ double val = 0.0;
+
+ for (ya = ya_low; ya <= ya_high; ya++)
+ {
+ for (xa = xa_low; xa <= xa_high; xa++)
+ {
+ val += c_mat_elt (mata, xa, ya) *
+ c_mat_elt (matb, xr - xa, yr - ya);
+ }
+ }
+
+ *c_mat_eltptr (result, xr, yr) = val;
+ }
+ }
+}
+
+void RefocusMatrix::convolve_star_mat (CMat * result, const CMat * const mata, const CMat * const matb)
+{
+ int xr, yr, xa, ya;
+
+ for (yr = -result->radius; yr <= result->radius; yr++)
+ {
+ for (xr = -result->radius; xr <= result->radius; xr++)
+ {
+ const int ya_low = TQMAX (-mata->radius, -matb->radius - yr);
+ const int ya_high = TQMIN (mata->radius, matb->radius - yr);
+ const int xa_low = TQMAX (-mata->radius, -matb->radius - xr);
+ const int xa_high = TQMIN (mata->radius, matb->radius - xr);
+ double val = 0.0;
+
+ for (ya = ya_low; ya <= ya_high; ya++)
+ {
+ for (xa = xa_low; xa <= xa_high; xa++)
+ {
+ val += c_mat_elt (mata, xa, ya) *
+ c_mat_elt (matb, xr + xa, yr + ya);
+ }
+ }
+
+ *c_mat_eltptr (result, xr, yr) = val;
+ }
+ }
+}
+
+void RefocusMatrix::convolve_mat_fun (CMat * result, const CMat * const mata, double (f) (int, int))
+{
+ int xr, yr, xa, ya;
+
+ for (yr = -result->radius; yr <= result->radius; yr++)
+ {
+ for (xr = -result->radius; xr <= result->radius; xr++)
+ {
+ double val = 0.0;
+
+ for (ya = -mata->radius; ya <= mata->radius; ya++)
+ {
+ for (xa = -mata->radius; xa <= mata->radius; xa++)
+ {
+ val += c_mat_elt (mata, xa, ya) * f (xr - xa, yr - ya);
+ }
+ }
+
+ *c_mat_eltptr (result, xr, yr) = val;
+ }
+ }
+}
+
+int RefocusMatrix::as_idx (const int k, const int l, const int m)
+{
+ return ((k + m) * (2 * m + 1) + (l + m));
+}
+
+int RefocusMatrix::as_cidx (const int k, const int l)
+{
+ const int a = TQMAX (TQABS (k), TQABS (l));
+ const int b = TQMIN (TQABS (k), TQABS (l));
+ return ((a * (a + 1)) / 2 + b);
+}
+
+void RefocusMatrix::print_c_mat (const CMat * const mat)
+{
+ int x, y;
+
+ for (y = -mat->radius; y <= mat->radius; y++)
+ {
+ TQString output, num;
+
+ for (x = -mat->radius; x <= mat->radius; x++)
+ {
+ output.append( num.setNum( c_mat_elt (mat, x, y) ) );
+ }
+
+ DDebug() << output << endl;
+ }
+}
+
+void RefocusMatrix::print_matrix (Mat * matrix)
+{
+ int col_idx, row_idx;
+
+ for (row_idx = 0; row_idx < matrix->rows; row_idx++)
+ {
+ TQString output, num;
+
+ for (col_idx = 0; col_idx < matrix->cols; col_idx++)
+ {
+ output.append( num.setNum( mat_elt (matrix, row_idx, col_idx) ) );
+ }
+
+ DDebug() << output << endl;
+ }
+}
+
+Mat *RefocusMatrix::make_s_matrix (CMat * mat, int m, double noise_factor)
+{
+ const int mat_size = SQR (2 * m + 1);
+ Mat *result = allocate_matrix (mat_size, mat_size);
+ int yr, yc, xr, xc;
+
+ for (yr = -m; yr <= m; yr++)
+ {
+ for (xr = -m; xr <= m; xr++)
+ {
+ for (yc = -m; yc <= m; yc++)
+ {
+ for (xc = -m; xc <= m; xc++)
+ {
+ *mat_eltptr (result, as_idx (xr, yr, m),
+ as_idx (xc, yc, m)) =
+ c_mat_elt (mat, xr - xc, yr - yc);
+ if ((xr == xc) && (yr == yc))
+ {
+ *mat_eltptr (result, as_idx (xr, yr, m),
+ as_idx (xc, yc, m)) += noise_factor;
+ }
+ }
+ }
+ }
+ }
+
+ return (result);
+}
+
+Mat *RefocusMatrix::make_s_cmatrix (CMat * mat, int m, double noise_factor)
+{
+ const int mat_size = as_cidx (m + 1, 0);
+ Mat *result = allocate_matrix (mat_size, mat_size);
+ int yr, yc, xr, xc;
+
+ for (yr = 0; yr <= m; yr++)
+ {
+ for (xr = 0; xr <= yr; xr++)
+ {
+ for (yc = -m; yc <= m; yc++)
+ {
+ for (xc = -m; xc <= m; xc++)
+ {
+ *mat_eltptr (result, as_cidx (xr, yr), as_cidx (xc, yc)) +=
+ c_mat_elt (mat, xr - xc, yr - yc);
+ if ((xr == xc) && (yr == yc))
+ {
+ *mat_eltptr (result, as_cidx (xr, yr),
+ as_cidx (xc, yc)) += noise_factor;
+ }
+ }
+ }
+ }
+ }
+
+ return (result);
+}
+
+double RefocusMatrix::correlation (const int x, const int y, const double gamma, const double musq)
+{
+ return (musq + pow (gamma, sqrt (SQR (x) + SQR (y))));
+}
+
+Mat *RefocusMatrix::copy_vec (const CMat * const mat, const int m)
+{
+ Mat *result = allocate_matrix (SQR (2 * m + 1), 1);
+ int x, y, index = 0;
+
+ for (y = -m; y <= m; y++)
+ {
+ for (x = -m; x <= m; x++)
+ {
+ *mat_eltptr (result, index, 0) = c_mat_elt (mat, x, y);
+ index++;
+ }
+ }
+
+ Q_ASSERT (index == SQR (2 * m + 1));
+ return (result);
+}
+
+Mat *RefocusMatrix::copy_cvec (const CMat * const mat, const int m)
+{
+ Mat *result = allocate_matrix (as_cidx (m + 1, 0), 1);
+ int x, y, index = 0;
+
+ for (y = 0; y <= m; y++)
+ {
+ for (x = 0; x <= y; x++)
+ {
+ *mat_eltptr (result, index, 0) = c_mat_elt (mat, x, y);
+ index++;
+ }
+ }
+
+ Q_ASSERT (index == as_cidx (m + 1, 0));
+ return (result);
+}
+
+CMat *RefocusMatrix::copy_cvec2mat (const Mat * const cvec, const int m)
+{
+ CMat *result = allocate_c_mat (m);
+ int x, y;
+
+ for (y = -m; y <= m; y++)
+ {
+ for (x = -m; x <= m; x++)
+ {
+ *c_mat_eltptr (result, x, y) = mat_elt (cvec, as_cidx (x, y), 0);
+ }
+ }
+
+ return (result);
+}
+
+CMat *RefocusMatrix::copy_vec2mat (const Mat * const cvec, const int m)
+{
+ CMat *result = allocate_c_mat (m);
+ int x, y;
+
+ for (y = -m; y <= m; y++)
+ {
+ for (x = -m; x <= m; x++)
+ {
+ *c_mat_eltptr (result, x, y) = mat_elt (cvec, as_idx (x, y, m), 0);
+ }
+ }
+
+ return (result);
+}
+
+CMat *RefocusMatrix::compute_g (const CMat * const convolution, const int m, const double gamma,
+ const double noise_factor, const double musq, const bool symmetric)
+{
+ CMat h_conv_ruv, a, corr;
+ CMat *result;
+ Mat *b;
+ Mat *s;
+ int status;
+
+ init_c_mat (&h_conv_ruv, 3 * m);
+ fill_matrix2 (&corr, 4 * m, correlation, gamma, musq);
+ convolve_mat (&h_conv_ruv, convolution, &corr);
+ init_c_mat (&a, 2 * m);
+ convolve_star_mat (&a, convolution, &h_conv_ruv);
+
+ if (symmetric)
+ {
+ s = make_s_cmatrix (&a, m, noise_factor);
+ b = copy_cvec (&h_conv_ruv, m);
+ }
+ else
+ {
+ s = make_s_matrix (&a, m, noise_factor);
+ b = copy_vec (&h_conv_ruv, m);
+ }
+
+#ifdef RF_DEBUG
+ DDebug() << "Convolution:" << endl;
+ print_c_mat (convolution);
+ DDebug() << "h_conv_ruv:" << endl;
+ print_c_mat (&h_conv_ruv);
+ DDebug() << "Value of s:" << endl;
+ print_matrix (s);
+#endif
+
+ Q_ASSERT (s->cols == s->rows);
+ Q_ASSERT (s->rows == b->rows);
+ status = dgesv (s->rows, 1, s->data, s->rows, b->data, b->rows);
+
+ if (symmetric)
+ {
+ result = copy_cvec2mat (b, m);
+ }
+ else
+ {
+ result = copy_vec2mat (b, m);
+ }
+
+#ifdef RF_DEBUG
+ DDebug() << "Deconvolution:" << endl;
+ print_c_mat (result);
+#endif
+
+ finish_c_mat (&a);
+ finish_c_mat (&h_conv_ruv);
+ finish_c_mat (&corr);
+ finish_and_free_matrix (s);
+ finish_and_free_matrix (b);
+ return (result);
+}
+
+CMat *RefocusMatrix::compute_g_matrix (const CMat * const convolution, const int m,
+ const double gamma, const double noise_factor,
+ const double musq, const bool symmetric)
+{
+#ifdef RF_DEBUG
+ DDebug() << "matrix size: " << m << endl;
+ DDebug() << "correlation: " << gamma << endl;
+ DDebug() << "noise: " << noise_factor << endl;
+#endif
+
+ CMat *g = compute_g (convolution, m, gamma, noise_factor, musq, symmetric);
+ int r, c;
+ double sum = 0.0;
+
+ /* Determine sum of array */
+ for (r = -g->radius; r <= g->radius; r++)
+ {
+ for (c = -g->radius; c <= g->radius; c++)
+ {
+ sum += c_mat_elt (g, r, c);
+ }
+ }
+
+ for (r = -g->radius; r <= g->radius; r++)
+ {
+ for (c = -g->radius; c <= g->radius; c++)
+ {
+ *c_mat_eltptr (g, r, c) /= sum;
+ }
+ }
+
+ return (g);
+}
+
+void RefocusMatrix::fill_matrix (CMat * matrix, const int m,
+ double f (const int, const int, const double),
+ const double fun_arg)
+{
+ int x, y;
+ init_c_mat (matrix, m);
+
+ for (y = -m; y <= m; y++)
+ {
+ for (x = -m; x <= m; x++)
+ {
+ *c_mat_eltptr (matrix, x, y) = f (x, y, fun_arg);
+ }
+ }
+}
+
+void RefocusMatrix::fill_matrix2 (CMat * matrix, const int m,
+ double f (const int, const int, const double, const double),
+ const double fun_arg1, const double fun_arg2)
+{
+ int x, y;
+ init_c_mat (matrix, m);
+
+ for (y = -m; y <= m; y++)
+ {
+ for (x = -m; x <= m; x++)
+ {
+ *c_mat_eltptr (matrix, x, y) = f (x, y, fun_arg1, fun_arg2);
+ }
+ }
+}
+
+void RefocusMatrix::make_gaussian_convolution (const double gradius, CMat * convolution, const int m)
+{
+ int x, y;
+
+#ifdef RF_DEBUG
+ DDebug() << "gauss: " << gradius << endl;
+#endif
+
+ init_c_mat (convolution, m);
+
+ if (SQR (gradius) <= 1 / 3.40282347e38F)
+ {
+ for (y = -m; y <= m; y++)
+ {
+ for (x = -m; x <= m; x++)
+ {
+ *c_mat_eltptr (convolution, x, y) = 0;
+ }
+ }
+
+ *c_mat_eltptr (convolution, 0, 0) = 1;
+ }
+ else
+ {
+ const double alpha = log (2.0) / SQR (gradius);
+
+ for (y = -m; y <= m; y++)
+ {
+ for (x = -m; x <= m; x++)
+ {
+ *c_mat_eltptr (convolution, x, y) =
+ exp (-alpha * (SQR (x) + SQR (y)));
+ }
+ }
+ }
+}
+
+/** Return the integral of sqrt(radius^2 - z^2) for z = 0 to x. */
+
+double RefocusMatrix::circle_integral (const double x, const double radius)
+{
+ if (radius == 0)
+ {
+ // Perhaps some epsilon must be added here.
+ return (0);
+ }
+ else
+ {
+ const double sin = x / radius;
+ const double sq_diff = SQR (radius) - SQR (x);
+ // From a mathematical point of view the following is redundant.
+ // Numerically they are not equivalent!
+
+ if ((sq_diff < 0.0) || (sin < -1.0) || (sin > 1.0))
+ {
+ if (sin < 0)
+ {
+ return (-0.25 * SQR (radius) * M_PI);
+ }
+ else
+ {
+ return (0.25 * SQR (radius) * M_PI);
+ }
+ }
+ else
+ {
+ return (0.5 * x * sqrt (sq_diff) + 0.5 * SQR (radius) * asin (sin));
+ }
+ }
+}
+
+double RefocusMatrix::circle_intensity (const int x, const int y, const double radius)
+{
+ if (radius == 0)
+ {
+ return (((x == 0) && (y == 0)) ? 1 : 0);
+ }
+ else
+ {
+ double xlo = TQABS (x) - 0.5, xhi = TQABS (x) + 0.5,
+ ylo = TQABS (y) - 0.5, yhi = TQABS (y) + 0.5;
+ double symmetry_factor = 1, xc1, xc2;
+
+ if (xlo < 0)
+ {
+ xlo = 0;
+ symmetry_factor *= 2;
+ }
+
+ if (ylo < 0)
+ {
+ ylo = 0;
+ symmetry_factor *= 2;
+ }
+
+ if (SQR (xlo) + SQR (yhi) > SQR (radius))
+ {
+ xc1 = xlo;
+ }
+ else if (SQR (xhi) + SQR (yhi) > SQR (radius))
+ {
+ xc1 = sqrt (SQR (radius) - SQR (yhi));
+ }
+ else
+ {
+ xc1 = xhi;
+ }
+
+ if (SQR (xlo) + SQR (ylo) > SQR (radius))
+ {
+ xc2 = xlo;
+ }
+ else if (SQR (xhi) + SQR (ylo) > SQR (radius))
+ {
+ xc2 = sqrt (SQR (radius) - SQR (ylo));
+ }
+ else
+ {
+ xc2 = xhi;
+ }
+
+ return (((yhi - ylo) * (xc1 - xlo) +
+ circle_integral (xc2, radius) - circle_integral (xc1, radius) -
+ (xc2 - xc1) * ylo) * symmetry_factor / (M_PI * SQR (radius)));
+ }
+}
+
+void RefocusMatrix::make_circle_convolution (const double radius, CMat * convolution, const int m)
+{
+#ifdef RF_DEBUG
+ DDebug() << "radius: " << radius << endl;
+#endif
+
+ fill_matrix (convolution, m, circle_intensity, radius);
+}
+
+int RefocusMatrix::dgesv (const int N, const int NRHS, double *A, const int lda, double *B, const int ldb)
+{
+ int result = 0;
+ integer i_N = N, i_NHRS = NRHS, i_lda = lda, i_ldb = ldb, info;
+ integer *ipiv = new integer[N];
+
+ // Clapack call.
+ dgesv_ (&i_N, &i_NHRS, A, &i_lda, ipiv, B, &i_ldb, &info);
+
+ delete [] ipiv;
+ result = info;
+ return (result);
+}
+
+} // NameSpace DigikamImagesPluginCore