File: | src/gage/optimsig.c |
Location: | line 328, column 5 |
Description: | Potential leak of memory pointed to by 'oscx' |
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((void*)0); | |||||
33 | static double *debugReconErr = NULL((void*)0); | |||||
34 | static char *debugReconErrName = NULL((void*)0); | |||||
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_MAX5 5 | |||||
61 | ||||||
62 | #define N-1 -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_MAX11][GAGE_OPTIMSIG_SAMPLES_MAXNUM11-1][GAGE_OPTIMSIG_SAMPLES_MAXNUM11] = { | |||||
89 | { | |||||
90 | {0,1,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
91 | {0,0.5279398,1,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
92 | {0,0.30728838,0.59967405,1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
93 | {0,0.25022203,0.47050092,0.69525677,1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
94 | {0,0.17127343,0.39234546,0.56356072,0.75660759,1,N-1,N-1,N-1,N-1,N-1}, | |||||
95 | {0,0.16795139,0.37100673,0.51324213,0.65655005,0.81952846,1,N-1,N-1,N-1,N-1}, | |||||
96 | {0,0.1662873,0.34969759,0.46556041,0.55324608,0.68717259,0.83465695,1,N-1,N-1,N-1}, | |||||
97 | {0,0.12720504,0.22565289,0.28316727,0.44209728,0.58615023,0.75034028,0.87391609,1,N-1,N-1}, | |||||
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-1}, | |||||
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-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
102 | {0,0.75118494,2,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
103 | {0,0.55478472,1.1535828,2,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
104 | {0,0.49007216,0.8412028,1.308665,2,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
105 | {0,0.29460263,0.57445061,0.93797231,1.368475,2,N-1,N-1,N-1,N-1,N-1}, | |||||
106 | {0,0.2506085,0.49080029,0.73882496,1.069332,1.4497081,2,N-1,N-1,N-1,N-1}, | |||||
107 | {0,0.18255657,0.42056954,0.62766695,0.87999368,1.1692151,1.5175625,2,N-1,N-1,N-1}, | |||||
108 | {0,0.17582123,0.40522173,0.58696139,0.79624867,1.0485514,1.2950466,1.5977446,2,N-1,N-1}, | |||||
109 | {0,0.17304537,0.39376548,0.56427032,0.75127059,0.96672511,1.187861,1.4141362,1.6921321,2,N-1}, | |||||
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-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
113 | {0,0.92324787,3,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
114 | {0,0.59671402,1.3871731,3,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
115 | {0,0.53303385,1.0274624,1.6725048,3,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
116 | {0,0.47298154,0.79659319,1.2379739,1.8434249,3,N-1,N-1,N-1,N-1,N-1}, | |||||
117 | {0,0.29337707,0.56664073,0.94871783,1.3666322,1.949043,3,N-1,N-1,N-1,N-1}, | |||||
118 | {0,0.25583801,0.52919179,0.78387552,1.1250161,1.516176,2.0632432,3,N-1,N-1,N-1}, | |||||
119 | {0,0.25013804,0.48255014,0.72428173,1.0308567,1.3638159,1.7629964,2.2885511,3,N-1,N-1}, | |||||
120 | {0,0.25038671,0.46448985,0.67336935,0.94502586,1.2324173,1.5780864,1.9883285,2.5002999,3,N-1}, | |||||
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-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
124 | {0,1.0342592,4,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
125 | {0,0.6341188,1.5414433,4,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
126 | {0,0.5523203,1.1400089,1.9595566,4,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
127 | {0,0.51082283,0.91567439,1.4275582,2.2504199,4,N-1,N-1,N-1,N-1,N-1}, | |||||
128 | {0,0.46390373,0.76406777,1.1620381,1.6579833,2.470386,4,N-1,N-1,N-1,N-1}, | |||||
129 | {0,0.29957226,0.58226484,0.90447241,1.318499,1.8011117,2.5972142,4,N-1,N-1,N-1}, | |||||
130 | {0,0.29072434,0.5657317,0.8687849,1.2413157,1.7351674,2.2752147,3.1038468,4,N-1,N-1}, | |||||
131 | {0,0.25000414,0.5027808,0.75375289,1.0744231,1.4267329,1.8665372,2.4665236,3.2203004,4,N-1}, | |||||
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-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
135 | {0,1.1176668,5,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
136 | {0,0.66791451,1.6688319,5,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
137 | {0,0.56513244,1.2151262,2.2046661,5,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
138 | {0,0.51955444,0.96157616,1.5293243,2.5639,5,N-1,N-1,N-1,N-1,N-1}, | |||||
139 | {0,0.50639188,0.83235806,1.2596023,1.8475783,2.8751452,5,N-1,N-1,N-1,N-1}, | |||||
140 | {0,0.30821687,0.60048282,1.0057166,1.4351804,2.0372179,3.0747592,5,N-1,N-1,N-1}, | |||||
141 | {0,0.28437388,0.560866,0.92278755,1.3049414,1.7620444,2.4607313,3.5198457,5,N-1,N-1}, | |||||
142 | {0,0.26883101,0.53947717,0.84076571,1.1986721,1.6077875,2.165575,2.9591467,3.931181,5,N-1}, | |||||
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-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
146 | {0,1.185726,6,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
147 | {0,0.69637311,1.7772807,6,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
148 | {0,0.57470578,1.2709187,2.4227901,6,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
149 | {0,0.52996641,1.0128419,1.632214,2.8718762,6,N-1,N-1,N-1,N-1,N-1}, | |||||
150 | {0,0.50426048,0.87729794,1.3428378,2.0053113,3.2981832,6,N-1,N-1,N-1,N-1}, | |||||
151 | {0,0.46658435,0.76617205,1.1726109,1.6950468,2.5514688,4.1463666,6,N-1,N-1,N-1}, | |||||
152 | {0,0.50030917,0.78596908,1.1486269,1.5887094,2.2150676,3.2805684,4.4828262,6,N-1,N-1}, | |||||
153 | {0,0.27919531,0.56878412,0.88591647,1.2631332,1.7201432,2.3851209,3.392889,4.6255312,6,N-1}, | |||||
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-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
157 | {0,1.2437892,7,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
158 | {0,0.72099203,1.8771845,7,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
159 | {0,0.58251196,1.3139123,2.6157444,7,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
160 | {0,0.5371021,1.0473768,1.7166929,3.1448426,7,N-1,N-1,N-1,N-1,N-1}, | |||||
161 | {0,0.51312029,0.92989367,1.4221185,2.2125893,3.6739931,7,N-1,N-1,N-1,N-1}, | |||||
162 | {0,0.50083971,0.84841007,1.2561073,1.8532455,2.8668625,4.7535434,7,N-1,N-1,N-1}, | |||||
163 | {0,0.3375614,0.63945627,1.0301709,1.4884938,2.073761,3.1614799,5.0744987,7,N-1,N-1}, | |||||
164 | {0,0.29428458,0.58668923,0.93714356,1.3736334,1.8300356,2.6405344,3.9042048,5.3097196,7,N-1}, | |||||
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-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
168 | {0,1.2942501,8,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
169 | {0,0.74332041,1.9693407,8,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
170 | {0,0.58823597,1.3483386,2.7880962,8,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
171 | {0,0.56661958,1.2263036,1.9593971,3.6037345,8,N-1,N-1,N-1,N-1,N-1}, | |||||
172 | {0,0.52106231,0.97026396,1.486012,2.3670862,4.1632919,8,N-1,N-1,N-1,N-1}, | |||||
173 | {0,0.50727636,0.86810225,1.3293955,2.0115428,3.1358411,5.3943086,8,N-1,N-1,N-1}, | |||||
174 | {0,0.47202346,0.77812189,1.1608884,1.6648751,2.4694417,3.9094045,5.7665443,8,N-1,N-1}, | |||||
175 | {0,0.37446901,0.66116196,1.038642,1.4625595,2.0528309,2.9814169,4.4429126,5.9815373,8,N-1}, | |||||
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-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
179 | {0,1.3413963,9,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
180 | {0,0.76222414,2.0542119,9,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
181 | {0,0.59559792,1.3777219,2.946173,9,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
182 | {0,0.56240517,1.1527119,1.9145473,3.6841569,9,N-1,N-1,N-1,N-1,N-1}, | |||||
183 | {0,0.52387071,0.98832464,1.5376476,2.5417714,4.4669261,9,N-1,N-1,N-1,N-1}, | |||||
184 | {0,0.50359035,0.87327009,1.3558764,2.0646384,3.3180211,5.9420524,9,N-1,N-1,N-1}, | |||||
185 | {0,0.50140077,0.83020425,1.256588,1.7709454,2.7100441,4.4434023,6.3934889,9,N-1,N-1}, | |||||
186 | {0,0.36521655,0.65757704,1.0627806,1.5081434,2.1497617,3.1920822,4.870122,6.6418982,9,N-1}, | |||||
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-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
190 | {0,1.3838946,10,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
191 | {0,0.77946955,2.1342247,10,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
192 | {0,0.60070014,1.4040204,3.0944126,10,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
193 | {0,0.55609542,1.1508646,1.9495349,3.9375696,10,N-1,N-1,N-1,N-1,N-1}, | |||||
194 | {0,0.5350194,1.031119,1.6607633,2.8520992,5.4718146,10,N-1,N-1,N-1,N-1}, | |||||
195 | {0,0.5083549,0.90783268,1.4059756,2.1796026,3.571064,6.5497985,10,N-1,N-1,N-1}, | |||||
196 | {0,0.50199872,0.85233968,1.2647815,1.8777326,2.8592849,4.7821364,7.0110598,10,N-1,N-1}, | |||||
197 | {0,0.46663594,0.75212663,1.1302133,1.6134665,2.3560972,3.6558499,5.3189116,7.2945781,10,N-1}, | |||||
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-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
201 | {0,1.4234025,11,N-1,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
202 | {0,0.79513794,2.2098076,11,N-1,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
203 | {0,0.60728961,1.4287171,3.2358651,11,N-1,N-1,N-1,N-1,N-1,N-1}, | |||||
204 | {0,0.55890071,1.165283,2.0149148,4.1530919,11,N-1,N-1,N-1,N-1,N-1}, | |||||
205 | {0,0.55071467,1.0660659,1.7177736,3.0094495,6.0395317,11,N-1,N-1,N-1,N-1}, | |||||
206 | {0,0.5066433,0.89661205,1.4050072,2.2117786,3.7080047,7.0954437,11,N-1,N-1,N-1}, | |||||
207 | {0,0.50242329,0.86727452,1.3264461,1.9118301,2.9509099,5.1184769,7.624764,11,N-1,N-1}, | |||||
208 | {0,0.47785854,0.78873962,1.1769236,1.6880652,2.4978926,4.0288033,5.7288432,7.9420485,11,N-1}, | |||||
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 | if (!scale) { | |||||
222 | biffAddf(GAGEgageBiffKey, "%s: got NULL pointer", me); | |||||
223 | return 1; | |||||
224 | } | |||||
225 | if (!AIR_IN_CL(2, num, GAGE_OPTIMSIG_SAMPLES_MAXNUM)((2) <= (num) && (num) <= (11))) { | |||||
226 | biffAddf(GAGEgageBiffKey, | |||||
227 | "%s: requested # sigma samples %u not in known range [2,%u]", | |||||
228 | me, num, GAGE_OPTIMSIG_SAMPLES_MAXNUM11); | |||||
229 | return 1; | |||||
230 | } | |||||
231 | if (!AIR_IN_CL(1, sigmaMax, GAGE_OPTIMSIG_SIGMA_MAX)((1) <= (sigmaMax) && (sigmaMax) <= (11))) { | |||||
232 | biffAddf(GAGEgageBiffKey, "%s: requested sigma max %u not in known range [1,%u]", | |||||
233 | me, sigmaMax, GAGE_OPTIMSIG_SIGMA_MAX11); | |||||
234 | return 1; | |||||
235 | } | |||||
236 | ||||||
237 | for (si=0; si<num; si++) { | |||||
238 | scale[si] = _optimSigTable[sigmaMax-1][num-2][si]; | |||||
239 | } | |||||
240 | return 0; | |||||
241 | } | |||||
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)(gageOptimSigContext*)(calloc((1), sizeof(gageOptimSigContext ))); | |||||
| ||||||
323 | if (!oscx) { | |||||
324 | biffAddf(GAGEgageBiffKey, "%s: couldn't allocate context", me); | |||||
325 | return NULL((void*)0); | |||||
326 | } | |||||
327 | if (!AIR_IN_CL(1, dim, 3)((1) <= (dim) && (dim) <= (3))) { | |||||
328 | biffAddf(GAGEgageBiffKey, "%s: dim %u not 1, 2, or 3", me, dim); | |||||
| ||||||
329 | return NULL((void*)0); | |||||
330 | } | |||||
331 | if (!(sampleNumMax >= 3)) { | |||||
332 | biffAddf(GAGEgageBiffKey, "%s: sampleNumMax %u not >= 3", me, sampleNumMax); | |||||
333 | return NULL((void*)0); | |||||
334 | } | |||||
335 | if (!(trueImgNum >= 3)) { | |||||
336 | biffAddf(GAGEgageBiffKey, "%s: trueImgNum %u not >= 3", me, trueImgNum); | |||||
337 | return NULL((void*)0); | |||||
338 | } | |||||
339 | if (!(sigmaMin >= 0 && sigmaMax > sigmaMin && cutoff > 0)) { | |||||
340 | biffAddf(GAGEgageBiffKey, "%s: sigmaMin %g, sigmaMax %g, cutoff %g not valid", me, | |||||
341 | sigmaMin, sigmaMax, cutoff); | |||||
342 | return NULL((void*)0); | |||||
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((void*)0); | |||||
354 | oscx->sampleNum = 0; | |||||
355 | oscx->maxIter = 0; | |||||
356 | oscx->imgMeasr = nrrdMeasureUnknown; | |||||
357 | oscx->allMeasr = nrrdMeasureUnknown; | |||||
358 | oscx->convEps = AIR_NAN(airFloatQNaN.f); | |||||
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))((int)(floor((nrrdKernelDiscreteGaussian->support(kparm))+ 0.5))); | |||||
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)((size_t)(oscx->trueImgNum))) | |||||
377 | || nrrdMaybeAlloc_va(oscx->ninterp, nrrdTypeDouble, 3, | |||||
378 | AIR_CAST(size_t, oscx->sx)((size_t)(oscx->sx)), | |||||
379 | AIR_CAST(size_t, oscx->sy)((size_t)(oscx->sy)), | |||||
380 | AIR_CAST(size_t, oscx->sz)((size_t)(oscx->sz))) | |||||
381 | || nrrdMaybeAlloc_va(oscx->ndiff, nrrdTypeDouble, 3, | |||||
382 | AIR_CAST(size_t, oscx->sx)((size_t)(oscx->sx)), | |||||
383 | AIR_CAST(size_t, oscx->sy)((size_t)(oscx->sy)), | |||||
384 | AIR_CAST(size_t, oscx->sz)((size_t)(oscx->sz)))) { | |||||
385 | biffMovef(GAGEgageBiffKey, NRRDnrrdBiffKey, "%s: couldn't allocate buffers", me); | |||||
386 | return NULL((void*)0); | |||||
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__stderrp, "!%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__stderrp, "!%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,( ((double)(oscx->rhoRange[1])-(oscx->rhoRange[0]))*((double )(ii)-(0)) / ((double)(oscx->trueImgNum-1)-(0)) + (oscx-> rhoRange[0])) | |||||
407 | oscx->rhoRange[0], oscx->rhoRange[1])( ((double)(oscx->rhoRange[1])-(oscx->rhoRange[0]))*((double )(ii)-(0)) / ((double)(oscx->trueImgNum-1)-(0)) + (oscx-> rhoRange[0])); | |||||
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 - rc) > 0.0f ? (rr - rc) : -(rr - rc))/(rr + eps) > eps ) { | |||||
415 | biffAddf(GAGEgageBiffKey, "%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 - rc) > 0.0f ? (rr - rc) : -(rr - rc))/(rr + eps/2), eps); | |||||
418 | return NULL((void*)0); | |||||
419 | } | |||||
420 | } | |||||
421 | ||||||
422 | oscx->kloc = AIR_CALLOC(oscx->sx, double)(double*)(calloc((oscx->sx), sizeof(double))); | |||||
423 | oscx->kern = AIR_CALLOC(oscx->sx, double)(double*)(calloc((oscx->sx), sizeof(double))); | |||||
424 | oscx->ktmp1 = AIR_CALLOC(oscx->sx, double)(double*)(calloc((oscx->sx), sizeof(double))); | |||||
425 | oscx->ktmp2 = AIR_CALLOC(oscx->sx, double)(double*)(calloc((oscx->sx), sizeof(double))); | |||||
426 | if (!(oscx->kloc && oscx->kern && oscx->ktmp1 && oscx->ktmp2)) { | |||||
427 | biffAddf(GAGEgageBiffKey, "%s: couldn't allocate kernel buffers", me); | |||||
428 | return NULL((void*)0); | |||||
429 | } | |||||
430 | for (ii=0; ii<oscx->sx; ii++) { | |||||
431 | oscx->kloc[ii] = AIR_CAST(double, ii)((double)(ii)) - ((oscx->sx + 1)/2 - 1); | |||||
432 | } | |||||
433 | oscx->kone[0] = 1.0; | |||||
434 | ||||||
435 | oscx->gctx = NULL((void*)0); | |||||
436 | oscx->pvlBase = NULL((void*)0); | |||||
437 | oscx->pvlSS = AIR_CALLOC(oscx->sampleNumMax, gagePerVolume *)(gagePerVolume **)(calloc((oscx->sampleNumMax), sizeof(gagePerVolume *))); | |||||
438 | oscx->nsampleImg = AIR_CALLOC(oscx->sampleNumMax, Nrrd *)(Nrrd **)(calloc((oscx->sampleNumMax), sizeof(Nrrd *))); | |||||
439 | oscx->sampleSigma = AIR_CALLOC(oscx->sampleNumMax, double)(double*)(calloc((oscx->sampleNumMax), sizeof(double))); | |||||
440 | oscx->sampleRho = AIR_CALLOC(oscx->sampleNumMax, double)(double*)(calloc((oscx->sampleNumMax), sizeof(double))); | |||||
441 | oscx->sampleTmp = AIR_CALLOC(oscx->sampleNumMax, double)(double*)(calloc((oscx->sampleNumMax), sizeof(double))); | |||||
442 | oscx->sampleErrMax = AIR_CALLOC(oscx->sampleNumMax, double)(double*)(calloc((oscx->sampleNumMax), sizeof(double))); | |||||
443 | oscx->step = AIR_CALLOC(oscx->sampleNumMax, double)(double*)(calloc((oscx->sampleNumMax), sizeof(double))); | |||||
444 | if (!(oscx->pvlSS && oscx->nsampleImg | |||||
445 | && oscx->sampleSigma && oscx->sampleRho | |||||
446 | && oscx->sampleTmp && oscx->sampleErrMax && oscx->step)) { | |||||
447 | biffAddf(GAGEgageBiffKey, "%s: couldn't allocate per-sample arrays", me); | |||||
448 | return NULL((void*)0); | |||||
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)((size_t)(oscx->sx)), | |||||
454 | AIR_CAST(size_t, oscx->sy)((size_t)(oscx->sy)), | |||||
455 | AIR_CAST(size_t, oscx->sz)((size_t)(oscx->sz)))) { | |||||
456 | biffMovef(GAGEgageBiffKey, NRRDnrrdBiffKey, "%s: couldn't allocate vol[%u]", me, ii); | |||||
457 | return NULL((void*)0); | |||||
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((void*)0); | |||||
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)((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_TRUE1 /* index space */, | |||||
526 | AIR_TRUE1 /* clamping */)) { | |||||
527 | biffAddf(GAGEgageBiffKey, "%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_NUM8], | |||||
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_MAX5) { | |||||
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_MAX5; | |||||
576 | dg->evalN_d(kern, kloc, sx, kparm); | |||||
577 | timeleft = sig*sig - GOOD_SIGMA_MAX5*GOOD_SIGMA_MAX5; | |||||
578 | do { | |||||
579 | tdelta = AIR_MIN( GOOD_SIGMA_MAX*GOOD_SIGMA_MAX, timeleft )((5*5) < (timeleft) ? (5*5) : (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)((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(GAGEgageBiffKey, "%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)((const double *)(oscx->ninterp->data)); | |||||
654 | diff = AIR_CAST(double *, oscx->ndiff->data)((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(airFloatQNaN.f), AIR_NAN(airFloatQNaN.f)); | |||||
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)((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,( ((double)(oscx->rhoRange[1])-(oscx->rhoRange[0]))*((double )(ii)-(0)) / ((double)(oscx->trueImgNum-1)-(0)) + (oscx-> rhoRange[0])) | |||||
689 | oscx->rhoRange[0],( ((double)(oscx->rhoRange[1])-(oscx->rhoRange[0]))*((double )(ii)-(0)) / ((double)(oscx->trueImgNum-1)-(0)) + (oscx-> rhoRange[0])) | |||||
690 | oscx->rhoRange[1])( ((double)(oscx->rhoRange[1])-(oscx->rhoRange[0]))*((double )(ii)-(0)) / ((double)(oscx->trueImgNum-1)-(0)) + (oscx-> rhoRange[0])))) { | |||||
691 | biffAddf(GAGEgageBiffKey, "%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(airFloatQNaN.f), AIR_NAN(airFloatQNaN.f)); | |||||
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(128+1)]; | |||||
712 | sprintf(fname, "err-%04u.nrrd", call)__builtin___sprintf_chk (fname, 0, __builtin_object_size (fname , 2 > 1 ? 1 : 0), "err-%04u.nrrd", call); | |||||
713 | nrrdSave(fname, oscx->nerr, NULL((void*)0)); | |||||
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)((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])( ((double)(rr[1])-(rr[0]))*((double)(ii)-(0)) / ((double)(oscx ->trueImgNum-1)-(0)) + (rr[0])); | |||||
738 | if (_errSingle(err + ii, oscx, rho)) { | |||||
739 | biffAddf(GAGEgageBiffKey, "%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)((unsigned int)(pid)); | |||||
745 | if (outside || !(pi <= oscx->sampleNum-2)) { | |||||
746 | biffAddf(GAGEgageBiffKey, "%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])((sem[pi]) > (err[ii]) ? (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(128+1)]; | |||||
770 | sprintf(fname, "err-%04u.nrrd", call)__builtin___sprintf_chk (fname, 0, __builtin_object_size (fname , 2 > 1 ? 1 : 0), "err-%04u.nrrd", call); | |||||
771 | nrrdSave(fname, oscx->nerr, NULL((void*)0)); | |||||
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_NUM8]; | |||||
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_FALSE0); | |||||
792 | gageParmSet(oscx->gctx, gageParmCheckIntegrals, AIR_FALSE0); | |||||
793 | gageParmSet(oscx->gctx, gageParmOrientationFromSpacing, AIR_TRUE1); | |||||
794 | gageParmSet(oscx->gctx, gageParmStackUse, AIR_TRUE1); | |||||
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*,((const Nrrd*const*)(oscx->nsampleImg)) | |||||
801 | oscx->nsampleImg)((const Nrrd*const*)(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(GAGEgageBiffKey, "%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(256+1)], double deltim) { | |||||
822 | ||||||
823 | if (deltim < 60) { | |||||
824 | sprintf(tstr, "%g secs", deltim)__builtin___sprintf_chk (tstr, 0, __builtin_object_size (tstr , 2 > 1 ? 1 : 0), "%g secs", deltim); | |||||
825 | return tstr; | |||||
826 | } | |||||
827 | deltim /= 60; | |||||
828 | if (deltim < 60) { | |||||
829 | sprintf(tstr, "%g mins", deltim)__builtin___sprintf_chk (tstr, 0, __builtin_object_size (tstr , 2 > 1 ? 1 : 0), "%g mins", deltim); | |||||
830 | return tstr; | |||||
831 | } | |||||
832 | deltim /= 60; | |||||
833 | if (deltim < 24) { | |||||
834 | sprintf(tstr, "%g hours", deltim)__builtin___sprintf_chk (tstr, 0, __builtin_object_size (tstr , 2 > 1 ? 1 : 0), "%g hours", deltim); | |||||
835 | return tstr; | |||||
836 | } | |||||
837 | deltim /= 24; | |||||
838 | if (deltim < 7) { | |||||
839 | sprintf(tstr, "%g days", deltim)__builtin___sprintf_chk (tstr, 0, __builtin_object_size (tstr , 2 > 1 ? 1 : 0), "%g days", deltim); | |||||
840 | return tstr; | |||||
841 | } | |||||
842 | deltim /= 7; | |||||
843 | sprintf(tstr, "%g weeks", deltim)__builtin___sprintf_chk (tstr, 0, __builtin_object_size (tstr , 2 > 1 ? 1 : 0), "%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(256+1)]; | |||||
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(GAGEgageBiffKey, "%s: first error measurement", me); | |||||
870 | return 1; | |||||
871 | } | |||||
872 | fprintf(stderr__stderrp, "%s: (%s for initial error measr)\n", me, | |||||
873 | _timefmt(tstr, airTime() - time0)); | |||||
874 | newErr = AIR_NAN(airFloatQNaN.f); | |||||
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))((int)(airRandInt(2))) - 1; | |||||
890 | pnt = 1 + (iter % (oscx->sampleNum-2)); | |||||
891 | lastPos = oscx->sampleRho[pnt]; | |||||
892 | fprintf(stderr__stderrp, "%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,(((oscx->sampleRho[pnt] - oscx->sampleRho[pnt-1])/3) < ((oscx->sampleRho[pnt+1] - oscx->sampleRho[pnt])/3) ? ( (oscx->sampleRho[pnt] - oscx->sampleRho[pnt-1])/3) : (( oscx->sampleRho[pnt+1] - oscx->sampleRho[pnt])/3)) | |||||
895 | (oscx->sampleRho[pnt+1] - oscx->sampleRho[pnt])/3)(((oscx->sampleRho[pnt] - oscx->sampleRho[pnt-1])/3) < ((oscx->sampleRho[pnt+1] - oscx->sampleRho[pnt])/3) ? ( (oscx->sampleRho[pnt] - oscx->sampleRho[pnt-1])/3) : (( oscx->sampleRho[pnt+1] - oscx->sampleRho[pnt])/3)); | |||||
896 | fprintf(stderr__stderrp, ". pnt %u: pos %g, step %g\n", | |||||
897 | pnt, lastPos, oscx->step[pnt]); | |||||
898 | fprintf(stderr__stderrp, ". 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(GAGEgageBiffKey, "%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__stderrp, ". grad = %g\n", grad); | |||||
910 | delta = -grad*oscx->step[pnt]; | |||||
911 | if (!AIR_EXISTS(delta)(((int)(!((delta) - (delta)))))) { | |||||
912 | biffAddf(GAGEgageBiffKey, "%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)((delta) > 0.0f ? (delta) : -(delta)) > limit) { | |||||
917 | oscx->step[pnt] *= limit/AIR_ABS(delta)((delta) > 0.0f ? (delta) : -(delta)); | |||||
918 | fprintf(stderr__stderrp, ". step *= %g/%g -> %g\n", | |||||
919 | limit, AIR_ABS(delta)((delta) > 0.0f ? (delta) : -(delta)), oscx->step[pnt]); | |||||
920 | delta = -grad*oscx->step[pnt]; | |||||
921 | } | |||||
922 | fprintf(stderr__stderrp, ". delta = %g\n", delta); | |||||
923 | tryi = 0; | |||||
924 | badStep = AIR_FALSE0; | |||||
925 | do { | |||||
926 | if (tryi == oscx->maxIter) { | |||||
927 | biffAddf(GAGEgageBiffKey, "%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__stderrp, "... try %u: delta = 0; nothing to do\n", tryi); | |||||
933 | newErr = lastErr; | |||||
934 | zerodelta = AIR_TRUE1; | |||||
935 | } else { | |||||
936 | zerodelta = AIR_FALSE0; | |||||
937 | _sampleSet(oscx, pnt, lastPos + delta); | |||||
938 | if (_errTotal(&newErr, oscx)) { | |||||
939 | biffAddf(GAGEgageBiffKey, "%s: for newErr (%u -> %.17g)", me, | |||||
940 | pnt, lastPos + delta); | |||||
941 | return 1; | |||||
942 | } | |||||
943 | badStep = newErr > lastErr; | |||||
944 | fprintf(stderr__stderrp, "... 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__stderrp, "... !! 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_FALSE0; | |||||
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,( ((double)((lastErr - newErr)/lastErr)-(decavg))*((double)(1 )-(0)) / ((double)(oscx->sampleNum)-(0)) + (decavg)) | |||||
969 | decavg, (lastErr - newErr)/lastErr)( ((double)((lastErr - newErr)/lastErr)-(decavg))*((double)(1 )-(0)) / ((double)(oscx->sampleNum)-(0)) + (decavg)); | |||||
970 | oscx->step[pnt] *= oppor; | |||||
971 | } | |||||
972 | if (decavg <= oscx->convEps) { | |||||
973 | fprintf(stderr__stderrp, "%s: converged (%g <= %g) after %u iters\n", me, | |||||
974 | decavg, oscx->convEps, iter); | |||||
975 | break; | |||||
976 | } else { | |||||
977 | fprintf(stderr__stderrp, "%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(GAGEgageBiffKey, "%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(256+1)]; | |||||
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(GAGEgageBiffKey, "%s: first error measurement", me); | |||||
1004 | return 1; | |||||
1005 | } | |||||
1006 | fprintf(stderr__stderrp, "%s: (init) min %u %g max %u %g\n", me, | |||||
1007 | mmIdx[0], mmErr[0], mmIdx[1], mmErr[1]); | |||||
1008 | fprintf(stderr__stderrp, "%s: (%s for initial error measr)\n", me, | |||||
1009 | _timefmt(tstr, airTime() - time0)); | |||||
1010 | newErr = AIR_NAN(airFloatQNaN.f); | |||||
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_FALSE0; | |||||
1036 | } else { | |||||
1037 | /* we will shrink gap around tallest peak */ | |||||
1038 | gap = mmIdx[1]; | |||||
1039 | gerr = mmErr[1]; | |||||
1040 | shrink = AIR_TRUE1; | |||||
1041 | } | |||||
1042 | midp = (srho[gap] + srho[gap+1])/2; | |||||
1043 | fprintf(stderr__stderrp, "%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_FALSE0; | |||||
1052 | do { | |||||
1053 | if (tryi == oscx->maxIter) { | |||||
1054 | biffAddf(GAGEgageBiffKey, "%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)( ((double)(midp)-(srho[gap]))*((double)(step)-(0)) / ((double )(1)-(0)) + (srho[gap])); | |||||
1060 | whi = AIR_AFFINE(0, step, 1, srho[gap+1], midp)( ((double)(midp)-(srho[gap+1]))*((double)(step)-(0)) / ((double )(1)-(0)) + (srho[gap+1])); | |||||
1061 | } else { | |||||
1062 | wlo = AIR_AFFINE(0, step, -2, srho[gap], midp)( ((double)(midp)-(srho[gap]))*((double)(step)-(0)) / ((double )(-2)-(0)) + (srho[gap])); | |||||
1063 | whi = AIR_AFFINE(0, step, -2, srho[gap+1], midp)( ((double)(midp)-(srho[gap+1]))*((double)(step)-(0)) / ((double )(-2)-(0)) + (srho[gap+1])); | |||||
1064 | } | |||||
1065 | glo = srho[gap]; | |||||
1066 | ghi = srho[gap+1]; | |||||
1067 | fprintf(stderr__stderrp, "%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,( ((double)(wlo)-(srho[0]))*((double)(srho[si])-(srho[0])) / ( (double)(glo)-(srho[0])) + (srho[0])) | |||||
1072 | srho[0], wlo)( ((double)(wlo)-(srho[0]))*((double)(srho[si])-(srho[0])) / ( (double)(glo)-(srho[0])) + (srho[0])) | |||||
1073 | : AIR_AFFINE(ghi, srho[si], srho[sn-1],( ((double)(srho[sn-1])-(whi))*((double)(srho[si])-(ghi)) / ( (double)(srho[sn-1])-(ghi)) + (whi)) | |||||
1074 | whi, srho[sn-1])( ((double)(srho[sn-1])-(whi))*((double)(srho[si])-(ghi)) / ( (double)(srho[sn-1])-(ghi)) + (whi)))); | |||||
1075 | } | |||||
1076 | if (_errTotalLinf(&newErr, | |||||
1077 | oscx, mmIdx, mmErr)) { | |||||
1078 | biffAddf(GAGEgageBiffKey, "%s: iter %u", me, iter); | |||||
1079 | return 1; | |||||
1080 | } | |||||
1081 | fprintf(stderr__stderrp, "%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__stderrp, "... 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)((0) < (decavg) && (decavg) < (ceps))) { | |||||
1103 | fprintf(stderr__stderrp, "%s: converged (%g <= %g) after %u iters\n", me, | |||||
1104 | decavg, ceps, iter); | |||||
1105 | break; | |||||
1106 | } else { | |||||
1107 | fprintf(stderr__stderrp, "%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(GAGEgageBiffKey, "%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(GAGEgageBiffKey, "%s: got NULL pointer", me); | |||||
1136 | return 1; | |||||
1137 | } | |||||
1138 | if (sigmaNum > oscx->sampleNumMax) { | |||||
1139 | biffAddf(GAGEgageBiffKey, "%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__stderrp, "%s: initializing %u samples ... ", me, oscx->sampleNum); | |||||
1147 | fflush(stderr__stderrp); | |||||
1148 | for (ii=0; ii<oscx->sampleNum; ii++) { | |||||
1149 | _sampleSet(oscx, ii, AIR_AFFINE(0, ii, oscx->sampleNum-1,( ((double)(oscx->rhoRange[1])-(oscx->rhoRange[0]))*((double )(ii)-(0)) / ((double)(oscx->sampleNum-1)-(0)) + (oscx-> rhoRange[0])) | |||||
1150 | oscx->rhoRange[0], oscx->rhoRange[1])( ((double)(oscx->rhoRange[1])-(oscx->rhoRange[0]))*((double )(ii)-(0)) / ((double)(oscx->sampleNum-1)-(0)) + (oscx-> rhoRange[0]))); | |||||
1151 | } | |||||
1152 | fprintf(stderr__stderrp, "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__stderrp, "%s: setting up gage ... \n", me); | |||||
1165 | if (_gageSetup(oscx)) { | |||||
1166 | biffAddf(GAGEgageBiffKey, "%s: problem setting up gage", me); | |||||
1167 | return 1; | |||||
1168 | } | |||||
1169 | fprintf(stderr__stderrp, "%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(GAGEgageBiffKey, "%s: trouble", me); | |||||
1179 | return 1; | |||||
1180 | } | |||||
1181 | } else { | |||||
1182 | fprintf(stderr__stderrp, "%s: num == 2, no optimization, finding error ... ", me); | |||||
1183 | fflush(stderr__stderrp); | |||||
1184 | if (_errTotal(&(oscx->finalErr), oscx)) { | |||||
1185 | biffAddf(GAGEgageBiffKey, "%s: for finalErr", me); | |||||
1186 | return 1; | |||||
1187 | } | |||||
1188 | fprintf(stderr__stderrp, "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(128+1)]; | |||||
1207 | double *out; | |||||
1208 | unsigned int ii; | |||||
1209 | ||||||
1210 | if (!(oscx && nout && sigma)) { | |||||
1211 | biffAddf(GAGEgageBiffKey, "%s: got NULL pointer", me); | |||||
1212 | return 1; | |||||
1213 | } | |||||
1214 | if (!( sigmaNum >= 2 )) { | |||||
1215 | biffAddf(GAGEgageBiffKey, "%s: need sigmaNum >= 2 (not %u)", me, sigmaNum); | |||||
1216 | return 1; | |||||
1217 | } | |||||
1218 | if (sigmaNum > oscx->sampleNumMax) { | |||||
1219 | biffAddf(GAGEgageBiffKey, "%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(airFloatQNaN.f); | |||||
1232 | if (nrrdMaybeAlloc_va(nout, nrrdTypeDouble, 2, | |||||
1233 | AIR_CAST(size_t, 2)((size_t)(2)), | |||||
1234 | AIR_CAST(size_t, oscx->trueImgNum)((size_t)(oscx->trueImgNum)))) { | |||||
1235 | biffMovef(GAGEgageBiffKey, NRRDnrrdBiffKey, "%s: trouble allocating output", me); | |||||
1236 | return 1; | |||||
1237 | } | |||||
1238 | out = AIR_CAST(double *, nout->data)((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(GAGEgageBiffKey, "%s: problem setting up gage", me); | |||||
1246 | return 1; | |||||
1247 | } | |||||
1248 | fprintf(stderr__stderrp, "%s: plotting ... ", me); fflush(stderr__stderrp); | |||||
1249 | for (ii=0; ii<oscx->trueImgNum; ii++) { | |||||
1250 | double rho, err; | |||||
1251 | fprintf(stderr__stderrp, "%s", airDoneStr(0, ii, oscx->trueImgNum, doneStr)); | |||||
1252 | fflush(stderr__stderrp); | |||||
1253 | rho = AIR_AFFINE(0, ii, oscx->trueImgNum-1,( ((double)(oscx->rhoRange[1])-(oscx->rhoRange[0]))*((double )(ii)-(0)) / ((double)(oscx->trueImgNum-1)-(0)) + (oscx-> rhoRange[0])) | |||||
1254 | oscx->rhoRange[0], oscx->rhoRange[1])( ((double)(oscx->rhoRange[1])-(oscx->rhoRange[0]))*((double )(ii)-(0)) / ((double)(oscx->trueImgNum-1)-(0)) + (oscx-> rhoRange[0])); | |||||
1255 | out[0 + 2*ii] = rho; | |||||
1256 | /* debugii = ii; */ | |||||
1257 | if (_errSingle(&err, oscx, rho)) { | |||||
1258 | biffAddf(GAGEgageBiffKey, "%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__stderrp, "%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(128+1)]; | |||||
1301 | unsigned int ii; | |||||
1302 | double *out; | |||||
1303 | char hackKeyStr[]="TEEM_OPTSIG_RECONERR"; | |||||
1304 | ||||||
1305 | if (!( oscx && nout && kssSpec )) { | |||||
1306 | biffAddf(GAGEgageBiffKey, "%s: got NULL pointer", me); | |||||
1307 | return 1; | |||||
1308 | } | |||||
1309 | if (windowRho <= 0) { | |||||
1310 | biffAddf(GAGEgageBiffKey, "%s: need positive windowRho (not %g)", me, windowRho); | |||||
1311 | return 1; | |||||
1312 | } | |||||
1313 | if (windowRho > oscx->rhoRange[1] - oscx->rhoRange[0]) { | |||||
1314 | biffAddf(GAGEgageBiffKey, "%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__stderrp, "%s: %s hack on: will save recon results to %s\n", | |||||
1322 | me, hackKeyStr, debugReconErrName); | |||||
1323 | debugReconErrArr = airArrayNew(AIR_CAST(void **, &(debugReconErr))((void **)(&(debugReconErr))), NULL((void*)0), | |||||
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(airFloatQNaN.f); | |||||
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(GAGEgageBiffKey, "%s: problem setting up gage", me); | |||||
1340 | return 1; | |||||
1341 | } | |||||
1342 | if (nrrdMaybeAlloc_va(nout, nrrdTypeDouble, 2, | |||||
1343 | AIR_CAST(size_t, 2)((size_t)(2)), | |||||
1344 | AIR_CAST(size_t, sampleNum)((size_t)(sampleNum)))) { | |||||
1345 | biffMovef(GAGEgageBiffKey, NRRDnrrdBiffKey, "%s: trouble allocating output", me); | |||||
1346 | return 1; | |||||
1347 | } | |||||
1348 | out = AIR_CAST(double *, nout->data)((double *)(nout->data)); | |||||
1349 | fprintf(stderr__stderrp, "%s: plotting ... ", me); fflush(stderr__stderrp); | |||||
1350 | for (ii=0; ii<sampleNum; ii++) { | |||||
1351 | double rho, rlo, rhi, err; | |||||
1352 | fprintf(stderr__stderrp, "%s", airDoneStr(0, ii, oscx->trueImgNum, doneStr)); | |||||
1353 | fflush(stderr__stderrp); | |||||
1354 | rho = AIR_AFFINE(0, ii, sampleNum,( ((double)(oscx->rhoRange[1])-(oscx->rhoRange[0]))*((double )(ii)-(0)) / ((double)(sampleNum)-(0)) + (oscx->rhoRange[0 ])) | |||||
1355 | oscx->rhoRange[0], oscx->rhoRange[1])( ((double)(oscx->rhoRange[1])-(oscx->rhoRange[0]))*((double )(ii)-(0)) / ((double)(sampleNum)-(0)) + (oscx->rhoRange[0 ])); | |||||
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(airFloatQNaN.f); | |||||
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(GAGEgageBiffKey, "%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__stderrp, "%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)((size_t)(2)), | |||||
1385 | AIR_CAST(size_t, oscx->sz*oscx->sy*oscx->sx)((size_t)(oscx->sz*oscx->sy*oscx->sx)), | |||||
1386 | AIR_CAST(size_t, sampleNum)((size_t)(sampleNum))); | |||||
1387 | nrrdSave(debugReconErrName, nre, NULL((void*)0)); | |||||
1388 | nrrdNix(nre); | |||||
1389 | } | |||||
1390 | ||||||
1391 | ||||||
1392 | return 0; | |||||
1393 | } | |||||
1394 |