GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/gage/deconvolve.c Lines: 0 158 0.0 %
Date: 2017-05-26 Branches: 0 124 0.0 %

Line Branch Exec Source
1
/*
2
  Teem: Tools to process and visualize scientific data and images             .
3
  Copyright (C) 2013, 2012, 2011, 2010, 2009  University of Chicago
4
  Copyright (C) 2008, 2007, 2006, 2005  Gordon Kindlmann
5
  Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998  University of Utah
6
7
  This library is free software; you can redistribute it and/or
8
  modify it under the terms of the GNU Lesser General Public License
9
  (LGPL) as published by the Free Software Foundation; either
10
  version 2.1 of the License, or (at your option) any later version.
11
  The terms of redistributing and/or modifying this software also
12
  include exceptions to the LGPL that facilitate static linking.
13
14
  This library is distributed in the hope that it will be useful,
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
  Lesser General Public License for more details.
18
19
  You should have received a copy of the GNU Lesser General Public License
20
  along with this library; if not, write to Free Software Foundation, Inc.,
21
  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
*/
23
24
#include "gage.h"
25
#include "privateGage.h"
26
27
int
28
gageDeconvolve(Nrrd *_nout, double *lastDiffP,
29
               const Nrrd *nin, const gageKind *kind,
30
               const NrrdKernelSpec *ksp, int typeOut,
31
               unsigned int maxIter, int saveAnyway,
32
               double step, double epsilon, int verbose) {
33
  static const char me[]="gageDeconvolve";
34
  gageContext *ctx[2];
35
  gagePerVolume *pvl[2];
36
  double *out[2], *val[2], alpha, (*lup)(const void *, size_t), meandiff=0;
37
  const double *ans[2];
38
  Nrrd *nout[2];
39
  airArray *mop;
40
  unsigned int sx, sy, sz, xi, yi, zi, anslen, thiz=0, last, inIdx, iter;
41
  int E, valItem;
42
43
  if (!(_nout && lastDiffP && nin && kind && ksp)) {
44
    biffAddf(GAGE, "%s: got NULL pointer", me);
45
    return 1;
46
  }
47
  if (!(nrrdTypeDefault == typeOut
48
        || !airEnumValCheck(nrrdType, typeOut))) {
49
    biffAddf(GAGE, "%s: typeOut %d not valid", me, typeOut);
50
    return 1;
51
  }
52
  if (!( maxIter >= 1 )) {
53
    biffAddf(GAGE, "%s: need maxIter >= 1 (not %u)", me, maxIter);
54
    return 1;
55
  }
56
  if (!( epsilon >= 0 )) {
57
    biffAddf(GAGE, "%s: need epsilon >= 0.0 (not %g)", me, epsilon);
58
    return 1;
59
  }
60
61
  /* this once changed from 0 to 1, but is unlikely to change again */
62
  valItem = 1;
63
64
  mop = airMopNew();
65
  for (iter=0; iter<2; iter++) {
66
    nout[iter] = nrrdNew();
67
    airMopAdd(mop, nout[iter], (airMopper)nrrdNuke, airMopAlways);
68
    if (nrrdConvert(nout[iter], nin, nrrdTypeDouble)) {
69
      biffMovef(GAGE, NRRD, "%s: couldn't allocate working buffer %u",
70
                me, iter);
71
      airMopError(mop); return 1;
72
    }
73
    ctx[iter] = gageContextNew();
74
    airMopAdd(mop, ctx[iter], (airMopper)gageContextNix, airMopAlways);
75
    E = 0;
76
    if (!E) E |= !(pvl[iter] = gagePerVolumeNew(ctx[iter], nout[iter], kind));
77
    if (!E) E |= gagePerVolumeAttach(ctx[iter], pvl[iter]);
78
    if (!E) E |= gageKernelSet(ctx[iter], gageKernel00,
79
                               ksp->kernel, ksp->parm);
80
    if (!E) E |= gageQueryItemOn(ctx[iter], pvl[iter], valItem);
81
    if (!E) E |= gageUpdate(ctx[iter]);
82
    if (E) {
83
      biffAddf(GAGE, "%s: trouble setting up context %u", me, iter);
84
      airMopError(mop); return 1;
85
    }
86
    out[iter] = AIR_CAST(double*, nout[iter]->data);
87
    ans[iter] = gageAnswerPointer(ctx[iter], pvl[iter], valItem);
88
  }
89
90
  anslen = kind->table[valItem].answerLength;
91
  lup = nrrdDLookup[nin->type];
92
93
  alpha = ksp->kernel->eval1_d(0.0, ksp->parm);
94
  sx = ctx[0]->shape->size[0];
95
  sy = ctx[0]->shape->size[1];
96
  sz = ctx[0]->shape->size[2];
97
98
  for (iter=0; iter<maxIter; iter++) {
99
    thiz = (iter+1) % 2;
100
    last = (iter+0) % 2;
101
    val[thiz] = out[thiz];
102
    val[last] = out[last];
103
    inIdx = 0;
104
    meandiff = 0;
105
    for (zi=0; zi<sz; zi++) {
106
      for (yi=0; yi<sy; yi++) {
107
        for (xi=0; xi<sx; xi++) {
108
          unsigned int ai;
109
          double in, aa;
110
          gageProbe(ctx[last], xi, yi, zi);
111
          for (ai=0; ai<anslen; ai++) {
112
            in = lup(nin->data, ai + anslen*inIdx);
113
            aa = ans[last][ai];
114
            val[thiz][ai] = val[last][ai] + step*(in - aa)/alpha;
115
            meandiff += 2*(in - aa)*(in - aa)/(DBL_EPSILON + in*in + aa*aa);
116
          }
117
          val[thiz] += anslen;
118
          val[last] += anslen;
119
          ++inIdx;
120
        }
121
      }
122
    }
123
    meandiff /= sx*sy*sz;
124
    if (verbose) {
125
      fprintf(stderr, "%s: iter %u meandiff = %g\n", me, iter, meandiff);
126
    }
127
    if (meandiff < epsilon) {
128
      /* we have indeed converged while iter < maxIter */
129
      break;
130
    }
131
  }
132
  if (iter == maxIter) {
133
    if (!saveAnyway) {
134
      biffAddf(GAGE, "%s: failed to converge in %u iterations, meandiff = %g",
135
               me, maxIter, meandiff);
136
      airMopError(mop); return 1;
137
    } else {
138
      if (verbose) {
139
        fprintf(stderr, "%s: at maxIter %u; err %g still > thresh %g\n", me,
140
                iter, meandiff, epsilon);
141
      }
142
    }
143
  }
144
145
  if (nrrdClampConvert(_nout, nout[thiz], (nrrdTypeDefault == typeOut
146
                                           ? nin->type
147
                                           : typeOut))) {
148
    biffAddf(GAGE, "%s: couldn't create output", me);
149
    airMopError(mop); return 1;
150
  }
151
  *lastDiffP = meandiff;
152
153
  airMopOkay(mop);
154
  return 0;
155
}
156
157
/*
158
*******************************
159
** all the following functionality should at some point be
160
** pushed down to nrrd . . .
161
*/
162
163
static void
164
deconvLine(double *line, size_t llen, const NrrdKernelSpec *ksp) {
165
166
  /* Add as many other parameters to this as you want,
167
     like number and location of poles, or whatever other
168
     buffers you think you need (they should be passed,
169
     not allocated and freed on a per-line basis) */
170
171
  /* comment these out when there is a real function body */
172
  AIR_UNUSED(line);
173
  AIR_UNUSED(llen);
174
  AIR_UNUSED(ksp);
175
176
  return;
177
}
178
179
static int
180
deconvTrivial(const NrrdKernelSpec *ksp) {
181
  int ret;
182
183
  /* HEY this will be much easier once kernels have a way of
184
     advertising whether or not they interpolate */
185
  if (1 == ksp->parm[0] &&
186
      (ksp->kernel == nrrdKernelHann ||
187
       ksp->kernel == nrrdKernelBlackman ||
188
       ksp->kernel == nrrdKernelBox ||
189
       ksp->kernel == nrrdKernelCheap ||
190
       ksp->kernel == nrrdKernelTent)) {
191
    ret = AIR_TRUE;
192
  } else {
193
    ret = AIR_FALSE;
194
  }
195
  return ret;
196
}
197
198
int
199
gageDeconvolveSeparableKnown(const NrrdKernelSpec *ksp) {
200
  int ret;
201
202
  if (!ksp) {
203
    ret = 0;
204
  } else if (deconvTrivial(ksp)
205
             || nrrdKernelBSpline3 == ksp->kernel
206
             || nrrdKernelBSpline5 == ksp->kernel) {
207
    ret = 1;
208
  } else {
209
    ret = 0;
210
  }
211
  return ret;
212
}
213
214
int
215
gageDeconvolveSeparable(Nrrd *nout, const Nrrd *nin,
216
                        const gageKind *kind,
217
                        const NrrdKernelSpec *ksp,
218
                        int typeOut) {
219
  static const char me[]="gageDeconvolveSeparable";
220
  double *line, (*lup)(const void *, size_t),
221
    (*ins)(void *, size_t, double);
222
  airArray *mop;
223
  size_t lineLen, sx, sy, sz, idx, ii, jj;
224
  unsigned int vi, valLen;
225
226
  if (!(nout && nin && kind && ksp)) {
227
    biffAddf(GAGE, "%s: got NULL pointer", me);
228
    return 1;
229
  }
230
  if (!(nrrdTypeDefault == typeOut
231
        || !airEnumValCheck(nrrdType, typeOut))) {
232
    biffAddf(GAGE, "%s: typeOut %d not valid", me, typeOut);
233
    return 1;
234
  }
235
  if (!gageDeconvolveSeparableKnown(ksp)) {
236
    biffAddf(GAGE, "%s: separable deconv not known for %s kernel",
237
             me, ksp->kernel->name);
238
    return 1;
239
  }
240
  if (gageKindVolumeCheck(kind, nin)) {
241
    biffAddf(GAGE, "%s: given volume doesn't fit %s kind",
242
             me, kind->name);
243
    return 1;
244
  }
245
  if (nrrdTypeDefault == typeOut
246
      ? nrrdCopy(nout, nin)
247
      : nrrdConvert(nout, nin, typeOut)) {
248
    biffMovef(GAGE, NRRD, "%s: problem allocating output", me);
249
    return 1;
250
  }
251
  if (deconvTrivial(ksp)) {
252
    /* if there's no real work for the deconvolution, then by
253
       copying the values we're already done; bye */
254
    return 0;
255
  }
256
257
  valLen = kind->valLen;
258
  sx = nin->axis[kind->baseDim + 0].size;
259
  sy = nin->axis[kind->baseDim + 1].size;
260
  sz = nin->axis[kind->baseDim + 2].size;
261
  lineLen = sx;
262
  lineLen = AIR_MAX(lineLen, sy);
263
  lineLen = AIR_MAX(lineLen, sz);
264
  lup = nrrdDLookup[nin->type];
265
  ins = nrrdDInsert[nout->type];
266
267
  mop = airMopNew();
268
  line = AIR_CALLOC(lineLen*valLen, double);
269
  airMopAdd(mop, line, airFree, airMopAlways);
270
271
  /* process along X scanlines */
272
  for (jj=0; jj<sy*sz; jj++) {
273
    /* xi = 0, yi = jj%sy, zi = jj/sy
274
       ==> xi + sx*(yi + sy*zi)
275
       == 0 + sx*(jj%sy + sy*(jj/sy)) == 0 + sx*jj */
276
    idx = 0 + valLen*(0 + sx*jj);
277
    for (ii=0; ii<sx; ii++) {
278
      for (vi=0; vi<valLen; vi++) {
279
        line[ii + sx*vi] = lup(nin->data, idx + vi + valLen*ii);
280
      }
281
    }
282
    for (vi=0; vi<valLen; vi++) {
283
      deconvLine(line + sx*vi, sx, ksp);
284
    }
285
    for (ii=0; ii<sx; ii++) {
286
      for (vi=0; vi<valLen; vi++) {
287
        ins(nout->data, idx + vi + valLen*ii, line[ii + sx*vi]);
288
      }
289
    }
290
  }
291
292
  /* process along Y scanlines */
293
  for (jj=0; jj<sx*sz; jj++) {
294
    /* xi = jj%sx, yi = 0, zi = jj/sx
295
       ==> xi + sx*(yi + sy*zi)
296
       == jj%sx + sx*(0 + sy*jj/sx) */
297
    idx = 0 + valLen*((jj%sx) + sx*(0 + sy*(jj/sx)));
298
    for (ii=0; ii<sy; ii++) {
299
      for (vi=0; vi<valLen; vi++) {
300
        line[ii + sy*vi] = lup(nin->data, idx + vi + valLen*sx*ii);
301
      }
302
    }
303
    for (vi=0; vi<valLen; vi++) {
304
      deconvLine(line + sy*vi, sy, ksp);
305
    }
306
    for (ii=0; ii<sx; ii++) {
307
      for (vi=0; vi<valLen; vi++) {
308
        ins(nout->data, idx + vi + valLen*sx*ii, line[ii + sy*vi]);
309
      }
310
    }
311
  }
312
313
  /* process along Z scanlines */
314
  for (jj=0; jj<sx*sy; jj++) {
315
    /* xi = jj%sx, yi = jj/sx, zi = 0
316
       ==> xi + sx*(yi + sy*zi)
317
       == jj%sx + sx*(jj/sx + sy*0)
318
       == jj%sx + sx*(jj/sx) == jj */
319
    idx = 0 + valLen*jj;
320
    for (ii=0; ii<sz; ii++) {
321
      for (vi=0; vi<valLen; vi++) {
322
        line[ii + sz*vi] = lup(nin->data, idx + vi + valLen*sx*sy*ii);
323
      }
324
    }
325
    for (vi=0; vi<valLen; vi++) {
326
      deconvLine(line + sz*vi, sz, ksp);
327
    }
328
    for (ii=0; ii<sx; ii++) {
329
      for (vi=0; vi<valLen; vi++) {
330
        ins(nout->data, idx + vi + valLen*sx*sy*ii, line[ii + sz*vi]);
331
      }
332
    }
333
  }
334
335
  airMopOkay(mop);
336
  return 0;
337
}