2 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6 * A PICTURE RECONSTRUCTION PROGRAM *
8 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
10 dist.cpp,v 1.2 2008/08/25 16:11:08 jklukowska Exp
12 COMPARE THE RECONSTRUCTION WITH THE TEST PICTURE
13 ***** INPUT VARIABLES *****
14 A,B: TWO NELEM*NELEM ARRAYS CONTAINING THE TWO PICTURES
16 LINEF: A LOGICAL VARIABLE WHICH DETERMINES IF THE RESIDUAL
17 IS TO BE COMPUTED IN LINE OR STRIP MODE.
18 LIST,WEIGHT: ARRAYS NECESSARY FOR RAY AND WRAY.
19 FLAG: INDICATOR TO CONTROL RESIDUAL COMPUTATION.
20 FLAG.NE.1 CAUSES RESIDUAL TO BE COMPUTED.
21 ***** OUTPUT VARIABLES *****
22 AVE(J): THE AVERAGE DENSITY IN REGION J OF PICTURE B.
23 DIS(J): THE TWO NORM DISTANCE IN REGION J BETWEEN A AND B.
24 REL(J): THE ONE NORM DISTANCE IN REGION J BETWEEN A AND B.
25 VAR(J): THE VARIANCE IN REGION J OF PICTURE B.
26 STD(J): THE STANDARD DEVIATION IN REGION J OF B (=SQRT(VAR)).
27 RESID: THE RESIDUAL- I.E. THE TWO NORM OF THE DIFFERENCE
28 BETWEEN THE PSEUDO PROJECTION OF B AND THE GIVEN
29 PROJECTION DATA FOR THE WHOLE PICTURE.
31 --- Modified 4/1/88 to enable evaluation of subregions, either
32 through boundary selection by geomtric descriptions OR (OR BOTH)
33 pixel selection through density windowing wrt to phantom.
34 --- Only pixels within the specified regions and density window
35 will be used in computing the metrics
36 --- A switch ISW is added to indicate whether the phantom is passed through
37 the first array, a(), or the second array, b(), so that density
38 selection can always be referenced wrt the phantom
58 #include "DistanceMeasureWSQD.h"
60 void Eval_class::dist(
84 REAL theta, sinth, costh;
109 // The near0 parameter is added to allow resetting non-zero variances
110 // (presumably arising from rounding error), computed variance < near0
111 // will be set to zero
113 REAL near0 = (REAL) 1e-5;
115 // Repeat for other specified regions until all are considered
116 for (INTEGER ObjJ = 0; ObjJ < ObjN; ObjJ++)
129 objtyp = Obj[ObjJ].objcod;
131 // Specified region is the whole picture
135 // Test if pixel density (of phantom) is within selected range,
136 // pixel outside density range are excluded
137 for (int i = 0; i < GeoPar.area; i++)
149 if ((dtmp >= t1) && (dtmp <= t2))
154 sumx2 += SQR(drecon);
155 drecon = (REAL) fabs(dfantom - drecon);
157 divis += drecon * drecon;
165 // Call subroutine "subreg" to compute parameters of specified region.
168 idx0 = (Region.iy1 - 2) * GeoPar.nelem;
170 for (int j = Region.iy1; j <= Region.iy2; j++)
174 idx0 += GeoPar.nelem;
176 // Test if current pixel is in specified region
177 for (int i = Region.ix1; i <= Region.ix2; i++)
181 // Rectangular subregion
182 if ((fabs(xd) > Region.aplus)
183 || (fabs(yd) > Region.bplus))
188 // Elliptical subregion
189 arg = (xd * xd) / Region.asq + (yd * yd) / Region.bsq;
194 // Test if pixel density is within selected range
206 if ((dtmp >= t1) && (dtmp <= t2))
211 sumx2 += SQR(drecon); // sumx2 += SQR(drecon - ave[ObjJ]);
212 drecon = (REAL) fabs(dfantom - drecon);
214 divis += drecon * drecon;
218 L222: xd += Region.d1;
222 Region.xd0 -= Region.d2;
223 Region.yd0 -= Region.d1;
228 Obj[ObjJ].npt = npt1;
230 ave[ObjJ] = sumx / rarea;
231 dis[ObjJ] = (REAL) sqrt(divis / rarea);
232 var[ObjJ] = MAX0((REAL) 0.0, sumx2 / rarea - SQR(ave[ObjJ]));
234 // Reset very small non-zero variance (presumably due to rounding
237 if (var[ObjJ] <= near0)
242 std[ObjJ] = (REAL) sqrt(var[ObjJ]);
245 // ALLOW USER TO SKIP EXPENSIVE STATISTIC COMPUTATION
246 if ((fresid || fklds || fwsqd) && flag != 1)
250 bool kldserrorreported=false;
251 for (int np = 0; np < GeoPar.prjnum; np++)
254 Anglst.getang(np, &theta, &sinth, &costh);
258 rinc = GeoPar.pinc * MAX0((REAL) fabs(sinth), (REAL) fabs(costh));
261 for (int nr = GeoPar.fusray; nr <= GeoPar.lusray; nr++)
263 raysum = Anglst.prdta(np, nr);
264 psum = pseudo(b, np, nr, list, weight, &numb, &snorm, linef, TRUE);
268 if (linef && !GeoPar.line) raysum /= rinc;
269 if (!linef && GeoPar.line) raysum *= rinc;
270 rdis += SQR(psum - raysum);
272 // calculate kullback-leibler distance
275 // if it wasn't requested, set it to nan
278 else if (raysum<0 && !kldserrorreported)
280 // report on non-applicability
281 std::cout << "\n****Warning: Negative raysum in prjfil detected, KLDS is not applicable and will be nan!";
283 kldserrorreported=true;
285 // if it was requested and no errors occured, perform calculation
286 else if (!kldserrorreported && !isnan(kldis) && kldis!=std::numeric_limits<double>::infinity() && kldis!=std::numeric_limits<double>::max())
288 if (raysum<=Consts.zero && psum<=Consts.zero)
292 else if (raysum<=Consts.zero)
296 else if (psum<=Consts.zero)
299 if (std::numeric_limits<double>::has_infinity) kldis = std::numeric_limits<double>::infinity();
300 else kldis = std::numeric_limits<double>::max();
304 if ((raysum / psum) > Consts.zero) kldis += (raysum * log(raysum / psum));
305 else kldis += (raysum * log(Consts.zero));
307 kldis += psum - raysum;
314 *resid = (REAL) sqrt(rdis);
318 DistanceMeasureWSQD* distanceMeasureWSQD = new DistanceMeasureWSQD();
319 *wsqd = distanceMeasureWSQD->calculateDistance(b, list, weight);
320 delete distanceMeasureWSQD;