GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/gage/sclanswer.c Lines: 45 175 25.7 %
Date: 2017-05-26 Branches: 35 112 31.2 %

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
/* HEY copied from ten.h */
28
#define TEN_M2T(t, m) (                         \
29
                       (t)[1] = (m)[0],         \
30
                       (t)[2] = ((m)[1]+(m)[3])/2.0,    \
31
                       (t)[3] = ((m)[2]+(m)[6])/2.0,    \
32
                       (t)[4] = (m)[4],                 \
33
                       (t)[5] = ((m)[5]+(m)[7])/2.0,    \
34
                       (t)[6] = (m)[8])
35
#define TEN_T_SCALE(a, s, b) (    \
36
                              (a)[0] = (b)[0],  \
37
                              (a)[1] = (s)*(b)[1],      \
38
                              (a)[2] = (s)*(b)[2],      \
39
                              (a)[3] = (s)*(b)[3],      \
40
                              (a)[4] = (s)*(b)[4],      \
41
                              (a)[5] = (s)*(b)[5],      \
42
                              (a)[6] = (s)*(b)[6])
43
44
void
45
_gageSclAnswer(gageContext *ctx, gagePerVolume *pvl) {
46
1789650
  char me[]="_gageSclAnswer";
47
  double gmag=0, *hess, *norm, *gvec, *gten, *k1, *k2, curv=0,
48
    sHess[9]={0,0,0,0,0,0,0,0,0};
49
894825
  double tmpMat[9], tmpVec[3], hevec[9], heval[3];
50
894825
  double len, gp1[3], gp2[3], *nPerp, ncTen[9], nProj[9]={0,0,0,0,0,0,0,0,0};
51
  double alpha = 0.5;
52
  double beta = 0.5;
53
  double _gamma = 5;
54
  double cc = 1e-6;
55
#define FD_MEDIAN_MAX 16
56
  int fd, nidx, xi, yi, zi;
57
894825
  double *fw, iv3wght[2*FD_MEDIAN_MAX*FD_MEDIAN_MAX*FD_MEDIAN_MAX],
58
    wghtSum, wght;
59
60
  /* convenience pointers for work below */
61
894825
  hess = pvl->directAnswer[gageSclHessian];
62
894825
  gvec = pvl->directAnswer[gageSclGradVec];
63
894825
  norm = pvl->directAnswer[gageSclNormal];
64
894825
  nPerp = pvl->directAnswer[gageSclNPerp];
65
894825
  gten = pvl->directAnswer[gageSclGeomTens];
66
894825
  k1 = pvl->directAnswer[gageSclK1];
67
894825
  k2 = pvl->directAnswer[gageSclK2];
68
69
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclValue)) {
70
    /* done if doV */
71
894825
    if (ctx->verbose > 2) {
72
      fprintf(stderr, "%s: val = % 15.7f\n", me,
73
              (double)(pvl->directAnswer[gageSclValue][0]));
74
    }
75
  }
76
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclGradVec)) {
77
    /* done if doD1 */
78
752905
    if (ctx->verbose > 2) {
79
      fprintf(stderr, "%s: gvec = ", me);
80
      ell_3v_print_d(stderr, gvec);
81
    }
82
  }
83
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclGradMag)) {
84
    /* this is the true value of gradient magnitude */
85
    gmag = pvl->directAnswer[gageSclGradMag][0] = sqrt(ELL_3V_DOT(gvec, gvec));
86
  }
87
88
  /* NB: it would seem that gageParmGradMagMin is completely ignored . . . */
89
90
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclNormal)) {
91
    if (gmag) {
92
      ELL_3V_SCALE(norm, 1/gmag, gvec);
93
      /* polishing
94
         len = sqrt(ELL_3V_DOT(norm, norm));
95
         ELL_3V_SCALE(norm, 1/len, norm);
96
      */
97
    } else {
98
      ELL_3V_COPY(norm, gageZeroNormal);
99
    }
100
  }
101
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclNProj)) {
102
    ELL_3MV_OUTER(pvl->directAnswer[gageSclNProj], norm, norm);
103
  }
104
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclNPerp)) {
105
    /* nPerp = I - outer(norm, norm) */
106
    /* NB: this sets both nPerp and nProj */
107
    ELL_3MV_OUTER(nProj, norm, norm);
108
    ELL_3M_SCALE(nPerp, -1, nProj);
109
    nPerp[0] += 1;
110
    nPerp[4] += 1;
111
    nPerp[8] += 1;
112
  }
113
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessian)) {
114
    /* done if doD2 */
115
752905
    if (ctx->verbose > 2) {
116
      fprintf(stderr, "%s: hess = \n", me);
117
      ell_3m_print_d(stderr, hess);
118
    }
119
  }
120
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessianTen)) {
121
    pvl->directAnswer[gageSclHessianTen][0] = 1.0;
122
    TEN_M2T(pvl->directAnswer[gageSclHessianTen],
123
            pvl->directAnswer[gageSclHessian]);
124
  }
125
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclLaplacian)) {
126
    pvl->directAnswer[gageSclLaplacian][0] = hess[0] + hess[4] + hess[8];
127
    if (ctx->verbose > 2) {
128
      fprintf(stderr, "%s: lapl = %g + %g + %g  = %g\n", me,
129
              hess[0], hess[4], hess[8],
130
              pvl->directAnswer[gageSclLaplacian][0]);
131
    }
132
  }
133
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessFrob)) {
134
    pvl->directAnswer[gageSclHessFrob][0] = ELL_3M_FROB(hess);
135
  }
136
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessEval)) {
137
    if (ctx->parm.twoDimZeroZ) {
138
      ell_3m2sub_eigensolve_d(heval, hevec, hess);
139
    } else {
140
      /* HEY: look at the return value for root multiplicity? */
141
      ell_3m_eigensolve_d(heval, hevec, hess, AIR_TRUE);
142
    }
143
    ELL_3V_COPY(pvl->directAnswer[gageSclHessEval], heval);
144
  }
145
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessEvec)) {
146
    ELL_3M_COPY(pvl->directAnswer[gageSclHessEvec], hevec);
147
  }
148
#if 1
149
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessRidgeness)) {
150
    double A, B, S;
151
    if (heval[1] >0 || heval[2]>0) {
152
      pvl->directAnswer[gageSclHessRidgeness][0] = 0;
153
    }
154
    else if (AIR_ABS(heval[1])<1e-10 || AIR_ABS(heval[2])<1e-10) {
155
      pvl->directAnswer[gageSclHessRidgeness][0] = 0;
156
    }
157
    else {
158
      double *ans;
159
      A = AIR_ABS(heval[1])/AIR_ABS(heval[2]);
160
      B = AIR_ABS(heval[0])/sqrt(AIR_ABS(heval[1]*heval[2]));
161
      S = sqrt(heval[0]*heval[0] + heval[1]*heval[1] + heval[2]*heval[2]);
162
      ans = pvl->directAnswer[gageSclHessRidgeness];
163
      ans[0] = (1-exp(-A*A/(2*alpha*alpha))) *
164
        exp(-B*B/(2*beta*beta)) *
165
        (1-exp(-S*S/(2*_gamma*_gamma))) *
166
        exp(-2*cc*cc/(AIR_ABS(heval[1])*heval[2]*heval[2]));
167
    }
168
  }
169
#else
170
  /* alternative implementation by GLK, based on directly following
171
     Frangi text.  Only significant difference from above is a
172
     discontinuity at heval[0] = -heval[1] */
173
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessRidgeness)) {
174
    double ev[4], tmp;
175
    ELL_3V_COPY(ev+1, heval);
176
    if (AIR_ABS(ev[2]) > AIR_ABS(ev[3])) { ELL_SWAP2(ev[2], ev[3], tmp); }
177
    if (AIR_ABS(ev[1]) > AIR_ABS(ev[2])) { ELL_SWAP2(ev[1], ev[2], tmp); }
178
    if (AIR_ABS(ev[2]) > AIR_ABS(ev[3])) { ELL_SWAP2(ev[2], ev[3], tmp); }
179
    if (ev[2] > 0 || ev[3] > 0) {
180
      pvl->directAnswer[gageSclHessRidgeness][0] = 0;
181
    } else {
182
      double a1, a2, a3, RB, RA, SS, fa, fb, fg, aa, bb, gg, frangi;
183
      a1 = AIR_ABS(ev[1]);
184
      a2 = AIR_ABS(ev[2]);
185
      a3 = AIR_ABS(ev[3]);
186
      RB = a1/sqrt(a2*a3);
187
      RA = a2/a3;
188
      SS = sqrt(a1*a1 + a2*a2 + a3*a3);
189
      aa = bb = 0.5;
190
      gg = 1;
191
      fa = 1 - exp(-RA*RA/(2*aa*aa));
192
      fb = exp(-RB*RB/(2*bb*bb));
193
      fg = 1 - exp(-SS*SS/(2*gg*gg));
194
      frangi = fa*fb*fg;
195
      if (!AIR_EXISTS(frangi)) { frangi = 0.0; }
196
      pvl->directAnswer[gageSclHessRidgeness][0] = frangi;
197
    }
198
  }
199
#endif
200
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessValleyness)) {
201
    double A, B, S;
202
    if (heval[0] <0 || heval[1]<0) {
203
      pvl->directAnswer[gageSclHessValleyness][0] = 0;
204
    }
205
    else if (AIR_ABS(heval[0])<1e-10 || AIR_ABS(heval[1])<1e-10) {
206
      pvl->directAnswer[gageSclHessValleyness][0] = 0;
207
    }
208
    else {
209
      double *ans;
210
      A = AIR_ABS(heval[1])/AIR_ABS(heval[0]);
211
      B = AIR_ABS(heval[2])/sqrt(AIR_ABS(heval[1]*heval[0]));
212
      S = sqrt(heval[0]*heval[0] + heval[1]*heval[1] + heval[2]*heval[2]);
213
      ans = pvl->directAnswer[gageSclHessValleyness];
214
      ans[0] = (1-exp(-A*A/(2*alpha*alpha))) *
215
        exp(-B*B/(2*beta*beta)) *
216
        (1-exp(-S*S/(2*_gamma*_gamma))) *
217
        exp(-2*cc*cc/(AIR_ABS(heval[1])*heval[0]*heval[0]));
218
    }
219
  }
220
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessDotPeakness)) {
221
#define OSQT 0.57735026918962576451
222
    double neval[3], hlen, pness,
223
      peak[3] = {-OSQT, -OSQT, -OSQT};
224
    ELL_3V_NORM(neval, heval, hlen);
225
    if (!hlen) {
226
      pness = 0;
227
    } else {
228
      pness = ELL_3V_DOT(peak, neval);
229
      pness = AIR_AFFINE(-1, pness, 1, 0, 1);
230
      pvl->directAnswer[gageSclHessDotPeakness][0] = pness;
231
    }
232
#undef OSQT
233
  }
234
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessMode)) {
235
    pvl->directAnswer[gageSclHessMode][0] = airMode3_d(heval);
236
  }
237
238
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageScl2ndDD)) {
239
    ELL_3MV_MUL(tmpVec, hess, norm);
240
    pvl->directAnswer[gageScl2ndDD][0] = ELL_3V_DOT(norm, tmpVec);
241
  }
242
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclGeomTens)) {
243
    if (gmag > ctx->parm.gradMagCurvMin) {
244
      /* parm.curvNormalSide applied here to determine the sense of the
245
         normal when doing all curvature calculations */
246
      ELL_3M_SCALE(sHess, -(ctx->parm.curvNormalSide)/gmag, hess);
247
248
      /* gten = nPerp * sHess * nPerp */
249
      ELL_3M_MUL(tmpMat, sHess, nPerp);
250
      ELL_3M_MUL(gten, nPerp, tmpMat);
251
252
      if (ctx->verbose > 2) {
253
        fprintf(stderr, "%s: gten: \n", me);
254
        ell_3m_print_d(stderr, gten);
255
        ELL_3MV_MUL(tmpVec, gten, norm);
256
        len = ELL_3V_LEN(tmpVec);
257
        fprintf(stderr, "%s: should be small: %30.15f\n", me, (double)len);
258
        ell_3v_perp_d(gp1, norm);
259
        ELL_3MV_MUL(tmpVec, gten, gp1);
260
        len = ELL_3V_LEN(tmpVec);
261
        fprintf(stderr, "%s: should be bigger: %30.15f\n", me, (double)len);
262
        ELL_3V_CROSS(gp2, gp1, norm);
263
        ELL_3MV_MUL(tmpVec, gten, gp2);
264
        len = ELL_3V_LEN(tmpVec);
265
        fprintf(stderr, "%s: should (also) be bigger: %30.15f\n",
266
                me, (double)len);
267
      }
268
    } else {
269
      ELL_3M_ZERO_SET(gten);
270
    }
271
  }
272
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclGeomTensTen)) {
273
    pvl->directAnswer[gageSclGeomTensTen][0] = 1.0;
274
    TEN_M2T(pvl->directAnswer[gageSclGeomTensTen],
275
            pvl->directAnswer[gageSclGeomTens]);
276
    TEN_T_SCALE(pvl->directAnswer[gageSclGeomTensTen], -1,
277
                pvl->directAnswer[gageSclGeomTensTen]);
278
  }
279
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query,  gageSclTotalCurv)) {
280
    curv = pvl->directAnswer[gageSclTotalCurv][0] = ELL_3M_FROB(gten);
281
  }
282
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query,  gageSclShapeTrace)) {
283
    pvl->directAnswer[gageSclShapeTrace][0] = (curv
284
                                               ? ELL_3M_TRACE(gten)/curv
285
                                               : 0);
286
  }
287

1789650
  if ( (GAGE_QUERY_ITEM_TEST(pvl->query,  gageSclK1)) ||
288
894825
       (GAGE_QUERY_ITEM_TEST(pvl->query,  gageSclK2)) ){
289
    double T, N, D;
290
    T = ELL_3M_TRACE(gten);
291
    N = curv;
292
    D = 2*N*N - T*T;
293
    /*
294
      if (D < -0.0000001) {
295
      fprintf(stderr, "%s: %g %g\n", me, T, N);
296
      fprintf(stderr, "%s: !!! D curv determinant % 22.10f < 0.0\n", me, D);
297
      fprintf(stderr, "%s: gten: \n", me);
298
      ell_3m_print_d(stderr, gten);
299
      }
300
    */
301
    D = AIR_MAX(D, 0);
302
    D = sqrt(D);
303
    k1[0] = 0.5*(T + D);
304
    k2[0] = 0.5*(T - D);
305
  }
306
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query,  gageSclMeanCurv)) {
307
    pvl->directAnswer[gageSclMeanCurv][0] = (*k1 + *k2)/2;
308
  }
309
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query,  gageSclGaussCurv)) {
310
    pvl->directAnswer[gageSclGaussCurv][0] = (*k1)*(*k2);
311
  }
312
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query,  gageSclShapeIndex)) {
313
    pvl->directAnswer[gageSclShapeIndex][0] =
314
      -(2/AIR_PI)*atan2(*k1 + *k2, *k1 - *k2);
315
  }
316
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclCurvDir1)) {
317
    /* HEY: this only works when K1, K2, 0 are all well mutually distinct,
318
       since these are the eigenvalues of the geometry tensor, and this
319
       code assumes that the eigenspaces are all one-dimensional */
320
    ELL_3M_COPY(tmpMat, gten);
321
    ELL_3M_DIAG_SET(tmpMat, gten[0] - *k1, gten[4]- *k1, gten[8] - *k1);
322
    ell_3m_1d_nullspace_d(tmpVec, tmpMat);
323
    ELL_3V_COPY(pvl->directAnswer[gageSclCurvDir1], tmpVec);
324
  }
325
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclCurvDir2)) {
326
    /* HEY: this only works when K1, K2, 0 are all well mutually distinct,
327
       since these are the eigenvalues of the geometry tensor, and this
328
       code assumes that the eigenspaces are all one-dimensional */
329
    ELL_3M_COPY(tmpMat, gten);
330
    ELL_3M_DIAG_SET(tmpMat, gten[0] - *k2, gten[4] - *k2, gten[8] - *k2);
331
    ell_3m_1d_nullspace_d(tmpVec, tmpMat);
332
    ELL_3V_COPY(pvl->directAnswer[gageSclCurvDir2], tmpVec);
333
  }
334
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclFlowlineCurv)) {
335
    if (gmag >= ctx->parm.gradMagCurvMin) {
336
      /* because of the gageSclGeomTens prerequisite, sHess, nPerp, and
337
         nProj are all already set */
338
      /* ncTen = nPerp * sHess * nProj */
339
      ELL_3M_MUL(tmpMat, sHess, nProj);
340
      ELL_3M_MUL(ncTen, nPerp, tmpMat);
341
    } else {
342
      ELL_3M_ZERO_SET(ncTen);
343
    }
344
    /* there used to be a wrong extra sqrt() here */
345
    pvl->directAnswer[gageSclFlowlineCurv][0] = ELL_3M_FROB(ncTen);
346
  }
347
894825
  if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclMedian)) {
348
    /* this item is currently a complete oddball in that it does not
349
       benefit from anything done in the "filter" stage, which is in
350
       fact a waste of time if the query consists only  of this item */
351
    fd = 2*ctx->radius;
352
    if (fd > FD_MEDIAN_MAX) {
353
      fprintf(stderr, "%s: PANIC: current filter diameter = %d "
354
              "> FD_MEDIAN_MAX = %d\n", me, fd, FD_MEDIAN_MAX);
355
      exit(1);
356
    }
357
    fw = ctx->fw + fd*3*gageKernel00;
358
    /* HEY: this needs some optimization help */
359
    wghtSum = 0;
360
    nidx = 0;
361
    for (xi=0; xi<fd; xi++) {
362
      for (yi=0; yi<fd; yi++) {
363
        for (zi=0; zi<fd; zi++) {
364
          iv3wght[0 + 2*nidx] = pvl->iv3[nidx];
365
          iv3wght[1 + 2*nidx] = fw[xi + 0*fd]*fw[yi + 1*fd]*fw[zi + 2*fd];
366
          wghtSum += iv3wght[1 + 2*nidx];
367
          nidx++;
368
        }
369
      }
370
    }
371
    qsort(iv3wght, fd*fd*fd, 2*sizeof(double), nrrdValCompare[nrrdTypeDouble]);
372
    wght = 0;
373
    for (nidx=0; nidx<fd*fd*fd; nidx++) {
374
      wght += iv3wght[1 + 2*nidx];
375
      if (wght > wghtSum/2) {
376
        break;
377
      }
378
    }
379
    pvl->directAnswer[gageSclMedian][0] = iv3wght[0 + 2*nidx];
380
  }
381
  return;
382
894825
}
383
384
#undef TEN_M2T
385
#undef TEN_T_SCALE