GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/ten/qseg.c Lines: 0 83 0.0 %
Date: 2017-05-26 Branches: 0 38 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
25
#include "ten.h"
26
#include "privateTen.h"
27
28
29
#define MAX_KMEANS_ITERATIONS 50
30
31
32
33
34
/* Calculate the Q-ball profile from DWIs */
35
void
36
_tenQball(const double b, const int gradcount, const double svals[],
37
          const double grads[], double qvals[] ) {
38
  /* Not an optimal Q-ball implementation! (Taken from submission to
39
     MICCAI 2006) Should be solved analytically in the future,
40
     implemented from recent papers. */
41
  int i,j;
42
  double d, dist, weight, min, max;
43
44
  AIR_UNUSED(b);
45
  min = max = svals[1] / svals[0];
46
  for( i = 0; i < gradcount; i++ ) {
47
    d = svals[i+1] / svals[0];
48
    if( d > max )
49
      max = d;
50
    else if( d < min )
51
      min = d;
52
  }
53
54
  for( i = 0; i < gradcount; i++ ) {
55
    qvals[i] = 0;
56
    for( j = 0; j < gradcount; j++ ) {
57
      d = AIR_AFFINE( min, svals[j+1] / svals[0], max, 0,1 );
58
      dist = ELL_3V_DOT(grads + 3*i, grads + 3*j);
59
      dist = AIR_ABS(dist);
60
      weight = cos( 0.5 * AIR_PI * dist );
61
      qvals[i] += d * weight*weight*weight*weight;
62
    }
63
  }
64
  return;
65
}
66
67
/* Segments DWIs into 2 segments based on Q-ball profiles */
68
void
69
_tenSegsamp2(const int gradcount, const double qvals[],
70
             const double grads[], const double qpoints[],
71
             unsigned int seg[], double dists[]) {
72
  const int segcount = 2;
73
  int i, changed=AIR_TRUE;
74
  double centroids[ 3*2 ]; /* 3*segcount */
75
76
  AIR_UNUSED(grads);
77
  _tenInitcent2(gradcount, qvals, qpoints, centroids);
78
79
  for( i = 0; i < MAX_KMEANS_ITERATIONS && changed; i++ ) {
80
    _tenCalcdists(segcount, centroids, gradcount, qpoints, dists);
81
    changed = _tenCalccent2(gradcount, qpoints, dists, centroids, seg);
82
83
    /*
84
      printf( "Seg[%d]\t= { ",i );
85
      for( j = 0; j < gradcount; j++ )
86
      printf( "%d ", seg[j] );
87
      printf( changed ? "}\n" : "} Convergence!\n" );
88
    */
89
90
  }
91
}
92
93
/* Gives an inital choice of 2 centroids */
94
void
95
_tenInitcent2(const int gradcount, const double qvals[],
96
              const double qpoints[], double centroids[6]) {
97
  int i, maxidx;
98
  double max, dist;
99
100
  /* Find largest peak in Q-ball */
101
  maxidx = 0;
102
  for( i = 0; i < gradcount; i++ )
103
    if( qvals[maxidx] < qvals[i] )
104
      maxidx = i;
105
106
  ELL_3V_COPY( centroids, qpoints +3*maxidx );
107
  /*
108
    printf("init: max=%d cent0=[%f %f %f]\n", maxidx,
109
    centroids[0], centroids[1], centroids[2]);
110
  */
111
112
  /* Find peak/axis from Q-ball furthest away from first peak */
113
  max = 0;
114
  for( i = 0; i < gradcount; i++ ) {
115
    dist = _tenPldist(qpoints +3*i, centroids);
116
    if (dist > max) {
117
      maxidx = i;
118
      max = dist;
119
    }
120
  }
121
122
  ELL_3V_COPY( centroids+3, qpoints +3*maxidx );
123
  /*
124
    printf( "\ninit: max=%d cent1=[%f %f %f]\n", maxidx,
125
    centroids[3], centroids[4], centroids[5]);
126
  */
127
}
128
129
/* Calculates 2 new centroids (and a new segmentation) from distances
130
   between Q-balls and centroids, returns true if segmentation changed
131
*/
132
int
133
_tenCalccent2(const int gradcount, const double qpoints[],
134
              const double dists[], double centroid[6], unsigned int seg[]) {
135
#if 0
136
  /* HEY: Attempt to implement better line-adding by adding
137
     outerproducts of points and estimating major eigenvector
138
     afterwards */
139
  int i,changed=AIR_FALSE;
140
  double sum0[9],sum1[9],mat[9], eval[3],evec[9];
141
142
  ELL_3M_ZERO_SET( sum0 );
143
  ELL_3M_ZERO_SET( sum1 );
144
  for( i = 0; i < gradcount; i++ ) {
145
    if( dists[i] < dists[gradcount+i] ) {
146
      ELL_3MV_OUTER( mat, qpoints +3*i, qpoints +3*i );
147
      ELL_3M_ADD2( sum0, sum0, mat );
148
      changed = changed || (seg[i] != 0);
149
      seg[i] = 0;
150
    } else {
151
      ELL_3MV_OUTER( mat, qpoints +3*i +gradcount, qpoints +3*i +gradcount );
152
      ELL_3M_ADD2( sum1, sum1, mat );
153
      changed = changed || (seg[i] != 1);
154
      seg[i] = 1;
155
    }
156
  }
157
158
  ell_3m_eigensolve_d( eval, evec, sum0, 0 );
159
  ELL_3V_COPY( centroid, evec + 3*ELL_MAX3_IDX( eval[0], eval[1], eval[2] ) );
160
  /* ELL_3V_SCALE( centroid, ELL_3V_LEN( centroid ), centroid ); */
161
162
163
  ell_3m_eigensolve_d( eval, evec, sum1, 0 );
164
  ELL_3V_COPY( centroid +3, evec + 3*ELL_MAX3_IDX( eval[0], eval[1], eval[2] ) );
165
  /* ELL_3V_SCALE( centroid +3, ELL_3V_LEN( centroid ), centroid +3); Normalize */
166
167
  return changed;
168
#endif
169
170
  int i, sign, seg0count=0, seg1count=0, changed=AIR_FALSE;
171
  double oldcentroid[6], diff[3], sum[3];
172
173
  memcpy( oldcentroid, centroid, 6 * sizeof( double ));
174
175
  for( i = 0; i < gradcount; i++ ) {
176
    if( dists[ 0*gradcount +i] < dists[1*gradcount +i] ) {
177
      /* Try to resolve sign so that centroid do not end up as all 0 */
178
      /* Choose signs so that the point lies "on the same side" as */
179
      /* the previous centroid. */
180
      diff[0] = oldcentroid[0] - qpoints[3*i +0];
181
      diff[1] = oldcentroid[1] - qpoints[3*i +1];
182
      diff[2] = oldcentroid[2] - qpoints[3*i +2];
183
      sum[0] = oldcentroid[0] + qpoints[3*i +0];
184
      sum[1] = oldcentroid[1] + qpoints[3*i +1];
185
      sum[2] = oldcentroid[2] + qpoints[3*i +2];
186
      sign = (diff[0]*diff[0] + diff[1]*diff[1] + diff[2]*diff[2]) <
187
        (sum[0]*sum[0] + sum[1]*sum[1] + sum[2]*sum[2]) ? -1 : +1;
188
189
      changed = changed || (seg[i] != 0);
190
191
      seg[i] = 0;
192
      centroid[0] += sign * qpoints[3*i +0];
193
      centroid[1] += sign * qpoints[3*i +1];
194
      centroid[2] += sign * qpoints[3*i +2];
195
      seg0count++;
196
    } else {
197
      diff[0] = oldcentroid[3+0] - qpoints[3*i +0];
198
      diff[1] = oldcentroid[3+1] - qpoints[3*i +1];
199
      diff[2] = oldcentroid[3+2] - qpoints[3*i +2];
200
      sum[0] = oldcentroid[3+0] + qpoints[3*i +0];
201
      sum[1] = oldcentroid[3+1] + qpoints[3*i +1];
202
      sum[2] = oldcentroid[3+2] + qpoints[3*i +2];
203
      sign = (diff[0]*diff[0] + diff[1]*diff[1] + diff[2]*diff[2]) <
204
        (sum[0]*sum[0] + sum[1]*sum[1] + sum[2]*sum[2]) ? -1 : +1;
205
206
      changed = changed || (seg[i] != 1);
207
208
      seg[i] = 1;
209
      centroid[3+0] += sign * qpoints[3*i +0];
210
      centroid[3+1] += sign * qpoints[3*i +1];
211
      centroid[3+2] += sign * qpoints[3*i +2];
212
      seg1count++;
213
    }
214
  }
215
  centroid[0] /= seg0count;
216
  centroid[1] /= seg0count;
217
  centroid[2] /= seg0count;
218
  centroid[3+0] /= seg1count;
219
  centroid[3+1] /= seg1count;
220
  centroid[3+2] /= seg1count;
221
222
  /* printf("cent = %f %f %f %f %f %f\n", centroid[0],centroid[1],centroid[2],centroid[3],centroid[4],centroid[5] ); */
223
224
  /*
225
    Should give error if any segment contains less than 6 elements,
226
    i.e. if( seg0count < 6 || seg1count < 6 ), since that would
227
    imply that a tensor cannot be computed for that segment.
228
  */
229
230
  return changed;
231
}
232
233
/* Converts Q-values and gradients to points on the Q-ball surface */
234
void
235
_tenQvals2points(const int gradcount, const double qvals[],
236
                 const double grads[], double qpoints[] ) {
237
  int i;
238
  memcpy( qpoints, grads, 3 * gradcount * sizeof( double ) );
239
  for( i = 0; i < gradcount; i++ ) {
240
    qpoints[3*i +0] *= qvals[i];
241
    qpoints[3*i +1] *= qvals[i];
242
    qpoints[3*i +2] *= qvals[i];
243
  }
244
}
245
246
/* Calculates the shortest distances from each centroid/axis to each
247
   Q-ball point */
248
void
249
_tenCalcdists(const int centcount, const double centroid[],
250
              const int gradcount, const double qpoints[], double dists[] ) {
251
  int i,j;
252
  for( j = 0; j < centcount; j++ )
253
    for( i = 0; i < gradcount; i++ )
254
      dists[j*gradcount +i] = _tenPldist(&qpoints[3*i], &centroid[3*j]);
255
256
  /*
257
    printf("dists = ");
258
    for( i = 0; i < 2*gradcount; i++ )
259
    printf( "%f ", dists[i] );
260
    printf("\n");
261
  */
262
}
263
264
/* Estimates the shortest distance from a point to a line going
265
   through the origin */
266
double
267
_tenPldist( const double point[], const double line[] ) {
268
269
  double cross[3];
270
  double negpoint[3];
271
272
  negpoint[0] = -point[0];
273
  negpoint[1] = -point[1];
274
  negpoint[2] = -point[2];
275
276
  ELL_3V_CROSS( cross, line, negpoint );
277
278
  return ELL_3V_LEN( cross ) / ELL_3V_LEN( line );
279
}
280
281
/* Converts a segmentation into a set of 0-1 weights */
282
void
283
_tenSeg2weights(const int gradcount, const int seg[],
284
                const int segcount, double weights[] ) {
285
  int i,j;
286
  for( j = 0; j < segcount; j++ ) {
287
    for( i = 0; i < gradcount; i++ ) {
288
      weights[j*gradcount +i] = (seg[i] == j) ? 1 : 0;
289
    }
290
  }
291
  return;
292
}
293