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 |
|
|
/* |
28 |
|
|
static int debugging = 0; |
29 |
|
|
static int debugii; |
30 |
|
|
*/ |
31 |
|
|
|
32 |
|
|
static airArray *debugReconErrArr = NULL; |
33 |
|
|
static double *debugReconErr = NULL; |
34 |
|
|
static char *debugReconErrName = NULL; |
35 |
|
|
|
36 |
|
|
/* |
37 |
|
|
** learned: |
38 |
|
|
** |
39 |
|
|
** -- debug high/discontinuous errors at the low sigmas: was because |
40 |
|
|
** cut-off was insufficient to prevent some discontinuous change in |
41 |
|
|
** kernel values: increased minimum support in the kernel itself, and |
42 |
|
|
** now using larger cut-offs. |
43 |
|
|
** |
44 |
|
|
** -- also, separately from this problem, you can have minima in the |
45 |
|
|
** inf error (in imgMeasr) *not* at sample points, apparently simply |
46 |
|
|
** because of how the hermite interpolation works (but this is |
47 |
|
|
** troubling) |
48 |
|
|
** |
49 |
|
|
** -- do now have a different minimization scheme for allMeasr=Linf, |
50 |
|
|
** but this may still be a work in progress. Recognizing that this is |
51 |
|
|
** essentially seeking to find a uniform re-parameterization of |
52 |
|
|
** something with a hidden non-uniform parameterization, we could |
53 |
|
|
** probably implement a simple global warping of control points within |
54 |
|
|
** the implied non-uniform domain. |
55 |
|
|
*/ |
56 |
|
|
|
57 |
|
|
/* this limits how big the kernel can get with a single evaluation |
58 |
|
|
of nrrdKernelDiscreteGaussian; there are some numerical issues |
59 |
|
|
with large kernels that need ironing out */ |
60 |
|
|
#define GOOD_SIGMA_MAX 5 |
61 |
|
|
|
62 |
|
|
#define N -1 |
63 |
|
|
|
64 |
|
|
/* |
65 |
|
|
** NOTE: The idea for this table originated with Raul San Jose Estepar; |
66 |
|
|
** GLK recomputed it optimizing for 3D recon, but |
67 |
|
|
** NOTE: there are probably still be bugs in this; look at the |
68 |
|
|
** "HEY: bug?" notes below, the same problem occurs elsewhere |
69 |
|
|
** |
70 |
|
|
** Basic indexing idea: [sigma max][total # samples][which sample] |
71 |
|
|
** |
72 |
|
|
** "sigma max" can't be 0; smallest value is 1 |
73 |
|
|
** ==> index with (sigma max)-1 |
74 |
|
|
** biggest value is GAGE_OPTIMSIG_SIGMA_MAX, |
75 |
|
|
** ==> biggest index is GAGE_OPTIMSIG_SIGMA_MAX-1 |
76 |
|
|
** ==> allocate for GAGE_OPTIMSIG_SIGMA_MAX |
77 |
|
|
** |
78 |
|
|
** "total # samples" can't be 0, or 1, smallest value is 2 |
79 |
|
|
** ==> index with (total # samples)-2 |
80 |
|
|
** biggest value is GAGE_OPTIMSIG_SAMPLES_MAXNUM |
81 |
|
|
** ==> biggest index is GAGE_OPTIMSIG_SAMPLES_MAXNUM-2 |
82 |
|
|
** ==> allocate for GAGE_OPTIMSIG_SAMPLES_MAXNUM-1 |
83 |
|
|
** |
84 |
|
|
** "which sample" ranges from 0 to GAGE_OPTIMSIG_SAMPLES_MAXNUM-1 |
85 |
|
|
** ==> allocate for GAGE_OPTIMSIG_SAMPLES_MAXNUM |
86 |
|
|
*/ |
87 |
|
|
static double |
88 |
|
|
_optimSigTable[GAGE_OPTIMSIG_SIGMA_MAX][GAGE_OPTIMSIG_SAMPLES_MAXNUM-1][GAGE_OPTIMSIG_SAMPLES_MAXNUM] = { |
89 |
|
|
{ |
90 |
|
|
{0,1,N,N,N,N,N,N,N,N,N}, |
91 |
|
|
{0,0.5279398,1,N,N,N,N,N,N,N,N}, |
92 |
|
|
{0,0.30728838,0.59967405,1,N,N,N,N,N,N,N}, |
93 |
|
|
{0,0.25022203,0.47050092,0.69525677,1,N,N,N,N,N,N}, |
94 |
|
|
{0,0.17127343,0.39234546,0.56356072,0.75660759,1,N,N,N,N,N}, |
95 |
|
|
{0,0.16795139,0.37100673,0.51324213,0.65655005,0.81952846,1,N,N,N,N}, |
96 |
|
|
{0,0.1662873,0.34969759,0.46556041,0.55324608,0.68717259,0.83465695,1,N,N,N}, |
97 |
|
|
{0,0.12720504,0.22565289,0.28316727,0.44209728,0.58615023,0.75034028,0.87391609,1,N,N}, |
98 |
|
|
{0,0.12836272 /* HEY: bug? should be < 0.12720504 */,0.22926401,0.27715567,0.43546647,0.56471503,0.69411868,0.80830419,0.89314467,1,N}, |
99 |
|
|
{0,0.13169055 /* HEY: bug? should be < 0.12720504 */,0.23498112,0.26570156,0.42672107,0.54272485,0.62969965,0.73375762,0.76996493,0.89293921,1} |
100 |
|
|
}, { |
101 |
|
|
{0,2,N,N,N,N,N,N,N,N,N}, |
102 |
|
|
{0,0.75118494,2,N,N,N,N,N,N,N,N}, |
103 |
|
|
{0,0.55478472,1.1535828,2,N,N,N,N,N,N,N}, |
104 |
|
|
{0,0.49007216,0.8412028,1.308665,2,N,N,N,N,N,N}, |
105 |
|
|
{0,0.29460263,0.57445061,0.93797231,1.368475,2,N,N,N,N,N}, |
106 |
|
|
{0,0.2506085,0.49080029,0.73882496,1.069332,1.4497081,2,N,N,N,N}, |
107 |
|
|
{0,0.18255657,0.42056954,0.62766695,0.87999368,1.1692151,1.5175625,2,N,N,N}, |
108 |
|
|
{0,0.17582123,0.40522173,0.58696139,0.79624867,1.0485514,1.2950466,1.5977446,2,N,N}, |
109 |
|
|
{0,0.17304537,0.39376548,0.56427032,0.75127059,0.96672511,1.187861,1.4141362,1.6921321,2,N}, |
110 |
|
|
{0,0.16970521,0.38116929,0.53575242,0.69498152,0.88430929,1.0844854,1.2899524,1.5211773,1.7645421,2} |
111 |
|
|
}, { |
112 |
|
|
{0,3,N,N,N,N,N,N,N,N,N}, |
113 |
|
|
{0,0.92324787,3,N,N,N,N,N,N,N,N}, |
114 |
|
|
{0,0.59671402,1.3871731,3,N,N,N,N,N,N,N}, |
115 |
|
|
{0,0.53303385,1.0274624,1.6725048,3,N,N,N,N,N,N}, |
116 |
|
|
{0,0.47298154,0.79659319,1.2379739,1.8434249,3,N,N,N,N,N}, |
117 |
|
|
{0,0.29337707,0.56664073,0.94871783,1.3666322,1.949043,3,N,N,N,N}, |
118 |
|
|
{0,0.25583801,0.52919179,0.78387552,1.1250161,1.516176,2.0632432,3,N,N,N}, |
119 |
|
|
{0,0.25013804,0.48255014,0.72428173,1.0308567,1.3638159,1.7629964,2.2885511,3,N,N}, |
120 |
|
|
{0,0.25038671,0.46448985,0.67336935,0.94502586,1.2324173,1.5780864,1.9883285,2.5002999,3,N}, |
121 |
|
|
{0,0.25034565,0.44725224,0.63590652,0.8669008,1.1130947,1.3942779,1.7180597,2.1408446,2.5466051,3} |
122 |
|
|
}, { |
123 |
|
|
{0,4,N,N,N,N,N,N,N,N,N}, |
124 |
|
|
{0,1.0342592,4,N,N,N,N,N,N,N,N}, |
125 |
|
|
{0,0.6341188,1.5414433,4,N,N,N,N,N,N,N}, |
126 |
|
|
{0,0.5523203,1.1400089,1.9595566,4,N,N,N,N,N,N}, |
127 |
|
|
{0,0.51082283,0.91567439,1.4275582,2.2504199,4,N,N,N,N,N}, |
128 |
|
|
{0,0.46390373,0.76406777,1.1620381,1.6579833,2.470386,4,N,N,N,N}, |
129 |
|
|
{0,0.29957226,0.58226484,0.90447241,1.318499,1.8011117,2.5972142,4,N,N,N}, |
130 |
|
|
{0,0.29072434,0.5657317,0.8687849,1.2413157,1.7351674,2.2752147,3.1038468,4,N,N}, |
131 |
|
|
{0,0.25000414,0.5027808,0.75375289,1.0744231,1.4267329,1.8665372,2.4665236,3.2203004,4,N}, |
132 |
|
|
{0,0.19010291,0.44269502,0.66081244,0.95829803,1.2627038,1.6005131,2.0043969,2.6440792,3.2979164,4} |
133 |
|
|
}, { |
134 |
|
|
{0,5,N,N,N,N,N,N,N,N,N}, |
135 |
|
|
{0,1.1176668,5,N,N,N,N,N,N,N,N}, |
136 |
|
|
{0,0.66791451,1.6688319,5,N,N,N,N,N,N,N}, |
137 |
|
|
{0,0.56513244,1.2151262,2.2046661,5,N,N,N,N,N,N}, |
138 |
|
|
{0,0.51955444,0.96157616,1.5293243,2.5639,5,N,N,N,N,N}, |
139 |
|
|
{0,0.50639188,0.83235806,1.2596023,1.8475783,2.8751452,5,N,N,N,N}, |
140 |
|
|
{0,0.30821687,0.60048282,1.0057166,1.4351804,2.0372179,3.0747592,5,N,N,N}, |
141 |
|
|
{0,0.28437388,0.560866,0.92278755,1.3049414,1.7620444,2.4607313,3.5198457,5,N,N}, |
142 |
|
|
{0,0.26883101,0.53947717,0.84076571,1.1986721,1.6077875,2.165575,2.9591467,3.931181,5,N}, |
143 |
|
|
{0,0.25029126,0.50162876,0.75587535,1.0861237,1.4452776,1.8865763,2.5002809,3.2476835,4.0337272,5} |
144 |
|
|
}, { |
145 |
|
|
{0,6,N,N,N,N,N,N,N,N,N}, |
146 |
|
|
{0,1.185726,6,N,N,N,N,N,N,N,N}, |
147 |
|
|
{0,0.69637311,1.7772807,6,N,N,N,N,N,N,N}, |
148 |
|
|
{0,0.57470578,1.2709187,2.4227901,6,N,N,N,N,N,N}, |
149 |
|
|
{0,0.52996641,1.0128419,1.632214,2.8718762,6,N,N,N,N,N}, |
150 |
|
|
{0,0.50426048,0.87729794,1.3428378,2.0053113,3.2981832,6,N,N,N,N}, |
151 |
|
|
{0,0.46658435,0.76617205,1.1726109,1.6950468,2.5514688,4.1463666,6,N,N,N}, |
152 |
|
|
{0,0.50030917,0.78596908,1.1486269,1.5887094,2.2150676,3.2805684,4.4828262,6,N,N}, |
153 |
|
|
{0,0.27919531,0.56878412,0.88591647,1.2631332,1.7201432,2.3851209,3.392889,4.6255312,6,N}, |
154 |
|
|
{0,0.25088972,0.50369233,0.78494686,1.1030188,1.482311,1.9812444,2.6906328,3.734978,4.7532525,6} |
155 |
|
|
}, { |
156 |
|
|
{0,7,N,N,N,N,N,N,N,N,N}, |
157 |
|
|
{0,1.2437892,7,N,N,N,N,N,N,N,N}, |
158 |
|
|
{0,0.72099203,1.8771845,7,N,N,N,N,N,N,N}, |
159 |
|
|
{0,0.58251196,1.3139123,2.6157444,7,N,N,N,N,N,N}, |
160 |
|
|
{0,0.5371021,1.0473768,1.7166929,3.1448426,7,N,N,N,N,N}, |
161 |
|
|
{0,0.51312029,0.92989367,1.4221185,2.2125893,3.6739931,7,N,N,N,N}, |
162 |
|
|
{0,0.50083971,0.84841007,1.2561073,1.8532455,2.8668625,4.7535434,7,N,N,N}, |
163 |
|
|
{0,0.3375614,0.63945627,1.0301709,1.4884938,2.073761,3.1614799,5.0744987,7,N,N}, |
164 |
|
|
{0,0.29428458,0.58668923,0.93714356,1.3736334,1.8300356,2.6405344,3.9042048,5.3097196,7,N}, |
165 |
|
|
{0,0.25234449,0.52068585,0.79422623,1.1273863,1.5991755,2.1453006,2.8984315,4.1899557,5.4597921,7} |
166 |
|
|
}, { |
167 |
|
|
{0,8,N,N,N,N,N,N,N,N,N}, |
168 |
|
|
{0,1.2942501,8,N,N,N,N,N,N,N,N}, |
169 |
|
|
{0,0.74332041,1.9693407,8,N,N,N,N,N,N,N}, |
170 |
|
|
{0,0.58823597,1.3483386,2.7880962,8,N,N,N,N,N,N}, |
171 |
|
|
{0,0.56661958,1.2263036,1.9593971,3.6037345,8,N,N,N,N,N}, |
172 |
|
|
{0,0.52106231,0.97026396,1.486012,2.3670862,4.1632919,8,N,N,N,N}, |
173 |
|
|
{0,0.50727636,0.86810225,1.3293955,2.0115428,3.1358411,5.3943086,8,N,N,N}, |
174 |
|
|
{0,0.47202346,0.77812189,1.1608884,1.6648751,2.4694417,3.9094045,5.7665443,8,N,N}, |
175 |
|
|
{0,0.37446901,0.66116196,1.038642,1.4625595,2.0528309,2.9814169,4.4429126,5.9815373,8,N}, |
176 |
|
|
{0,0.26310974,0.54373014,0.84282249,1.2090484,1.6551158,2.3275802,3.3196113,4.7216973,6.1578932,8} |
177 |
|
|
}, { |
178 |
|
|
{0,9,N,N,N,N,N,N,N,N,N}, |
179 |
|
|
{0,1.3413963,9,N,N,N,N,N,N,N,N}, |
180 |
|
|
{0,0.76222414,2.0542119,9,N,N,N,N,N,N,N}, |
181 |
|
|
{0,0.59559792,1.3777219,2.946173,9,N,N,N,N,N,N}, |
182 |
|
|
{0,0.56240517,1.1527119,1.9145473,3.6841569,9,N,N,N,N,N}, |
183 |
|
|
{0,0.52387071,0.98832464,1.5376476,2.5417714,4.4669261,9,N,N,N,N}, |
184 |
|
|
{0,0.50359035,0.87327009,1.3558764,2.0646384,3.3180211,5.9420524,9,N,N,N}, |
185 |
|
|
{0,0.50140077,0.83020425,1.256588,1.7709454,2.7100441,4.4434023,6.3934889,9,N,N}, |
186 |
|
|
{0,0.36521655,0.65757704,1.0627806,1.5081434,2.1497617,3.1920822,4.870122,6.6418982,9,N}, |
187 |
|
|
{0,0.31160679,0.59032226,0.94745982,1.3620865,1.8115216,2.6007423,3.8324564,5.2064519,6.8468728,9} |
188 |
|
|
}, { |
189 |
|
|
{0,10,N,N,N,N,N,N,N,N,N}, |
190 |
|
|
{0,1.3838946,10,N,N,N,N,N,N,N,N}, |
191 |
|
|
{0,0.77946955,2.1342247,10,N,N,N,N,N,N,N}, |
192 |
|
|
{0,0.60070014,1.4040204,3.0944126,10,N,N,N,N,N,N}, |
193 |
|
|
{0,0.55609542,1.1508646,1.9495349,3.9375696,10,N,N,N,N,N}, |
194 |
|
|
{0,0.5350194,1.031119,1.6607633,2.8520992,5.4718146,10,N,N,N,N}, |
195 |
|
|
{0,0.5083549,0.90783268,1.4059756,2.1796026,3.571064,6.5497985,10,N,N,N}, |
196 |
|
|
{0,0.50199872,0.85233968,1.2647815,1.8777326,2.8592849,4.7821364,7.0110598,10,N,N}, |
197 |
|
|
{0,0.46663594,0.75212663,1.1302133,1.6134665,2.3560972,3.6558499,5.3189116,7.2945781,10,N}, |
198 |
|
|
{0,0.3789258,0.64023608,1.0374272,1.4685256,2.0717783,3.0241971,4.2591534,5.6669927,7.5286098,10} |
199 |
|
|
}, { |
200 |
|
|
{0,11,N,N,N,N,N,N,N,N,N}, |
201 |
|
|
{0,1.4234025,11,N,N,N,N,N,N,N,N}, |
202 |
|
|
{0,0.79513794,2.2098076,11,N,N,N,N,N,N,N}, |
203 |
|
|
{0,0.60728961,1.4287171,3.2358651,11,N,N,N,N,N,N}, |
204 |
|
|
{0,0.55890071,1.165283,2.0149148,4.1530919,11,N,N,N,N,N}, |
205 |
|
|
{0,0.55071467,1.0660659,1.7177736,3.0094495,6.0395317,11,N,N,N,N}, |
206 |
|
|
{0,0.5066433,0.89661205,1.4050072,2.2117786,3.7080047,7.0954437,11,N,N,N}, |
207 |
|
|
{0,0.50242329,0.86727452,1.3264461,1.9118301,2.9509099,5.1184769,7.624764,11,N,N}, |
208 |
|
|
{0,0.47785854,0.78873962,1.1769236,1.6880652,2.4978926,4.0288033,5.7288432,7.9420485,11,N}, |
209 |
|
|
{0,0.50532979,0.79486167,1.1706896,1.6148115,2.2648265,3.3499777,4.5595574,6.116312,8.2049971,11} |
210 |
|
|
} |
211 |
|
|
}; |
212 |
|
|
|
213 |
|
|
/* |
214 |
|
|
** this is only for retreiving part of the table above |
215 |
|
|
*/ |
216 |
|
|
int |
217 |
|
|
gageOptimSigSet(double *scale, unsigned int num, unsigned int sigmaMax) { |
218 |
|
|
static const char me[]="gageOptimSigSet"; |
219 |
|
|
unsigned int si; |
220 |
|
|
|
221 |
✗✓ |
4 |
if (!scale) { |
222 |
|
|
biffAddf(GAGE, "%s: got NULL pointer", me); |
223 |
|
|
return 1; |
224 |
|
|
} |
225 |
✗✓ |
2 |
if (!AIR_IN_CL(2, num, GAGE_OPTIMSIG_SAMPLES_MAXNUM)) { |
226 |
|
|
biffAddf(GAGE, |
227 |
|
|
"%s: requested # sigma samples %u not in known range [2,%u]", |
228 |
|
|
me, num, GAGE_OPTIMSIG_SAMPLES_MAXNUM); |
229 |
|
|
return 1; |
230 |
|
|
} |
231 |
✗✓ |
2 |
if (!AIR_IN_CL(1, sigmaMax, GAGE_OPTIMSIG_SIGMA_MAX)) { |
232 |
|
|
biffAddf(GAGE, "%s: requested sigma max %u not in known range [1,%u]", |
233 |
|
|
me, sigmaMax, GAGE_OPTIMSIG_SIGMA_MAX); |
234 |
|
|
return 1; |
235 |
|
|
} |
236 |
|
|
|
237 |
✓✓ |
20 |
for (si=0; si<num; si++) { |
238 |
|
8 |
scale[si] = _optimSigTable[sigmaMax-1][num-2][si]; |
239 |
|
|
} |
240 |
|
2 |
return 0; |
241 |
|
2 |
} |
242 |
|
|
|
243 |
|
|
/* ------- from here down is the stuff for computing the table ------ */ |
244 |
|
|
|
245 |
|
|
/* rho is a stand-in for tau - and something that will likely change |
246 |
|
|
based on the findings from using this code; the idea is that it |
247 |
|
|
reflects the needed density of samples for optimal scale-space |
248 |
|
|
reconstruction. In order to be used for the internal workings of |
249 |
|
|
the sigma optimization, its important that the conversion between |
250 |
|
|
sigma and rho be accurately invertible. */ |
251 |
|
|
|
252 |
|
|
/* |
253 |
|
|
** |
254 |
|
|
** This is a decent approximation of tau(sigma), made of a slightly |
255 |
|
|
** scaled version of the taylor expansion of tau(sigma=0) which meets |
256 |
|
|
** up with the large-scale approximation of tau from Lindeberg. |
257 |
|
|
** However, because its so flat at sigma=0, its not really invertible |
258 |
|
|
** there, so its a poor basis for computations that are parameterized |
259 |
|
|
** by rho. Keeping it around for reference. |
260 |
|
|
|
261 |
|
|
static double |
262 |
|
|
_RhoOfSig(double sig) { |
263 |
|
|
double rho; |
264 |
|
|
|
265 |
|
|
if (sig < 1.05189095) { |
266 |
|
|
rho = sig*sig*(0.2775733212544225 + 0.13078298856958057*sig*sig); |
267 |
|
|
} else { |
268 |
|
|
double tee; |
269 |
|
|
tee = sig*sig; |
270 |
|
|
rho = 0.53653222368715360118 + log(tee)/2.0 + log(1.0 - 1.0/(8.0*tee)); |
271 |
|
|
} |
272 |
|
|
return rho; |
273 |
|
|
} |
274 |
|
|
|
275 |
|
|
static double |
276 |
|
|
_SigOfRho(double rho) { |
277 |
|
|
double sig; |
278 |
|
|
|
279 |
|
|
if (rho < 0.46724360022171363) { |
280 |
|
|
sig = 0.00033978812426865065 * |
281 |
|
|
sqrt(-9.191366355042886e6 + 245.3752559286824 * |
282 |
|
|
sqrt(1.403132301e9 + 9.526961876920057e9*rho)); |
283 |
|
|
} else { |
284 |
|
|
double ee, tee; |
285 |
|
|
ee = exp(2.0*rho); |
286 |
|
|
tee = 0.0063325739776461107152*(27.0*ee + 2*AIR_PI*AIR_PI |
287 |
|
|
+ 3.0*sqrt(81.0*ee*ee |
288 |
|
|
+ 12*ee*AIR_PI*AIR_PI)); |
289 |
|
|
sig = sqrt(tee); |
290 |
|
|
} |
291 |
|
|
return sig; |
292 |
|
|
} |
293 |
|
|
*/ |
294 |
|
|
|
295 |
|
|
static double |
296 |
|
|
_RhoOfSig(double sig) { |
297 |
|
|
|
298 |
|
|
return log(sig + 1); |
299 |
|
|
} |
300 |
|
|
|
301 |
|
|
static double |
302 |
|
|
_SigOfRho(double rho) { |
303 |
|
|
|
304 |
|
|
return exp(rho)-1; |
305 |
|
|
} |
306 |
|
|
|
307 |
|
|
|
308 |
|
|
/* |
309 |
|
|
** allocates context, with error checking |
310 |
|
|
** does use biff |
311 |
|
|
*/ |
312 |
|
|
gageOptimSigContext *gageOptimSigContextNew(unsigned int dim, |
313 |
|
|
unsigned int sampleNumMax, |
314 |
|
|
unsigned int trueImgNum, |
315 |
|
|
double sigmaMin, double sigmaMax, |
316 |
|
|
double cutoff) { |
317 |
|
|
static const char me[]="gageOptimSigContextNew"; |
318 |
|
|
gageOptimSigContext *oscx; |
319 |
|
|
unsigned int support, ii; |
320 |
|
|
double kparm[2]; |
321 |
|
|
|
322 |
|
|
oscx = AIR_CALLOC(1, gageOptimSigContext); |
323 |
|
|
if (!oscx) { |
324 |
|
|
biffAddf(GAGE, "%s: couldn't allocate context", me); |
325 |
|
|
return NULL; |
326 |
|
|
} |
327 |
|
|
if (!AIR_IN_CL(1, dim, 3)) { |
328 |
|
|
biffAddf(GAGE, "%s: dim %u not 1, 2, or 3", me, dim); |
329 |
|
|
return NULL; |
330 |
|
|
} |
331 |
|
|
if (!(sampleNumMax >= 3)) { |
332 |
|
|
biffAddf(GAGE, "%s: sampleNumMax %u not >= 3", me, sampleNumMax); |
333 |
|
|
return NULL; |
334 |
|
|
} |
335 |
|
|
if (!(trueImgNum >= 3)) { |
336 |
|
|
biffAddf(GAGE, "%s: trueImgNum %u not >= 3", me, trueImgNum); |
337 |
|
|
return NULL; |
338 |
|
|
} |
339 |
|
|
if (!(sigmaMin >= 0 && sigmaMax > sigmaMin && cutoff > 0)) { |
340 |
|
|
biffAddf(GAGE, "%s: sigmaMin %g, sigmaMax %g, cutoff %g not valid", me, |
341 |
|
|
sigmaMin, sigmaMax, cutoff); |
342 |
|
|
return NULL; |
343 |
|
|
} |
344 |
|
|
|
345 |
|
|
oscx->dim = dim; |
346 |
|
|
oscx->sampleNumMax = sampleNumMax; |
347 |
|
|
oscx->trueImgNum = trueImgNum; |
348 |
|
|
oscx->sigmaRange[0] = sigmaMin; |
349 |
|
|
oscx->sigmaRange[1] = sigmaMax; |
350 |
|
|
oscx->cutoff = cutoff; |
351 |
|
|
|
352 |
|
|
/* will be set later */ |
353 |
|
|
oscx->kssSpec = NULL; |
354 |
|
|
oscx->sampleNum = 0; |
355 |
|
|
oscx->maxIter = 0; |
356 |
|
|
oscx->imgMeasr = nrrdMeasureUnknown; |
357 |
|
|
oscx->allMeasr = nrrdMeasureUnknown; |
358 |
|
|
oscx->convEps = AIR_NAN; |
359 |
|
|
|
360 |
|
|
/* allocate internal buffers based on arguments */ |
361 |
|
|
kparm[0] = oscx->sigmaRange[1]; |
362 |
|
|
kparm[1] = oscx->cutoff; |
363 |
|
|
support = AIR_ROUNDUP(nrrdKernelDiscreteGaussian->support(kparm)); |
364 |
|
|
oscx->sx = 2*support - 1; |
365 |
|
|
oscx->sy = dim >= 2 ? 2*support - 1 : 1; |
366 |
|
|
oscx->sz = dim >= 3 ? 2*support - 1 : 1; |
367 |
|
|
/* |
368 |
|
|
fprintf(stderr, "%s: max sigma = %g, cutoff %g ==> support=%u, " |
369 |
|
|
"3D vol size=%u x %u x %u\n", me, |
370 |
|
|
sigmaMax, cutoff, support, oscx->sx, oscx->sy, oscx->sz); |
371 |
|
|
*/ |
372 |
|
|
oscx->nerr = nrrdNew(); |
373 |
|
|
oscx->ninterp = nrrdNew(); |
374 |
|
|
oscx->ndiff = nrrdNew(); |
375 |
|
|
if (nrrdMaybeAlloc_va(oscx->nerr, nrrdTypeDouble, 1, |
376 |
|
|
AIR_CAST(size_t, oscx->trueImgNum)) |
377 |
|
|
|| nrrdMaybeAlloc_va(oscx->ninterp, nrrdTypeDouble, 3, |
378 |
|
|
AIR_CAST(size_t, oscx->sx), |
379 |
|
|
AIR_CAST(size_t, oscx->sy), |
380 |
|
|
AIR_CAST(size_t, oscx->sz)) |
381 |
|
|
|| nrrdMaybeAlloc_va(oscx->ndiff, nrrdTypeDouble, 3, |
382 |
|
|
AIR_CAST(size_t, oscx->sx), |
383 |
|
|
AIR_CAST(size_t, oscx->sy), |
384 |
|
|
AIR_CAST(size_t, oscx->sz))) { |
385 |
|
|
biffMovef(GAGE, NRRD, "%s: couldn't allocate buffers", me); |
386 |
|
|
return NULL; |
387 |
|
|
} |
388 |
|
|
nrrdAxisInfoSet_va(oscx->ninterp, nrrdAxisInfoSpacing, |
389 |
|
|
1.0, 1.0, 1.0); |
390 |
|
|
nrrdAxisInfoSet_va(oscx->ndiff, nrrdAxisInfoSpacing, |
391 |
|
|
1.0, 1.0, 1.0); |
392 |
|
|
oscx->rhoRange[0] = _RhoOfSig(oscx->sigmaRange[0]); |
393 |
|
|
oscx->rhoRange[1] = _RhoOfSig(oscx->sigmaRange[1]); |
394 |
|
|
nrrdAxisInfoSet_va(oscx->nerr, nrrdAxisInfoMin, |
395 |
|
|
oscx->rhoRange[0]); |
396 |
|
|
nrrdAxisInfoSet_va(oscx->nerr, nrrdAxisInfoMax, |
397 |
|
|
oscx->rhoRange[1]); |
398 |
|
|
|
399 |
|
|
fprintf(stderr, "!%s: sigma [%g,%g] -> rho [%g,%g]\n", me, |
400 |
|
|
oscx->sigmaRange[0], oscx->sigmaRange[1], |
401 |
|
|
oscx->rhoRange[0], oscx->rhoRange[1]); |
402 |
|
|
fprintf(stderr, "!%s: rho %g -- %g\n", me, |
403 |
|
|
oscx->rhoRange[0], oscx->rhoRange[1]); |
404 |
|
|
for (ii=0; ii<oscx->trueImgNum; ii++) { |
405 |
|
|
double rr, ss, rc, eps=1e-13; |
406 |
|
|
rr = AIR_AFFINE(0, ii, oscx->trueImgNum-1, |
407 |
|
|
oscx->rhoRange[0], oscx->rhoRange[1]); |
408 |
|
|
ss = _SigOfRho(rr); |
409 |
|
|
rc = _RhoOfSig(ss); |
410 |
|
|
/* |
411 |
|
|
fprintf(stderr, "!%s: (%u) rho %.17g -> sig %.17g -> rho %.17g (%.17g)\n", |
412 |
|
|
me, ii, rr, ss, rc, AIR_ABS(rr - rc)/(rr + eps/2)); |
413 |
|
|
*/ |
414 |
|
|
if ( AIR_ABS(rr - rc)/(rr + eps) > eps ) { |
415 |
|
|
biffAddf(GAGE, "%s: rho %g -> sig %g -> rho %g has error %g > %g; " |
416 |
|
|
"_SigOfRho() and _RhoOfSig() not invertible", |
417 |
|
|
me, rr, ss, rc, AIR_ABS(rr - rc)/(rr + eps/2), eps); |
418 |
|
|
return NULL; |
419 |
|
|
} |
420 |
|
|
} |
421 |
|
|
|
422 |
|
|
oscx->kloc = AIR_CALLOC(oscx->sx, double); |
423 |
|
|
oscx->kern = AIR_CALLOC(oscx->sx, double); |
424 |
|
|
oscx->ktmp1 = AIR_CALLOC(oscx->sx, double); |
425 |
|
|
oscx->ktmp2 = AIR_CALLOC(oscx->sx, double); |
426 |
|
|
if (!(oscx->kloc && oscx->kern && oscx->ktmp1 && oscx->ktmp2)) { |
427 |
|
|
biffAddf(GAGE, "%s: couldn't allocate kernel buffers", me); |
428 |
|
|
return NULL; |
429 |
|
|
} |
430 |
|
|
for (ii=0; ii<oscx->sx; ii++) { |
431 |
|
|
oscx->kloc[ii] = AIR_CAST(double, ii) - ((oscx->sx + 1)/2 - 1); |
432 |
|
|
} |
433 |
|
|
oscx->kone[0] = 1.0; |
434 |
|
|
|
435 |
|
|
oscx->gctx = NULL; |
436 |
|
|
oscx->pvlBase = NULL; |
437 |
|
|
oscx->pvlSS = AIR_CALLOC(oscx->sampleNumMax, gagePerVolume *); |
438 |
|
|
oscx->nsampleImg = AIR_CALLOC(oscx->sampleNumMax, Nrrd *); |
439 |
|
|
oscx->sampleSigma = AIR_CALLOC(oscx->sampleNumMax, double); |
440 |
|
|
oscx->sampleRho = AIR_CALLOC(oscx->sampleNumMax, double); |
441 |
|
|
oscx->sampleTmp = AIR_CALLOC(oscx->sampleNumMax, double); |
442 |
|
|
oscx->sampleErrMax = AIR_CALLOC(oscx->sampleNumMax, double); |
443 |
|
|
oscx->step = AIR_CALLOC(oscx->sampleNumMax, double); |
444 |
|
|
if (!(oscx->pvlSS && oscx->nsampleImg |
445 |
|
|
&& oscx->sampleSigma && oscx->sampleRho |
446 |
|
|
&& oscx->sampleTmp && oscx->sampleErrMax && oscx->step)) { |
447 |
|
|
biffAddf(GAGE, "%s: couldn't allocate per-sample arrays", me); |
448 |
|
|
return NULL; |
449 |
|
|
} |
450 |
|
|
for (ii=0; ii<oscx->sampleNumMax; ii++) { |
451 |
|
|
oscx->nsampleImg[ii] = nrrdNew(); |
452 |
|
|
if (nrrdMaybeAlloc_va(oscx->nsampleImg[ii], nrrdTypeDouble, 3, |
453 |
|
|
AIR_CAST(size_t, oscx->sx), |
454 |
|
|
AIR_CAST(size_t, oscx->sy), |
455 |
|
|
AIR_CAST(size_t, oscx->sz))) { |
456 |
|
|
biffMovef(GAGE, NRRD, "%s: couldn't allocate vol[%u]", me, ii); |
457 |
|
|
return NULL; |
458 |
|
|
} |
459 |
|
|
nrrdAxisInfoSet_va(oscx->nsampleImg[ii], nrrdAxisInfoSpacing, |
460 |
|
|
1.0, 1.0, 1.0); |
461 |
|
|
} |
462 |
|
|
|
463 |
|
|
/* implementation not started |
464 |
|
|
oscx->nsampleHist = nrrdNew(); |
465 |
|
|
*/ |
466 |
|
|
|
467 |
|
|
return oscx; |
468 |
|
|
} |
469 |
|
|
|
470 |
|
|
gageOptimSigContext * |
471 |
|
|
gageOptimSigContextNix(gageOptimSigContext *oscx) { |
472 |
|
|
|
473 |
|
|
if (oscx) { |
474 |
|
|
unsigned int si; |
475 |
|
|
nrrdKernelSpecNix(oscx->kssSpec); |
476 |
|
|
nrrdNuke(oscx->nerr); |
477 |
|
|
nrrdNuke(oscx->ninterp); |
478 |
|
|
nrrdNuke(oscx->ndiff); |
479 |
|
|
airFree(oscx->kloc); |
480 |
|
|
airFree(oscx->kern); |
481 |
|
|
airFree(oscx->ktmp1); |
482 |
|
|
airFree(oscx->ktmp2); |
483 |
|
|
gageContextNix(oscx->gctx); |
484 |
|
|
/* airFree(oscx->pvlSS); needed? */ |
485 |
|
|
for (si=0; si<oscx->sampleNumMax; si++) { |
486 |
|
|
nrrdNuke(oscx->nsampleImg[si]); |
487 |
|
|
} |
488 |
|
|
airFree(oscx->nsampleImg); |
489 |
|
|
airFree(oscx->sampleSigma); |
490 |
|
|
airFree(oscx->sampleRho); |
491 |
|
|
airFree(oscx->sampleTmp); |
492 |
|
|
airFree(oscx->sampleErrMax); |
493 |
|
|
airFree(oscx->step); |
494 |
|
|
/* nrrdNuke(oscx->nsampleHist); */ |
495 |
|
|
airFree(oscx); |
496 |
|
|
} |
497 |
|
|
return NULL; |
498 |
|
|
} |
499 |
|
|
|
500 |
|
|
static int |
501 |
|
|
_volInterp(Nrrd *ninterp, double rho, gageOptimSigContext *oscx) { |
502 |
|
|
static const char me[]="_volInterp"; |
503 |
|
|
double *interp, scaleIdx, sigma; |
504 |
|
|
const double *answer; |
505 |
|
|
unsigned int xi, yi, zi; |
506 |
|
|
int outside; |
507 |
|
|
|
508 |
|
|
/* |
509 |
|
|
debugging = rho > 1.197; |
510 |
|
|
gageParmSet(oscx->gctx, gageParmVerbose, 2*debugging); |
511 |
|
|
*/ |
512 |
|
|
sigma = _SigOfRho(rho); |
513 |
|
|
scaleIdx = gageStackWtoI(oscx->gctx, sigma, &outside); |
514 |
|
|
/* Because of limited numerical precision, _SigOfRho(rhoRange[1]) |
515 |
|
|
can end up "outside" stack, which should really be a bug. |
516 |
|
|
However, since the use of gage is pretty straight-forward here, |
517 |
|
|
we're okay with ignoring the "outside" here, and also clamping |
518 |
|
|
the probe below */ |
519 |
|
|
answer = gageAnswerPointer(oscx->gctx, oscx->pvlBase, gageSclValue); |
520 |
|
|
interp = AIR_CAST(double *, ninterp->data); |
521 |
|
|
for (zi=0; zi<oscx->sz; zi++) { |
522 |
|
|
for (yi=0; yi<oscx->sy; yi++) { |
523 |
|
|
for (xi=0; xi<oscx->sx; xi++) { |
524 |
|
|
if (gageStackProbeSpace(oscx->gctx, xi, yi, zi, scaleIdx, |
525 |
|
|
AIR_TRUE /* index space */, |
526 |
|
|
AIR_TRUE /* clamping */)) { |
527 |
|
|
biffAddf(GAGE, "%s: probe error at (%u,%u,%u,%.17g): %s (%d)", me, |
528 |
|
|
xi, yi, zi, scaleIdx, |
529 |
|
|
oscx->gctx->errStr, oscx->gctx->errNum); |
530 |
|
|
return 1; |
531 |
|
|
} |
532 |
|
|
interp[xi + oscx->sx*(yi + oscx->sy*zi)] = answer[0]; |
533 |
|
|
} |
534 |
|
|
} |
535 |
|
|
} |
536 |
|
|
/* |
537 |
|
|
gageParmSet(oscx->gctx, gageParmVerbose, 0); |
538 |
|
|
*/ |
539 |
|
|
/* |
540 |
|
|
if (debugging) { |
541 |
|
|
char fname[AIR_STRLEN_SMALL]; |
542 |
|
|
sprintf(fname, "interp-%04u.nrrd", debugii); |
543 |
|
|
nrrdSave(fname, ninterp, NULL); |
544 |
|
|
} |
545 |
|
|
*/ |
546 |
|
|
return 0; |
547 |
|
|
} |
548 |
|
|
|
549 |
|
|
static void |
550 |
|
|
_kernset(double **kzP, double **kyP, double **kxP, |
551 |
|
|
gageOptimSigContext *oscx, |
552 |
|
|
double rho) { |
553 |
|
|
NrrdKernel *dg; |
554 |
|
|
double sig, kparm[NRRD_KERNEL_PARMS_NUM], |
555 |
|
|
*kloc, *kern, *ktmp1, *ktmp2; |
556 |
|
|
unsigned int ki, kj, kk, sx; |
557 |
|
|
|
558 |
|
|
kern = oscx->kern; |
559 |
|
|
kloc = oscx->kloc; |
560 |
|
|
ktmp1 = oscx->ktmp1; |
561 |
|
|
ktmp2 = oscx->ktmp2; |
562 |
|
|
sx = oscx->sx; |
563 |
|
|
sig = _SigOfRho(rho); |
564 |
|
|
dg = nrrdKernelDiscreteGaussian; |
565 |
|
|
kparm[1] = oscx->cutoff; |
566 |
|
|
if (sig < GOOD_SIGMA_MAX) { |
567 |
|
|
/* for small sigma, can evaluate directly into kern */ |
568 |
|
|
kparm[0] = sig; |
569 |
|
|
dg->evalN_d(kern, kloc, sx, kparm); |
570 |
|
|
} else { |
571 |
|
|
double timeleft, tdelta; |
572 |
|
|
unsigned int rx; |
573 |
|
|
rx = (sx + 1)/2 - 1; |
574 |
|
|
/* we have to iteratively blur */ |
575 |
|
|
kparm[0] = GOOD_SIGMA_MAX; |
576 |
|
|
dg->evalN_d(kern, kloc, sx, kparm); |
577 |
|
|
timeleft = sig*sig - GOOD_SIGMA_MAX*GOOD_SIGMA_MAX; |
578 |
|
|
do { |
579 |
|
|
tdelta = AIR_MIN( GOOD_SIGMA_MAX*GOOD_SIGMA_MAX, timeleft ); |
580 |
|
|
kparm[0] = sqrt(tdelta); |
581 |
|
|
dg->evalN_d(ktmp1, kloc, sx, kparm); |
582 |
|
|
for (ki=0; ki<sx; ki++) { |
583 |
|
|
double csum = 0.0; |
584 |
|
|
for (kj=0; kj<sx; kj++) { |
585 |
|
|
kk = ki - kj + rx; |
586 |
|
|
if (kk < sx) { |
587 |
|
|
csum += kern[kk]*ktmp1[kj]; |
588 |
|
|
} |
589 |
|
|
} |
590 |
|
|
ktmp2[ki] = csum; |
591 |
|
|
} |
592 |
|
|
for (ki=0; ki<sx; ki++) { |
593 |
|
|
kern[ki] = ktmp2[ki]; |
594 |
|
|
} |
595 |
|
|
timeleft -= tdelta; |
596 |
|
|
} while (timeleft); |
597 |
|
|
} |
598 |
|
|
*kzP = oscx->dim >= 3 ? kern : oscx->kone; |
599 |
|
|
*kyP = oscx->dim >= 2 ? kern : oscx->kone; |
600 |
|
|
*kxP = kern; |
601 |
|
|
return; |
602 |
|
|
} |
603 |
|
|
|
604 |
|
|
/* |
605 |
|
|
** sets one of the sampleImg, to be used as a sample in scale-space interp |
606 |
|
|
*/ |
607 |
|
|
static void |
608 |
|
|
_sampleSet(gageOptimSigContext *oscx, unsigned int si, double rho) { |
609 |
|
|
double *vol, *kz, *ky, *kx; |
610 |
|
|
unsigned int ii, xi, yi, zi; |
611 |
|
|
|
612 |
|
|
oscx->sampleSigma[si] = _SigOfRho(rho); |
613 |
|
|
oscx->sampleRho[si] = rho; |
614 |
|
|
vol = AIR_CAST(double *, oscx->nsampleImg[si]->data); |
615 |
|
|
_kernset(&kz, &ky, &kx, oscx, rho); |
616 |
|
|
ii = 0; |
617 |
|
|
for (zi=0; zi<oscx->sz; zi++) { |
618 |
|
|
for (yi=0; yi<oscx->sy; yi++) { |
619 |
|
|
for (xi=0; xi<oscx->sx; xi++) { |
620 |
|
|
vol[ii] = kz[zi]*ky[yi]*kx[xi]; |
621 |
|
|
ii++; |
622 |
|
|
} |
623 |
|
|
} |
624 |
|
|
} |
625 |
|
|
if (oscx->gctx) { |
626 |
|
|
/* the gage stack needs to know new scale pos */ |
627 |
|
|
oscx->gctx->stackPos[si] = oscx->sampleSigma[si]; |
628 |
|
|
/* HEY: GLK forgets why this is needed, |
629 |
|
|
but remembers it was a tricky bug to find */ |
630 |
|
|
gagePointReset(&(oscx->gctx->point)); |
631 |
|
|
} |
632 |
|
|
return; |
633 |
|
|
} |
634 |
|
|
|
635 |
|
|
static int |
636 |
|
|
_errSingle(double *retP, gageOptimSigContext *oscx, double rho) { |
637 |
|
|
static const char me[]="_errSingle"; |
638 |
|
|
double *diff, *kx, *ky, *kz; |
639 |
|
|
const double *interp; |
640 |
|
|
unsigned int ii, xi, yi, zi; |
641 |
|
|
|
642 |
|
|
if (_volInterp(oscx->ninterp, rho, oscx)) { |
643 |
|
|
biffAddf(GAGE, "%s: trouble at rho %.17g\n", me, rho); |
644 |
|
|
return 1; |
645 |
|
|
} |
646 |
|
|
/* |
647 |
|
|
if (debugging) { |
648 |
|
|
char fname[AIR_STRLEN_SMALL]; |
649 |
|
|
sprintf(fname, "interp-%04u.nrrd", debugii); |
650 |
|
|
nrrdSave(fname, oscx->ninterp, NULL); |
651 |
|
|
} |
652 |
|
|
*/ |
653 |
|
|
interp = AIR_CAST(const double *, oscx->ninterp->data); |
654 |
|
|
diff = AIR_CAST(double *, oscx->ndiff->data); |
655 |
|
|
_kernset(&kz, &ky, &kx, oscx, rho); |
656 |
|
|
ii = 0; |
657 |
|
|
for (zi=0; zi<oscx->sz; zi++) { |
658 |
|
|
for (yi=0; yi<oscx->sy; yi++) { |
659 |
|
|
for (xi=0; xi<oscx->sx; xi++) { |
660 |
|
|
double tru; |
661 |
|
|
tru = kz[zi]*ky[yi]*kx[xi]; |
662 |
|
|
diff[ii] = interp[ii] - tru; |
663 |
|
|
if (debugReconErrArr) { |
664 |
|
|
unsigned int idx = airArrayLenIncr(debugReconErrArr, 2); |
665 |
|
|
debugReconErr[idx + 0] = tru; |
666 |
|
|
debugReconErr[idx + 1] = interp[ii]; |
667 |
|
|
} |
668 |
|
|
ii++; |
669 |
|
|
} |
670 |
|
|
} |
671 |
|
|
} |
672 |
|
|
nrrdMeasureLine[oscx->imgMeasr](retP, nrrdTypeDouble, |
673 |
|
|
diff, nrrdTypeDouble, |
674 |
|
|
ii /* HEY: cleverness */, |
675 |
|
|
AIR_NAN, AIR_NAN); |
676 |
|
|
return 0; |
677 |
|
|
} |
678 |
|
|
|
679 |
|
|
static int |
680 |
|
|
_errTotal(double *retP, gageOptimSigContext *oscx) { |
681 |
|
|
static const char me[]="_errTotal"; |
682 |
|
|
unsigned int ii; |
683 |
|
|
double *err; |
684 |
|
|
|
685 |
|
|
err = AIR_CAST(double *, oscx->nerr->data); |
686 |
|
|
for (ii=0; ii<oscx->trueImgNum; ii++) { |
687 |
|
|
/* debugii = ii; */ |
688 |
|
|
if (_errSingle(err + ii, oscx, AIR_AFFINE(0, ii, oscx->trueImgNum-1, |
689 |
|
|
oscx->rhoRange[0], |
690 |
|
|
oscx->rhoRange[1]))) { |
691 |
|
|
biffAddf(GAGE, "%s: trouble at ii %u", me, ii); |
692 |
|
|
return 1; |
693 |
|
|
} |
694 |
|
|
} |
695 |
|
|
nrrdMeasureLine[oscx->allMeasr](retP, nrrdTypeDouble, |
696 |
|
|
err, nrrdTypeDouble, |
697 |
|
|
oscx->trueImgNum, |
698 |
|
|
AIR_NAN, AIR_NAN); |
699 |
|
|
/* |
700 |
|
|
if (debugging) { |
701 |
|
|
char fname[AIR_STRLEN_SMALL]; |
702 |
|
|
unsigned int ni; |
703 |
|
|
for (ni=0; ni<oscx->sampleNum; ni++) { |
704 |
|
|
sprintf(fname, "sample-%04u.nrrd", ni); |
705 |
|
|
nrrdSave(fname, oscx->nsampleImg[ni], NULL); |
706 |
|
|
} |
707 |
|
|
} |
708 |
|
|
*/ |
709 |
|
|
if (0) { |
710 |
|
|
static unsigned int call=0; |
711 |
|
|
char fname[AIR_STRLEN_SMALL]; |
712 |
|
|
sprintf(fname, "err-%04u.nrrd", call); |
713 |
|
|
nrrdSave(fname, oscx->nerr, NULL); |
714 |
|
|
call++; |
715 |
|
|
} |
716 |
|
|
return 0; |
717 |
|
|
} |
718 |
|
|
|
719 |
|
|
static int |
720 |
|
|
_errTotalLinf(double *retP, gageOptimSigContext *oscx, |
721 |
|
|
unsigned int mmIdx[2], double mmErr[2]) { |
722 |
|
|
static const char me[]="_errTotalLinf"; |
723 |
|
|
unsigned int ii, pi; |
724 |
|
|
double *err, *sem, *rr, rho, sig, pid; |
725 |
|
|
int outside; |
726 |
|
|
|
727 |
|
|
err = AIR_CAST(double *, oscx->nerr->data); |
728 |
|
|
sem = oscx->sampleErrMax; |
729 |
|
|
rr = oscx->rhoRange; |
730 |
|
|
for (pi=0; pi<=oscx->sampleNum-2; pi++) { |
731 |
|
|
sem[pi] = 0; |
732 |
|
|
} |
733 |
|
|
/* NOTE: we don't bother with last "true image": it will always be a |
734 |
|
|
low error, and not meaningfully associated with a gap */ |
735 |
|
|
for (ii=0; ii<oscx->trueImgNum-1; ii++) { |
736 |
|
|
/* debugii = ii; */ |
737 |
|
|
rho = AIR_AFFINE(0, ii, oscx->trueImgNum-1, rr[0], rr[1]); |
738 |
|
|
if (_errSingle(err + ii, oscx, rho)) { |
739 |
|
|
biffAddf(GAGE, "%s: trouble at ii %u", me, ii); |
740 |
|
|
return 1; |
741 |
|
|
} |
742 |
|
|
sig = _SigOfRho(rho); |
743 |
|
|
pid = gageStackWtoI(oscx->gctx, sig, &outside); |
744 |
|
|
pi = AIR_CAST(unsigned int, pid); |
745 |
|
|
if (outside || !(pi <= oscx->sampleNum-2)) { |
746 |
|
|
biffAddf(GAGE, "%s: ii %u -> rho %g -> sig %g -> pi %u-> OUTSIDE", |
747 |
|
|
me, ii, rho, sig, pi); |
748 |
|
|
return 1; |
749 |
|
|
} |
750 |
|
|
sem[pi] = AIR_MAX(sem[pi], err[ii]); |
751 |
|
|
} |
752 |
|
|
mmIdx[0] = mmIdx[1] = 0; |
753 |
|
|
mmErr[0] = mmErr[1] = sem[0]; |
754 |
|
|
for (pi=1; pi<=oscx->sampleNum-2; pi++) { |
755 |
|
|
if (sem[pi] < mmErr[0]) { |
756 |
|
|
mmIdx[0] = pi; |
757 |
|
|
mmErr[0] = sem[pi]; |
758 |
|
|
} |
759 |
|
|
if (sem[pi] > mmErr[1]) { |
760 |
|
|
mmIdx[1] = pi; |
761 |
|
|
mmErr[1] = sem[pi]; |
762 |
|
|
} |
763 |
|
|
} |
764 |
|
|
/* returned error invented, not really Linf, but minimizing this |
765 |
|
|
does the right thing */ |
766 |
|
|
*retP = 1000*oscx->sampleNum*(mmErr[1] - mmErr[0])/(rr[1] - rr[0]); |
767 |
|
|
if (0) { |
768 |
|
|
static unsigned int call=0; |
769 |
|
|
char fname[AIR_STRLEN_SMALL]; |
770 |
|
|
sprintf(fname, "err-%04u.nrrd", call); |
771 |
|
|
nrrdSave(fname, oscx->nerr, NULL); |
772 |
|
|
call++; |
773 |
|
|
} |
774 |
|
|
return 0; |
775 |
|
|
} |
776 |
|
|
|
777 |
|
|
/* |
778 |
|
|
** this can be called repeatedly |
779 |
|
|
*/ |
780 |
|
|
static int |
781 |
|
|
_gageSetup(gageOptimSigContext *oscx) { |
782 |
|
|
static const char me[]="_gageSetup"; |
783 |
|
|
double kparm[NRRD_KERNEL_PARMS_NUM]; |
784 |
|
|
int E; |
785 |
|
|
|
786 |
|
|
if (oscx->gctx) { |
787 |
|
|
gageContextNix(oscx->gctx); |
788 |
|
|
} |
789 |
|
|
oscx->gctx = gageContextNew(); |
790 |
|
|
gageParmSet(oscx->gctx, gageParmVerbose, 0); |
791 |
|
|
gageParmSet(oscx->gctx, gageParmRenormalize, AIR_FALSE); |
792 |
|
|
gageParmSet(oscx->gctx, gageParmCheckIntegrals, AIR_FALSE); |
793 |
|
|
gageParmSet(oscx->gctx, gageParmOrientationFromSpacing, AIR_TRUE); |
794 |
|
|
gageParmSet(oscx->gctx, gageParmStackUse, AIR_TRUE); |
795 |
|
|
E = 0; |
796 |
|
|
if (!E) E |= !(oscx->pvlBase = gagePerVolumeNew(oscx->gctx, |
797 |
|
|
oscx->nsampleImg[0], |
798 |
|
|
gageKindScl)); |
799 |
|
|
if (!E) E |= gageStackPerVolumeNew(oscx->gctx, oscx->pvlSS, |
800 |
|
|
AIR_CAST(const Nrrd*const*, |
801 |
|
|
oscx->nsampleImg), |
802 |
|
|
oscx->sampleNum, gageKindScl); |
803 |
|
|
if (!E) E |= gageStackPerVolumeAttach(oscx->gctx, |
804 |
|
|
oscx->pvlBase, oscx->pvlSS, |
805 |
|
|
oscx->sampleSigma, oscx->sampleNum); |
806 |
|
|
kparm[0] = 1; |
807 |
|
|
if (!E) E |= gageKernelSet(oscx->gctx, gageKernel00, |
808 |
|
|
nrrdKernelBox, kparm); |
809 |
|
|
if (!E) E |= gageKernelSet(oscx->gctx, gageKernelStack, |
810 |
|
|
oscx->kssSpec->kernel, oscx->kssSpec->parm); |
811 |
|
|
if (!E) E |= gageQueryItemOn(oscx->gctx, oscx->pvlBase, gageSclValue); |
812 |
|
|
if (!E) E |= gageUpdate(oscx->gctx); |
813 |
|
|
if (E) { |
814 |
|
|
biffAddf(GAGE, "%s: problem setting up gage", me); |
815 |
|
|
return 1; |
816 |
|
|
} |
817 |
|
|
return 0; |
818 |
|
|
} |
819 |
|
|
|
820 |
|
|
static char * |
821 |
|
|
_timefmt(char tstr[AIR_STRLEN_MED], double deltim) { |
822 |
|
|
|
823 |
|
|
if (deltim < 60) { |
824 |
|
|
sprintf(tstr, "%g secs", deltim); |
825 |
|
|
return tstr; |
826 |
|
|
} |
827 |
|
|
deltim /= 60; |
828 |
|
|
if (deltim < 60) { |
829 |
|
|
sprintf(tstr, "%g mins", deltim); |
830 |
|
|
return tstr; |
831 |
|
|
} |
832 |
|
|
deltim /= 60; |
833 |
|
|
if (deltim < 24) { |
834 |
|
|
sprintf(tstr, "%g hours", deltim); |
835 |
|
|
return tstr; |
836 |
|
|
} |
837 |
|
|
deltim /= 24; |
838 |
|
|
if (deltim < 7) { |
839 |
|
|
sprintf(tstr, "%g days", deltim); |
840 |
|
|
return tstr; |
841 |
|
|
} |
842 |
|
|
deltim /= 7; |
843 |
|
|
sprintf(tstr, "%g weeks", deltim); |
844 |
|
|
return tstr; |
845 |
|
|
} |
846 |
|
|
|
847 |
|
|
static int |
848 |
|
|
_optsigrun(gageOptimSigContext *oscx) { |
849 |
|
|
static const char me[]="_optsigrun"; |
850 |
|
|
char tstr[AIR_STRLEN_MED]; |
851 |
|
|
unsigned int iter, pnt; |
852 |
|
|
double lastErr, newErr, rhoeps, oppor, lastPos, backoff, decavg, time0; |
853 |
|
|
int badStep; |
854 |
|
|
|
855 |
|
|
/* used to debug failure to measure error meaningfully |
856 |
|
|
{ |
857 |
|
|
unsigned int hi, hn=200; |
858 |
|
|
double rr; |
859 |
|
|
for (hi=0; hi<hn; hi++) { |
860 |
|
|
rr = AIR_AFFINE(-20, hi, hn+20, oscx->rhoRange[0], oscx->rhoRange[1]); |
861 |
|
|
_sampleSet(oscx, 1, rr); |
862 |
|
|
_errTotal(oscx); |
863 |
|
|
} |
864 |
|
|
} |
865 |
|
|
*/ |
866 |
|
|
|
867 |
|
|
time0 = airTime(); |
868 |
|
|
if (_errTotal(&lastErr, oscx)) { |
869 |
|
|
biffAddf(GAGE, "%s: first error measurement", me); |
870 |
|
|
return 1; |
871 |
|
|
} |
872 |
|
|
fprintf(stderr, "%s: (%s for initial error measr)\n", me, |
873 |
|
|
_timefmt(tstr, airTime() - time0)); |
874 |
|
|
newErr = AIR_NAN; |
875 |
|
|
decavg = oscx->sampleNum; /* hack */ |
876 |
|
|
/* meaningful discrete difference for looking at error gradient is |
877 |
|
|
bounded by the resolution of the sampling we're doing along scale */ |
878 |
|
|
rhoeps = 0.1*(oscx->rhoRange[1]-oscx->rhoRange[0])/oscx->trueImgNum; |
879 |
|
|
oppor = 1.3333; |
880 |
|
|
backoff = 0.25; |
881 |
|
|
/* initialize step for the moving samples: 1 through oscx->sampleNum-2 */ |
882 |
|
|
for (pnt=1; pnt<oscx->sampleNum-1; pnt++) { |
883 |
|
|
oscx->step[pnt] = 10; |
884 |
|
|
} |
885 |
|
|
for (iter=0; iter<oscx->maxIter; iter++) { |
886 |
|
|
double limit, err1, grad, delta; |
887 |
|
|
unsigned int tryi; |
888 |
|
|
int zerodelta, esgn; |
889 |
|
|
esgn = 2*AIR_CAST(int, airRandInt(2)) - 1; |
890 |
|
|
pnt = 1 + (iter % (oscx->sampleNum-2)); |
891 |
|
|
lastPos = oscx->sampleRho[pnt]; |
892 |
|
|
fprintf(stderr, "%s: ***** iter %u; [[ err %g ]] %s\n", |
893 |
|
|
me, iter, lastErr, _timefmt(tstr, airTime() - time0)); |
894 |
|
|
limit = AIR_MIN((oscx->sampleRho[pnt] - oscx->sampleRho[pnt-1])/3, |
895 |
|
|
(oscx->sampleRho[pnt+1] - oscx->sampleRho[pnt])/3); |
896 |
|
|
fprintf(stderr, ". pnt %u: pos %g, step %g\n", |
897 |
|
|
pnt, lastPos, oscx->step[pnt]); |
898 |
|
|
fprintf(stderr, ". limit = min((%g-%g)/3,(%g-%g)/3) = %g\n", |
899 |
|
|
oscx->sampleRho[pnt], oscx->sampleRho[pnt-1], |
900 |
|
|
oscx->sampleRho[pnt+1], oscx->sampleRho[pnt], limit); |
901 |
|
|
_sampleSet(oscx, pnt, lastPos + esgn*rhoeps); |
902 |
|
|
if (_errTotal(&err1, oscx)) { |
903 |
|
|
biffAddf(GAGE, "%s: for err1 (%u -> %.17g)", |
904 |
|
|
me, pnt, lastPos + esgn*rhoeps); |
905 |
|
|
return 1; |
906 |
|
|
} |
907 |
|
|
_sampleSet(oscx, pnt, lastPos); |
908 |
|
|
grad = (err1 - lastErr)/(esgn*rhoeps); |
909 |
|
|
fprintf(stderr, ". grad = %g\n", grad); |
910 |
|
|
delta = -grad*oscx->step[pnt]; |
911 |
|
|
if (!AIR_EXISTS(delta)) { |
912 |
|
|
biffAddf(GAGE, "%s: got non-exist delta %g on iter %u (pnt %u) err %g", |
913 |
|
|
me, delta, iter, pnt, lastErr); |
914 |
|
|
return 1; |
915 |
|
|
} |
916 |
|
|
if (AIR_ABS(delta) > limit) { |
917 |
|
|
oscx->step[pnt] *= limit/AIR_ABS(delta); |
918 |
|
|
fprintf(stderr, ". step *= %g/%g -> %g\n", |
919 |
|
|
limit, AIR_ABS(delta), oscx->step[pnt]); |
920 |
|
|
delta = -grad*oscx->step[pnt]; |
921 |
|
|
} |
922 |
|
|
fprintf(stderr, ". delta = %g\n", delta); |
923 |
|
|
tryi = 0; |
924 |
|
|
badStep = AIR_FALSE; |
925 |
|
|
do { |
926 |
|
|
if (tryi == oscx->maxIter) { |
927 |
|
|
biffAddf(GAGE, "%s: confusion (tryi %u) on iter %u (pnt %u) err %g", |
928 |
|
|
me, tryi, iter, pnt, lastErr); |
929 |
|
|
return 1; |
930 |
|
|
} |
931 |
|
|
if (!delta) { |
932 |
|
|
fprintf(stderr, "... try %u: delta = 0; nothing to do\n", tryi); |
933 |
|
|
newErr = lastErr; |
934 |
|
|
zerodelta = AIR_TRUE; |
935 |
|
|
} else { |
936 |
|
|
zerodelta = AIR_FALSE; |
937 |
|
|
_sampleSet(oscx, pnt, lastPos + delta); |
938 |
|
|
if (_errTotal(&newErr, oscx)) { |
939 |
|
|
biffAddf(GAGE, "%s: for newErr (%u -> %.17g)", me, |
940 |
|
|
pnt, lastPos + delta); |
941 |
|
|
return 1; |
942 |
|
|
} |
943 |
|
|
badStep = newErr > lastErr; |
944 |
|
|
fprintf(stderr, "... try %u: pos[%u] %g + %g = %g;\n" |
945 |
|
|
"%s: err %g %s %g\n", |
946 |
|
|
tryi, pnt, lastPos, delta, |
947 |
|
|
oscx->sampleRho[pnt], |
948 |
|
|
badStep ? "*BAD*" : "good", |
949 |
|
|
newErr, newErr > lastErr ? ">" : "<=", lastErr); |
950 |
|
|
if (badStep) { |
951 |
|
|
oscx->step[pnt] *= backoff; |
952 |
|
|
if (oscx->step[pnt] < rhoeps/1000) { |
953 |
|
|
/* step got so small its stupid to be moving this point */ |
954 |
|
|
fprintf(stderr, "... !! step %g < %g pointlessly small, " |
955 |
|
|
"moving on\n", oscx->step[pnt], rhoeps/1000); |
956 |
|
|
_sampleSet(oscx, pnt, lastPos); |
957 |
|
|
newErr = lastErr; |
958 |
|
|
badStep = AIR_FALSE; |
959 |
|
|
} else { |
960 |
|
|
delta = -grad*oscx->step[pnt]; |
961 |
|
|
} |
962 |
|
|
} |
963 |
|
|
} |
964 |
|
|
tryi++; |
965 |
|
|
} while (badStep); |
966 |
|
|
if (!zerodelta) { |
967 |
|
|
/* don't update decavg if we moved on because slope was EXACTLY zero */ |
968 |
|
|
decavg = AIR_AFFINE(0, 1, oscx->sampleNum, |
969 |
|
|
decavg, (lastErr - newErr)/lastErr); |
970 |
|
|
oscx->step[pnt] *= oppor; |
971 |
|
|
} |
972 |
|
|
if (decavg <= oscx->convEps) { |
973 |
|
|
fprintf(stderr, "%s: converged (%g <= %g) after %u iters\n", me, |
974 |
|
|
decavg, oscx->convEps, iter); |
975 |
|
|
break; |
976 |
|
|
} else { |
977 |
|
|
fprintf(stderr, "%s: _____ iter %u done; decavg = %g > eps %g\n", me, |
978 |
|
|
iter, decavg, oscx->convEps); |
979 |
|
|
} |
980 |
|
|
lastErr = newErr; |
981 |
|
|
} |
982 |
|
|
if (iter == oscx->maxIter && decavg > oscx->convEps) { |
983 |
|
|
biffAddf(GAGE, "%s: failed to converge (%g > %g) after %u iters\n", me, |
984 |
|
|
decavg, oscx->convEps, iter); |
985 |
|
|
return 1; |
986 |
|
|
} |
987 |
|
|
oscx->finalErr = lastErr; |
988 |
|
|
|
989 |
|
|
return 0; |
990 |
|
|
} |
991 |
|
|
|
992 |
|
|
static int |
993 |
|
|
_optsigrunLinf(gageOptimSigContext *oscx) { |
994 |
|
|
static const char me[]="_optsigrunLinf"; |
995 |
|
|
char tstr[AIR_STRLEN_MED]; |
996 |
|
|
double *srho, *stmp, time0, lastErr, newErr, decavg, |
997 |
|
|
step, oppor, backoff, ceps, mmErr[2]; |
998 |
|
|
unsigned int iter, si, sn, mmIdx[2]; |
999 |
|
|
int shrink; |
1000 |
|
|
|
1001 |
|
|
time0 = airTime(); |
1002 |
|
|
if (_errTotalLinf(&lastErr, oscx, mmIdx, mmErr)) { |
1003 |
|
|
biffAddf(GAGE, "%s: first error measurement", me); |
1004 |
|
|
return 1; |
1005 |
|
|
} |
1006 |
|
|
fprintf(stderr, "%s: (init) min %u %g max %u %g\n", me, |
1007 |
|
|
mmIdx[0], mmErr[0], mmIdx[1], mmErr[1]); |
1008 |
|
|
fprintf(stderr, "%s: (%s for initial error measr)\n", me, |
1009 |
|
|
_timefmt(tstr, airTime() - time0)); |
1010 |
|
|
newErr = AIR_NAN; |
1011 |
|
|
|
1012 |
|
|
/* shorcuts */ |
1013 |
|
|
sn = oscx->sampleNum; |
1014 |
|
|
srho = oscx->sampleRho; |
1015 |
|
|
stmp = oscx->sampleTmp; |
1016 |
|
|
|
1017 |
|
|
/* Linf uses a single scalar step istead of oscx->step array */ |
1018 |
|
|
step = 0.1; |
1019 |
|
|
oppor = 1.1; |
1020 |
|
|
backoff = 0.5; |
1021 |
|
|
|
1022 |
|
|
/* more demanding for more points */ |
1023 |
|
|
ceps = oscx->convEps/sn; |
1024 |
|
|
|
1025 |
|
|
decavg = 2*ceps; |
1026 |
|
|
for (iter=0; iter<oscx->maxIter; iter++) { |
1027 |
|
|
double midp, wlo, whi, glo, ghi, gerr; |
1028 |
|
|
unsigned int gap, tryi; |
1029 |
|
|
int badStep; |
1030 |
|
|
|
1031 |
|
|
if (iter % 2) { |
1032 |
|
|
/* we will grow gap around smallest peak */ |
1033 |
|
|
gap = mmIdx[0]; |
1034 |
|
|
gerr = mmErr[0]; |
1035 |
|
|
shrink = AIR_FALSE; |
1036 |
|
|
} else { |
1037 |
|
|
/* we will shrink gap around tallest peak */ |
1038 |
|
|
gap = mmIdx[1]; |
1039 |
|
|
gerr = mmErr[1]; |
1040 |
|
|
shrink = AIR_TRUE; |
1041 |
|
|
} |
1042 |
|
|
midp = (srho[gap] + srho[gap+1])/2; |
1043 |
|
|
fprintf(stderr, "%s: ---- iter %u (step %g): gap [%u]/%g (%s)\n", |
1044 |
|
|
me, iter, step, gap, gerr, |
1045 |
|
|
shrink ? "shrinking tallest" : "growing lowest"); |
1046 |
|
|
/* save last set of positions to restore after bad step */ |
1047 |
|
|
for (si=1; si<sn-1; si++) { |
1048 |
|
|
stmp[si] = srho[si]; |
1049 |
|
|
} |
1050 |
|
|
tryi = 0; |
1051 |
|
|
badStep = AIR_FALSE; |
1052 |
|
|
do { |
1053 |
|
|
if (tryi == oscx->maxIter) { |
1054 |
|
|
biffAddf(GAGE, "%s: confusion (tryi %u) on iter %u err %g", |
1055 |
|
|
me, tryi, iter, lastErr); |
1056 |
|
|
return 1; |
1057 |
|
|
} |
1058 |
|
|
if (shrink) { |
1059 |
|
|
wlo = AIR_AFFINE(0, step, 1, srho[gap], midp); |
1060 |
|
|
whi = AIR_AFFINE(0, step, 1, srho[gap+1], midp); |
1061 |
|
|
} else { |
1062 |
|
|
wlo = AIR_AFFINE(0, step, -2, srho[gap], midp); |
1063 |
|
|
whi = AIR_AFFINE(0, step, -2, srho[gap+1], midp); |
1064 |
|
|
} |
1065 |
|
|
glo = srho[gap]; |
1066 |
|
|
ghi = srho[gap+1]; |
1067 |
|
|
fprintf(stderr, "%s: rho[%u] %g | %g -- rho[%u] %g | %g\n", me, |
1068 |
|
|
gap, srho[gap], wlo, gap+1, srho[gap+1], whi); |
1069 |
|
|
for (si=1; si<sn-1; si++) { |
1070 |
|
|
_sampleSet(oscx, si, (si <= gap |
1071 |
|
|
? AIR_AFFINE(srho[0], srho[si], glo, |
1072 |
|
|
srho[0], wlo) |
1073 |
|
|
: AIR_AFFINE(ghi, srho[si], srho[sn-1], |
1074 |
|
|
whi, srho[sn-1]))); |
1075 |
|
|
} |
1076 |
|
|
if (_errTotalLinf(&newErr, |
1077 |
|
|
oscx, mmIdx, mmErr)) { |
1078 |
|
|
biffAddf(GAGE, "%s: iter %u", me, iter); |
1079 |
|
|
return 1; |
1080 |
|
|
} |
1081 |
|
|
fprintf(stderr, "%s: min %u %g max %u %g\n", me, |
1082 |
|
|
mmIdx[0], mmErr[0], mmIdx[1], mmErr[1]); |
1083 |
|
|
if (iter % 3) { |
1084 |
|
|
badStep = newErr > lastErr; |
1085 |
|
|
fprintf(stderr, "... try %u [%u] step %g -> newErr %g %s " |
1086 |
|
|
"lastErr %g %s\n", |
1087 |
|
|
tryi, gap, step, newErr, |
1088 |
|
|
badStep ? ">" : "<=", |
1089 |
|
|
lastErr, |
1090 |
|
|
badStep ? "*BAD*" : "good"); |
1091 |
|
|
if (badStep) { |
1092 |
|
|
step *= backoff; |
1093 |
|
|
for (si=1; si<sn-1; si++) { |
1094 |
|
|
srho[si] = stmp[si]; |
1095 |
|
|
} |
1096 |
|
|
} |
1097 |
|
|
tryi++; |
1098 |
|
|
} |
1099 |
|
|
} while (badStep); |
1100 |
|
|
step *= oppor; |
1101 |
|
|
decavg = (decavg + (lastErr - newErr))/2; |
1102 |
|
|
if (AIR_IN_OP(0, decavg, ceps)) { |
1103 |
|
|
fprintf(stderr, "%s: converged (%g <= %g) after %u iters\n", me, |
1104 |
|
|
decavg, ceps, iter); |
1105 |
|
|
break; |
1106 |
|
|
} else { |
1107 |
|
|
fprintf(stderr, "%s: iter %u done; decavg = %g > eps %g\n", me, |
1108 |
|
|
iter, decavg, ceps); |
1109 |
|
|
} |
1110 |
|
|
lastErr = newErr; |
1111 |
|
|
} /* for iter */ |
1112 |
|
|
if (oscx->maxIter |
1113 |
|
|
&& iter == oscx->maxIter |
1114 |
|
|
&& decavg > ceps) { |
1115 |
|
|
biffAddf(GAGE, "%s: failed to converge (%g > %g) after %u iters\n", me, |
1116 |
|
|
decavg, ceps, iter); |
1117 |
|
|
return 1; |
1118 |
|
|
} |
1119 |
|
|
oscx->finalErr = lastErr; |
1120 |
|
|
|
1121 |
|
|
return 0; |
1122 |
|
|
} |
1123 |
|
|
|
1124 |
|
|
int |
1125 |
|
|
gageOptimSigCalculate(gageOptimSigContext *oscx, |
1126 |
|
|
/* output */ double *sigma, |
1127 |
|
|
unsigned int sigmaNum, |
1128 |
|
|
const NrrdKernelSpec *kssSpec, |
1129 |
|
|
int imgMeasr, int allMeasr, |
1130 |
|
|
unsigned int maxIter, double convEps) { |
1131 |
|
|
static const char me[]="gageOptimSigCalculate"; |
1132 |
|
|
unsigned int ii; |
1133 |
|
|
|
1134 |
|
|
if (!( oscx && sigma && kssSpec )) { |
1135 |
|
|
biffAddf(GAGE, "%s: got NULL pointer", me); |
1136 |
|
|
return 1; |
1137 |
|
|
} |
1138 |
|
|
if (sigmaNum > oscx->sampleNumMax) { |
1139 |
|
|
biffAddf(GAGE, "%s: initialized for max %u samples, not %u", me, |
1140 |
|
|
oscx->sampleNumMax, sigmaNum); |
1141 |
|
|
return 1; |
1142 |
|
|
} |
1143 |
|
|
|
1144 |
|
|
/* initialize to uniform samples in rho */ |
1145 |
|
|
oscx->sampleNum = sigmaNum; |
1146 |
|
|
fprintf(stderr, "%s: initializing %u samples ... ", me, oscx->sampleNum); |
1147 |
|
|
fflush(stderr); |
1148 |
|
|
for (ii=0; ii<oscx->sampleNum; ii++) { |
1149 |
|
|
_sampleSet(oscx, ii, AIR_AFFINE(0, ii, oscx->sampleNum-1, |
1150 |
|
|
oscx->rhoRange[0], oscx->rhoRange[1])); |
1151 |
|
|
} |
1152 |
|
|
fprintf(stderr, "done.\n"); |
1153 |
|
|
|
1154 |
|
|
/* copy remaining input parameters */ |
1155 |
|
|
nrrdKernelSpecNix(oscx->kssSpec); |
1156 |
|
|
oscx->kssSpec = nrrdKernelSpecCopy(kssSpec); |
1157 |
|
|
oscx->imgMeasr = imgMeasr; |
1158 |
|
|
oscx->allMeasr = allMeasr; |
1159 |
|
|
oscx->convEps = convEps; |
1160 |
|
|
oscx->maxIter = maxIter; |
1161 |
|
|
oscx->convEps = convEps; |
1162 |
|
|
|
1163 |
|
|
/* set up gage */ |
1164 |
|
|
fprintf(stderr, "%s: setting up gage ... \n", me); |
1165 |
|
|
if (_gageSetup(oscx)) { |
1166 |
|
|
biffAddf(GAGE, "%s: problem setting up gage", me); |
1167 |
|
|
return 1; |
1168 |
|
|
} |
1169 |
|
|
fprintf(stderr, "%s: ... gage setup done.\n", me); |
1170 |
|
|
|
1171 |
|
|
/* run the optimization */ |
1172 |
|
|
if (oscx->sampleNum > 2) { |
1173 |
|
|
int EE; |
1174 |
|
|
EE = (nrrdMeasureLinf == oscx->allMeasr |
1175 |
|
|
? _optsigrunLinf(oscx) |
1176 |
|
|
: _optsigrun(oscx)); |
1177 |
|
|
if (EE) { |
1178 |
|
|
biffAddf(GAGE, "%s: trouble", me); |
1179 |
|
|
return 1; |
1180 |
|
|
} |
1181 |
|
|
} else { |
1182 |
|
|
fprintf(stderr, "%s: num == 2, no optimization, finding error ... ", me); |
1183 |
|
|
fflush(stderr); |
1184 |
|
|
if (_errTotal(&(oscx->finalErr), oscx)) { |
1185 |
|
|
biffAddf(GAGE, "%s: for finalErr", me); |
1186 |
|
|
return 1; |
1187 |
|
|
} |
1188 |
|
|
fprintf(stderr, "done.\n"); |
1189 |
|
|
} |
1190 |
|
|
|
1191 |
|
|
/* save output */ |
1192 |
|
|
for (ii=0; ii<oscx->sampleNum; ii++) { |
1193 |
|
|
sigma[ii] = oscx->sampleSigma[ii]; |
1194 |
|
|
} |
1195 |
|
|
|
1196 |
|
|
return 0; |
1197 |
|
|
} |
1198 |
|
|
|
1199 |
|
|
int |
1200 |
|
|
gageOptimSigErrorPlot(gageOptimSigContext *oscx, Nrrd *nout, |
1201 |
|
|
const double *sigma, |
1202 |
|
|
unsigned int sigmaNum, |
1203 |
|
|
const NrrdKernelSpec *kssSpec, |
1204 |
|
|
int imgMeasr) { |
1205 |
|
|
static const char me[]="gageOptimSigErrorPlot"; |
1206 |
|
|
char doneStr[AIR_STRLEN_SMALL]; |
1207 |
|
|
double *out; |
1208 |
|
|
unsigned int ii; |
1209 |
|
|
|
1210 |
|
|
if (!(oscx && nout && sigma)) { |
1211 |
|
|
biffAddf(GAGE, "%s: got NULL pointer", me); |
1212 |
|
|
return 1; |
1213 |
|
|
} |
1214 |
|
|
if (!( sigmaNum >= 2 )) { |
1215 |
|
|
biffAddf(GAGE, "%s: need sigmaNum >= 2 (not %u)", me, sigmaNum); |
1216 |
|
|
return 1; |
1217 |
|
|
} |
1218 |
|
|
if (sigmaNum > oscx->sampleNumMax) { |
1219 |
|
|
biffAddf(GAGE, "%s: initialized for max %u samples, not %u", me, |
1220 |
|
|
oscx->sampleNumMax, sigmaNum); |
1221 |
|
|
return 1; |
1222 |
|
|
} |
1223 |
|
|
|
1224 |
|
|
/* copy remaining input parms */ |
1225 |
|
|
nrrdKernelSpecNix(oscx->kssSpec); |
1226 |
|
|
oscx->kssSpec = nrrdKernelSpecCopy(kssSpec); |
1227 |
|
|
oscx->sampleNum = sigmaNum; |
1228 |
|
|
oscx->maxIter = 0; |
1229 |
|
|
oscx->imgMeasr = imgMeasr; |
1230 |
|
|
oscx->allMeasr = nrrdMeasureUnknown; |
1231 |
|
|
oscx->convEps = AIR_NAN; |
1232 |
|
|
if (nrrdMaybeAlloc_va(nout, nrrdTypeDouble, 2, |
1233 |
|
|
AIR_CAST(size_t, 2), |
1234 |
|
|
AIR_CAST(size_t, oscx->trueImgNum))) { |
1235 |
|
|
biffMovef(GAGE, NRRD, "%s: trouble allocating output", me); |
1236 |
|
|
return 1; |
1237 |
|
|
} |
1238 |
|
|
out = AIR_CAST(double *, nout->data); |
1239 |
|
|
|
1240 |
|
|
/* set up requested samples */ |
1241 |
|
|
for (ii=0; ii<oscx->sampleNum; ii++) { |
1242 |
|
|
_sampleSet(oscx, ii, _RhoOfSig(sigma[ii])); |
1243 |
|
|
} |
1244 |
|
|
if (_gageSetup(oscx)) { |
1245 |
|
|
biffAddf(GAGE, "%s: problem setting up gage", me); |
1246 |
|
|
return 1; |
1247 |
|
|
} |
1248 |
|
|
fprintf(stderr, "%s: plotting ... ", me); fflush(stderr); |
1249 |
|
|
for (ii=0; ii<oscx->trueImgNum; ii++) { |
1250 |
|
|
double rho, err; |
1251 |
|
|
fprintf(stderr, "%s", airDoneStr(0, ii, oscx->trueImgNum, doneStr)); |
1252 |
|
|
fflush(stderr); |
1253 |
|
|
rho = AIR_AFFINE(0, ii, oscx->trueImgNum-1, |
1254 |
|
|
oscx->rhoRange[0], oscx->rhoRange[1]); |
1255 |
|
|
out[0 + 2*ii] = rho; |
1256 |
|
|
/* debugii = ii; */ |
1257 |
|
|
if (_errSingle(&err, oscx, rho)) { |
1258 |
|
|
biffAddf(GAGE, "%s: plotting %u", me, ii); |
1259 |
|
|
return 1; |
1260 |
|
|
} |
1261 |
|
|
out[1 + 2*ii] = err; |
1262 |
|
|
/* |
1263 |
|
|
if (AIR_IN_CL(69,ii,71)) { |
1264 |
|
|
fprintf(stderr, "!%s: ----- %u : %g\n", me, ii, err); |
1265 |
|
|
} |
1266 |
|
|
*/ |
1267 |
|
|
} |
1268 |
|
|
fprintf(stderr, "%s\n", airDoneStr(0, ii, oscx->trueImgNum, doneStr)); |
1269 |
|
|
|
1270 |
|
|
/* |
1271 |
|
|
if (0) { |
1272 |
|
|
static unsigned int call=0; |
1273 |
|
|
char fname[AIR_STRLEN_SMALL]; |
1274 |
|
|
unsigned int ni; |
1275 |
|
|
if (0) { |
1276 |
|
|
sprintf(fname, "err-%04u.nrrd", call); |
1277 |
|
|
nrrdSave(fname, oscx->nerr, NULL); |
1278 |
|
|
} |
1279 |
|
|
if (debugging) { |
1280 |
|
|
for (ni=0; ni<oscx->sampleNum; ni++) { |
1281 |
|
|
sprintf(fname, "sample-%04u.nrrd", ni); |
1282 |
|
|
nrrdSave(fname, oscx->nsampleImg[ni], NULL); |
1283 |
|
|
} |
1284 |
|
|
} |
1285 |
|
|
call++; |
1286 |
|
|
debugging = (2 == call); |
1287 |
|
|
} |
1288 |
|
|
*/ |
1289 |
|
|
|
1290 |
|
|
return 0; |
1291 |
|
|
} |
1292 |
|
|
|
1293 |
|
|
int |
1294 |
|
|
gageOptimSigErrorPlotSliding(gageOptimSigContext *oscx, Nrrd *nout, |
1295 |
|
|
double windowRho, |
1296 |
|
|
unsigned int sampleNum, |
1297 |
|
|
const NrrdKernelSpec *kssSpec, |
1298 |
|
|
int imgMeasr) { |
1299 |
|
|
static const char me[]="gageOptimSigRecondErrorPlotSliding"; |
1300 |
|
|
char doneStr[AIR_STRLEN_SMALL]; |
1301 |
|
|
unsigned int ii; |
1302 |
|
|
double *out; |
1303 |
|
|
char hackKeyStr[]="TEEM_OPTSIG_RECONERR"; |
1304 |
|
|
|
1305 |
|
|
if (!( oscx && nout && kssSpec )) { |
1306 |
|
|
biffAddf(GAGE, "%s: got NULL pointer", me); |
1307 |
|
|
return 1; |
1308 |
|
|
} |
1309 |
|
|
if (windowRho <= 0) { |
1310 |
|
|
biffAddf(GAGE, "%s: need positive windowRho (not %g)", me, windowRho); |
1311 |
|
|
return 1; |
1312 |
|
|
} |
1313 |
|
|
if (windowRho > oscx->rhoRange[1] - oscx->rhoRange[0]) { |
1314 |
|
|
biffAddf(GAGE, "%s: window %g > rhorange %g-%g=%g", me, |
1315 |
|
|
windowRho, oscx->rhoRange[1], oscx->rhoRange[0], |
1316 |
|
|
oscx->rhoRange[1] - oscx->rhoRange[0]); |
1317 |
|
|
return 1; |
1318 |
|
|
} |
1319 |
|
|
|
1320 |
|
|
if (nrrdGetenvString(&debugReconErrName, hackKeyStr)) { |
1321 |
|
|
fprintf(stderr, "%s: %s hack on: will save recon results to %s\n", |
1322 |
|
|
me, hackKeyStr, debugReconErrName); |
1323 |
|
|
debugReconErrArr = airArrayNew(AIR_CAST(void **, &(debugReconErr)), NULL, |
1324 |
|
|
sizeof(double), 1000); |
1325 |
|
|
} |
1326 |
|
|
|
1327 |
|
|
/* copy remaining input parms */ |
1328 |
|
|
nrrdKernelSpecNix(oscx->kssSpec); |
1329 |
|
|
oscx->kssSpec = nrrdKernelSpecCopy(kssSpec); |
1330 |
|
|
oscx->sampleNum = 3; /* hacky */ |
1331 |
|
|
oscx->maxIter = 0; |
1332 |
|
|
oscx->imgMeasr = imgMeasr; |
1333 |
|
|
oscx->allMeasr = nrrdMeasureUnknown; |
1334 |
|
|
oscx->convEps = AIR_NAN; |
1335 |
|
|
oscx->sampleSigma[0] = oscx->sigmaRange[0]; /* just for gage setup */ |
1336 |
|
|
oscx->sampleSigma[1] = oscx->sigmaRange[1]; /* just for gage setup */ |
1337 |
|
|
oscx->sampleSigma[2] = oscx->sigmaRange[1]+1; |
1338 |
|
|
if (_gageSetup(oscx)) { |
1339 |
|
|
biffAddf(GAGE, "%s: problem setting up gage", me); |
1340 |
|
|
return 1; |
1341 |
|
|
} |
1342 |
|
|
if (nrrdMaybeAlloc_va(nout, nrrdTypeDouble, 2, |
1343 |
|
|
AIR_CAST(size_t, 2), |
1344 |
|
|
AIR_CAST(size_t, sampleNum))) { |
1345 |
|
|
biffMovef(GAGE, NRRD, "%s: trouble allocating output", me); |
1346 |
|
|
return 1; |
1347 |
|
|
} |
1348 |
|
|
out = AIR_CAST(double *, nout->data); |
1349 |
|
|
fprintf(stderr, "%s: plotting ... ", me); fflush(stderr); |
1350 |
|
|
for (ii=0; ii<sampleNum; ii++) { |
1351 |
|
|
double rho, rlo, rhi, err; |
1352 |
|
|
fprintf(stderr, "%s", airDoneStr(0, ii, oscx->trueImgNum, doneStr)); |
1353 |
|
|
fflush(stderr); |
1354 |
|
|
rho = AIR_AFFINE(0, ii, sampleNum, |
1355 |
|
|
oscx->rhoRange[0], oscx->rhoRange[1]); |
1356 |
|
|
rlo = rho - windowRho/2; |
1357 |
|
|
rhi = rho + windowRho/2; |
1358 |
|
|
if (rlo < oscx->rhoRange[0] |
1359 |
|
|
|| rhi > oscx->rhoRange[1]) { |
1360 |
|
|
if (debugReconErrArr) { |
1361 |
|
|
/* we have to simulate the updates to debugReconErrArr |
1362 |
|
|
that would happen with a call to _errSingle */ |
1363 |
|
|
airArrayLenIncr(debugReconErrArr, 2*oscx->sz*oscx->sy*oscx->sx); |
1364 |
|
|
} |
1365 |
|
|
out[0 + 2*ii] = _SigOfRho(rho); |
1366 |
|
|
out[1 + 2*ii] = AIR_NAN; |
1367 |
|
|
continue; |
1368 |
|
|
} |
1369 |
|
|
/* required samples will slide along with plotting */ |
1370 |
|
|
_sampleSet(oscx, 0, rlo); |
1371 |
|
|
_sampleSet(oscx, 1, rhi); |
1372 |
|
|
if (_errSingle(&err, oscx, rho)) { |
1373 |
|
|
biffAddf(GAGE, "%s: plotting/sliding %u", me, ii); |
1374 |
|
|
return 1; |
1375 |
|
|
} |
1376 |
|
|
out[0 + 2*ii] = _SigOfRho(rho); |
1377 |
|
|
out[1 + 2*ii] = err; |
1378 |
|
|
} |
1379 |
|
|
fprintf(stderr, "%s\n", airDoneStr(0, ii, oscx->trueImgNum, doneStr)); |
1380 |
|
|
|
1381 |
|
|
if (debugReconErrArr) { |
1382 |
|
|
Nrrd *nre = nrrdNew(); |
1383 |
|
|
nrrdWrap_va(nre, debugReconErr, nrrdTypeDouble, 3, |
1384 |
|
|
AIR_CAST(size_t, 2), |
1385 |
|
|
AIR_CAST(size_t, oscx->sz*oscx->sy*oscx->sx), |
1386 |
|
|
AIR_CAST(size_t, sampleNum)); |
1387 |
|
|
nrrdSave(debugReconErrName, nre, NULL); |
1388 |
|
|
nrrdNix(nre); |
1389 |
|
|
} |
1390 |
|
|
|
1391 |
|
|
|
1392 |
|
|
return 0; |
1393 |
|
|
} |
1394 |
|
|
|