TPCCLIB
Loading...
Searching...
No Matches
imgsrtm.c
Go to the documentation of this file.
1
9/*****************************************************************************/
10#include "tpcclibConfig.h"
11/*****************************************************************************/
12#include <stdio.h>
13#include <stdlib.h>
14#include <unistd.h>
15#include <string.h>
16#include <math.h>
17#include <time.h>
18/*****************************************************************************/
19#include "libtpccurveio.h"
20#include "libtpcmodext.h"
21#include "libtpcmisc.h"
22#include "libtpcmodel.h"
23#include "libtpcimgio.h"
24#include "libtpcimgp.h"
25/*****************************************************************************/
26#define NNLS_N 3
27enum {MODEL_UNKNOWN, MODEL_SRTM, MODEL_SRTM2};
28/*****************************************************************************/
29
30/*****************************************************************************/
31static char *info[] = {
32 "Computation of parametric image of binding potential (BPnd) from",
33 "dynamic PET image in ECAT, NIfTI, or Analyze format applying simplified",
34 "reference tissue model (SRTM) [1]:",
35 " ______ K1' ___________ ",
36 " | | --> | | dCt(t)= ",
37 " | | <-- | Cr | +R1*dCr(t) ",
38 " | | k2'|___________| +k2*Cr(t) ",
39 " | | ____________________ -(k2/(1+BPnd))*Ct(t)",
40 " | Cp | K1 | k3 | | Ct(t)=Cf(t)+Cb(t) ",
41 " | | --> | Cf -------> Cb | ",
42 " | | <-- | <------- | ",
43 " | | k2 | | k4 | R1=K1/K1'=k2/k2' ",
44 " |______| |___________|________| BPnd=k3/k4 ",
45 " ",
46 "The model is transformed to general linear least squares functions [2],",
47 "which are solved using Lawson-Hanson non-negative least squares (NNLS)",
48 "algorithm [3]. BPnd is estimated directly without division [4].",
49 " ",
50 "Dynamic PET image and reference region TAC must be corrected for decay.",
51 " ",
52 "Usage: @P [Options] imgfile rtacfile bpfile",
53 " ",
54 "Options:",
55 " -SRTM2",
56 " STRM2 method (5) is applied; in brief, traditional SRTM method is",
57 " used first to calculate median k2' from all pixels where BPnd>0; then",
58 " SRTM is run another time with fixed k2'",
59 " -R1=<filename>",
60 " Programs computes also an R1 image.",
61 " -k2=<filename>",
62 " Programs computes also a k2 image.",
63 " -k2s=<filename>",
64 " Program computes also a k2' image",
65 " -theta3=<filename> or -t3=<filename>",
66 " Program computes also a theta3 image; theta3 = k2/(1+BPnd)+lambda",
67 " -rp=<filename>",
68 " Program writes regression parameters in the specified image file",
69 " -dual=<filename> or -du=<filename>",
70 " Program writes number of i in set p in NNLS dual solution vector in",
71 " the specified image file",
72 " -thr=<threshold%>",
73 " Pixels with AUC less than (threshold/100 x ref AUC) are set to zero",
74 " default is 0%",
75 " -DVR",
76 " Instead of BP, program saves the DVR (=BP+1) values.",
77 " -end=<Fit end time (min)>",
78 " Use data from 0 to end time; by default, model is fitted to all frames.",
79 " -stdoptions", // List standard options like --help, -v, etc
80 " ",
81 "Example:",
82 " @P ua2918dy1.v ua2918cer.dft ua2918bp.v",
83 " ",
84 "References:",
85 "1. Lammertsma AA, Hume SP. Simplified reference tissue model for PET",
86 " receptor studies. NeuroImage 1996;4:153-158.",
87 "2. Blomqvist G. On the construction of functional maps in positron emission",
88 " tomography. J Cereb Blood Flow Metab 1984;4:629-632.",
89 "3. Lawson CL & Hanson RJ. Solving least squares problems.",
90 " Prentice-Hall, 1974.",
91 "4. Zhou Y, Brasic J, Endres CJ, Kuwabara H, Kimes A, Contoreggi C, Maini A,",
92 " Ernst M, Wong DF. Binding potential image based statistical mapping for",
93 " detection of dopamine release by [11C]raclopride dynamic PET.",
94 " NeuroImage 2002;16:S91.",
95 "5. Wu Y, Carson RE. Noise reduction in the simplified reference tissue",
96 " model for neuroreceptor functional imaging. J Cereb Blood Flow Metab.",
97 " 2002;22:1440-1452.",
98 " ",
99 "See also: imgdv, imgbfbp, imgratio, imgunit, eframe, imgdecay, img2dft",
100 " ",
101 "Keywords: image, modelling, binding potential, SRTM, SRTM2, reference input",
102 0};
103/*****************************************************************************/
104
105/*****************************************************************************/
106/* Turn on the globbing of the command line, since it is disabled by default in
107 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
108 In Unix&Linux wildcard command line processing is enabled by default. */
109/*
110#undef _CRT_glob
111#define _CRT_glob -1
112*/
113int _dowildcard = -1;
114/*****************************************************************************/
115
116/*****************************************************************************/
120int main(int argc, char **argv)
121{
122 int ai, help=0, version=0, verbose=1;
123 int pi, yi, xi, fi, ret;
124 int model=MODEL_SRTM, bp_plus_one=0, weight=0;
125 int fitdimt;
126 char inpfile[FILENAME_MAX], petfile[FILENAME_MAX], bpfile[FILENAME_MAX];
127 char r1file[FILENAME_MAX], k2file[FILENAME_MAX], k2sfile[FILENAME_MAX];
128 char t3file[FILENAME_MAX], regfile[FILENAME_MAX], dualfile[FILENAME_MAX];
129 char *cptr, tmp[512];
130 float threshold, calcThreshold=0.0;
131 double fittime=-1.0, f;
132 DFT tac;
133 IMG pet, bpout, r1out, k2out, k2sout, t3out, tout, dualout;
134 clock_t fitStart, fitFinish;
135 double lambda=0;
136 double *ct, *cti, *cr, *cri; /* Pointers to tissue and reference TACs */
137 /* nnls */
138 int nnls_n, nnls_m, n, m, nnls_index[NNLS_N];
139 double *nnls_a[NNLS_N], *nnls_b, *nnls_zz, nnls_x[NNLS_N], *nnls_mat,
140 nnls_wp[NNLS_N], *dptr, nnls_rnorm;
141
142
143
144 /*
145 * Get arguments
146 */
147 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
148 inpfile[0]=petfile[0]=bpfile[0]=r1file[0]=k2file[0]=k2sfile[0]=(char)0;
149 t3file[0]=regfile[0]=dualfile[0]=(char)0;
150 /* Get options */
151 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
152 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
153 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
154 if(strcasecmp(cptr, "DVR")==0 || strcasecmp(cptr, "BP+1")==0) {
155 bp_plus_one=1; continue;
156 } else if(*cptr=='w' || *cptr=='W') {
157 weight=1; continue;
158 } else if(strncasecmp(cptr, "R1=", 3)==0) {
159 strlcpy(r1file, cptr+3, FILENAME_MAX); continue;
160 } else if(strncasecmp(cptr, "k2=", 3)==0) {
161 strlcpy(k2file, cptr+3, FILENAME_MAX); continue;
162 } else if(strncasecmp(cptr, "k2s=", 4)==0) {
163 strlcpy(k2sfile, cptr+4, FILENAME_MAX); continue;
164 } else if(strncasecmp(cptr, "theta3=", 7)==0) {
165 strlcpy(t3file, cptr+7, FILENAME_MAX); continue;
166 } else if(strncasecmp(cptr, "t3=", 3)==0) {
167 strlcpy(t3file, cptr+3, FILENAME_MAX); continue;
168 } else if(strncasecmp(cptr, "dual=", 5)==0) {
169 strlcpy(dualfile, cptr+5, FILENAME_MAX); continue;
170 } else if(strncasecmp(cptr, "du=", 3)==0) {
171 strlcpy(dualfile, cptr+3, FILENAME_MAX); continue;
172 } else if(strncasecmp(cptr, "RP=", 3)==0) {
173 strlcpy(regfile, cptr+3, FILENAME_MAX); continue;
174 } else if(strncasecmp(cptr, "THR=", 4)==0) {
175 double v; ret=atof_with_check(cptr+4, &v);
176 if(!ret && v>=0.0 && v<=200.0) {calcThreshold=(float)(0.01*v); continue;}
177 } else if(strncasecmp(cptr, "END=", 4)==0) {
178 fittime=atof_dpi(cptr+4); if(fittime>0.0) continue;
179 } else if(strcasecmp(cptr, "SRTM2")==0) {
180 model=MODEL_SRTM2; continue;
181 }
182 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
183 return(1);
184 } else break;
185
186 /* Print help or version? */
187 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
188 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
189 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
190
191 /* Process other arguments, starting from the first non-option */
192 if(ai<argc) strlcpy(petfile, argv[ai++], FILENAME_MAX);
193 if(ai<argc) strlcpy(inpfile, argv[ai++], FILENAME_MAX);
194 if(ai<argc) strlcpy(bpfile, argv[ai++], FILENAME_MAX);
195 if(ai<argc) {
196 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
197 return(1);
198 }
199 /* Did we get all the information that we need? */
200 if(!bpfile[0]) {
201 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
202 return(1);
203 }
204 if(strcasecmp(petfile, bpfile)==0 || strcasecmp(petfile, r1file)==0 ||
205 strcasecmp(petfile, k2file)==0 || strcasecmp(petfile, regfile)==0)
206 {
207 fprintf(stderr, "Error: check the output filenames.\n");
208 return(1);
209 }
210 /* In verbose mode print arguments and options */
211 if(verbose>1) {
212 printf("inpfile := %s\n", inpfile);
213 printf("petfile := %s\n", petfile);
214 printf("bpfile := %s\n", bpfile);
215 if(r1file[0]) printf("r1file := %s\n", r1file);
216 if(k2file[0]) printf("k2file := %s\n", k2file);
217 if(k2sfile[0]) printf("k2sfile := %s\n", k2sfile);
218 if(t3file[0]) printf("t3file := %s\n", t3file);
219 if(dualfile[0]) printf("dualfile := %s\n", dualfile);
220 if(regfile[0]) printf("regfile := %s\n", regfile);
221 printf("calcThreshold :=%g\n", calcThreshold);
222 printf("bp_plus_one := %d\n", bp_plus_one);
223 printf("weight := %d\n", weight);
224 if(fittime>0.0) printf("required_fittime := %g min\n", fittime);
225 printf("model := %d\n", model);
226 }
227 if(verbose>8) IMG_TEST=verbose-8; else IMG_TEST=0;
228
229
230
231 /*
232 * Read PET image and reference tissue TAC
233 */
234 imgInit(&pet); dftInit(&tac);
236 petfile, NULL, inpfile, NULL, NULL, &fittime, &fitdimt, &pet,
237 NULL, &tac, 1, stdout, verbose-2, tmp);
238 if(ret!=0) {
239 fprintf(stderr, "Error: %s.\n", tmp);
240 if(verbose>1) printf(" ret := %d\n", ret);
241 return(2);
242 }
243 if(imgNaNs(&pet, 1)>0)
244 if(verbose>0) fprintf(stderr, "Warning: missing pixel values.\n");
245 /* Set time unit to min, also for integrals in y2[] */
246 if(tac.timeunit==TUNIT_SEC)
247 for(fi=0; fi<tac.frameNr; fi++) tac.voi[0].y2[fi]/=60.0;
248 dftTimeunitConversion(&tac, TUNIT_MIN);
249
250 /* Theta3 can be calculated only if isotope halflife is known; check that */
251 /* and calculate the lambda */
252 if(t3file[0]) {
253 if(pet.isotopeHalflife<=1.0E-005) {
254 fprintf(stderr,"Error: %s does not contain isotope halflife;\n", petfile);
255 fprintf(stderr," this is required with option -theta3=<filename>\n");
256 imgEmpty(&pet); dftEmpty(&tac);
257 return(3);
258 }
259 lambda=M_LN2/(pet.isotopeHalflife/60.0);
260 if(verbose>1) fprintf(stdout, "lambda := %g [1/min]\n", lambda);
261 }
262 if(verbose>1) {
263 printf("fittimeFinal := %g min\n", fittime);
264 printf("fitdimt := %d\n", fitdimt);
265 }
266 /* Check that image is dynamic and fit time long enough */
267 if(fitdimt<4) {
268 fprintf(stderr, "Error: too few time frames for fitting.\n");
269 if(verbose>1) imgInfo(&pet);
270 imgEmpty(&pet); dftEmpty(&tac);
271 return(2);
272 }
273
274
275 /* Allocate memory for tissue TAC and integral */
276 ret=dftAddmem(&tac, 1);
277 if(ret!=0) {
278 fprintf(stderr, "Error: cannot allocate memory.\n");
279 if(verbose>0) printf(" ret := %d\n", ret);
280 imgEmpty(&pet); dftEmpty(&tac);
281 return(3);
282 }
283 strcpy(tac.voi[0].voiname, "input");
284 strcpy(tac.voi[1].voiname, "tissue");
285
286
287 /* Determine the threshold based on reference tissue integral */
288 threshold=calcThreshold*tac.voi[0].y2[fitdimt-1];
289 if(verbose>2) printf("threshold_AUC := %g\n", threshold);
290
291
292 /*
293 * Allocate result images and fill the header info
294 */
295 if(verbose>1) printf("allocating memory for parametric images\n");
296 imgInit(&tout); imgInit(&bpout); imgInit(&r1out); imgInit(&k2out);
297 imgInit(&k2sout); imgInit(&t3out); imgInit(&dualout);
298 ret=imgAllocateWithHeader(&tout, pet.dimz, pet.dimy, pet.dimx, NNLS_N, &pet);
299 if(ret==0)
300 ret=imgAllocateWithHeader(&bpout, pet.dimz, pet.dimy, pet.dimx, 1, &pet);
301 if(ret==0 && r1file[0])
302 ret=imgAllocateWithHeader(&r1out, pet.dimz, pet.dimy, pet.dimx, 1, &pet);
303 if(ret==0 && k2file[0])
304 ret=imgAllocateWithHeader(&k2out, pet.dimz, pet.dimy, pet.dimx, 1, &pet);
305 if(ret==0 && (k2sfile[0] || model==MODEL_SRTM2))
306 ret=imgAllocateWithHeader(&k2sout, pet.dimz, pet.dimy, pet.dimx, 1, &pet);
307 if(ret==0 && t3file[0])
308 ret=imgAllocateWithHeader(&t3out, pet.dimz, pet.dimy, pet.dimx, 1, &pet);
309 if(ret==0 && dualfile[0])
310 ret=imgAllocateWithHeader(&dualout, pet.dimz, pet.dimy, pet.dimx, 1, &pet);
311 if(ret) {
312 fprintf(stderr, "Error (%d): out of memory.\n", ret);
313 imgEmpty(&pet); dftEmpty(&tac); imgEmpty(&tout); imgEmpty(&bpout);
314 imgEmpty(&r1out); imgEmpty(&k2out); imgEmpty(&t3out); imgEmpty(&dualout);
315 imgEmpty(&k2sout);
316 return(4);
317 }
318 /* Set the rest of image header */
319 if(verbose>1) fprintf(stdout, "setting parametric image headers\n");
320 bpout.start[0]=pet.start[0]; bpout.end[0]=pet.end[fitdimt-1];
321 tout.unit=(char)CUNIT_UNITLESS;
322 bpout.unit=(char)CUNIT_UNITLESS;
323 if(r1file[0]) {
324 r1out.unit=(char)CUNIT_UNITLESS;
325 r1out.start[0]=pet.start[0]; r1out.end[0]=pet.end[fitdimt-1];
326 }
327 if(k2file[0]) {
328 k2out.unit=(char)CUNIT_PER_MIN;
329 k2out.start[0]=pet.start[0]; k2out.end[0]=pet.end[fitdimt-1];
330 }
331 if(k2sfile[0] || model==MODEL_SRTM2) {
332 k2sout.unit=(char)CUNIT_PER_MIN;
333 k2sout.start[0]=pet.start[0]; k2sout.end[0]=pet.end[fitdimt-1];
334 }
335 if(t3file[0]) {
336 t3out.unit=(char)CUNIT_PER_MIN;
337 t3out.start[0]=pet.start[0]; t3out.end[0]=pet.end[fitdimt-1];
338 }
339 if(dualfile[0]) {
340 dualout.unit=(char)CUNIT_UNITLESS;
341 dualout.start[0]=pet.start[0]; dualout.end[0]=pet.end[fitdimt-1];
342 }
343
344
345 /*
346 * Allocate memory required by NNLS
347 */
348 if(verbose>1) printf("allocating memory for NNLS\n");
349 nnls_n=NNLS_N; nnls_m=fitdimt;
350 nnls_mat=(double*)malloc(((nnls_n+2)*nnls_m)*sizeof(double));
351 if(nnls_mat==NULL) {
352 fprintf(stderr, "Error: cannot allocate memory for NNLS.\n");
353 imgEmpty(&pet); dftEmpty(&tac); imgEmpty(&tout); imgEmpty(&bpout);
354 imgEmpty(&r1out); imgEmpty(&k2out); imgEmpty(&t3out); imgEmpty(&dualout);
355 imgEmpty(&k2sout);
356 return(5);
357 }
358 for(n=0, dptr=nnls_mat; n<nnls_n; n++) {nnls_a[n]=dptr; dptr+=nnls_m;}
359 nnls_b=dptr; dptr+=nnls_m; nnls_zz=dptr;
360
361 /* Copy weights if available */
362 /* or set them to frame lengths */
363 if(verbose>2) printf("working with NNLS weights\n");
364 if(weight==1 && pet.isWeight==0) {
365 for(m=0; m<nnls_m; m++) pet.weight[m]=pet.end[m]-pet.start[m];
366 pet.isWeight=1;
367 }
368 /* Compute NNLS weights */
369 if(pet.isWeight) {
370 for(m=0; m<nnls_m; m++) {
371 tac.w[m]=pet.weight[m];
372 if(tac.w[m]<=1.0e-20) tac.w[m]=0.0;
373 }
374 }
375
376
377
378 /*
379 * Compute SRTM pixel-by-pixel
380 */
381 if(verbose>0) fprintf(stdout, "computing SRTM pixel-by-pixel\n");
382 cr=tac.voi[0].y; cri=tac.voi[0].y2;
383 ct=tac.voi[1].y; cti=tac.voi[1].y2;
384 int thresholded_nr=0, nosolution_nr=0;
385 fitStart=clock();
386 for(pi=0; pi<pet.dimz; pi++) {
387 if(verbose>2) printf("computing plane %d\n", pet.planeNumber[pi]);
388 else if(pet.dimz>1 && verbose>0) {fprintf(stdout, "."); fflush(stdout);}
389 for(yi=0; yi<pet.dimy; yi++) {
390 for(xi=0; xi<pet.dimx; xi++) {
391 /* Set regression coefs to zero */
392 for(n=0; n<nnls_n; n++) tout.m[0][yi][xi][n]=0.0;
393 /* Calculate pixel integral */
394 for(fi=0; fi<tac.frameNr; fi++) ct[fi]=pet.m[pi][yi][xi][fi];
395 ret=petintegral(tac.x1, tac.x2, ct, tac.frameNr, cti, NULL);
396 if(verbose>6 && pi==pet.dimz/2 && yi==pet.dimy/3 && xi==pet.dimx/3) {
397 printf("\nExample pixel pi=%d yi=%d xi=%d\n", pi, yi, xi);
398 printf(" Cr Cri Ct Cti\n");
399 for(m=0; m<nnls_m; m++)
400 printf("%12.4f %12.4f %12.4f %12.4f\n", cr[m],cri[m],ct[m],cti[m]);
401 }
402 /* if AUC at the end is less than threshold value, then do nothing */
403 if(cti[fitdimt-1]<threshold) {
404 thresholded_nr++;
405 continue;
406 }
407
408 /* Fit using traditional formulation, if R1, k2 and/or k2' are needed */
409 if(model==MODEL_SRTM2 ||
410 r1file[0] || k2file[0] || k2sfile[0] || t3file[0])
411 {
412 /* Fill A matrix: */
413 /* function #1: */
414 for(m=0; m<nnls_m; m++) nnls_a[0][m]=cr[m];
415 /* function #2: */
416 for(m=0; m<nnls_m; m++) nnls_a[1][m]=cri[m];
417 /* function #3: */
418 for(m=0; m<nnls_m; m++) nnls_a[2][m]=-cti[m];
419 /* Fill B array: */
420 for(m=0; m<nnls_m; m++) nnls_b[m]=ct[m];
421 /* Apply data weights */
422 if(pet.isWeight) nnlsWght(nnls_n, nnls_m, nnls_a, nnls_b, tac.w);
423 if(verbose>6 && pi==pet.dimz/2 && yi==pet.dimy/3 && xi==pet.dimx/3) {
424 printf("Matrix A Array B\n");
425 for(m=0; m<nnls_m; m++) {
426 printf("%12.3f %12.3f %12.3f %12.3f\n",
427 nnls_a[0][m], nnls_a[1][m], nnls_a[2][m], nnls_b[m]);
428 }
429 }
430 /* NNLS */
431 ret=nnls(nnls_a, nnls_m, nnls_n, nnls_b, nnls_x, &nnls_rnorm,
432 nnls_wp, nnls_zz, nnls_index);
433 if(ret>1) { /* no solution is possible */
434 nosolution_nr++; continue;
435 }
436 for(n=0; n<nnls_n; n++) tout.m[pi][yi][xi][n]=nnls_x[n];
437 /* Get R1 */
438 if(r1file[0]) r1out.m[pi][yi][xi][0]=nnls_x[0];
439 /* Get k2 */
440 if(k2file[0]) k2out.m[pi][yi][xi][0]=nnls_x[1];
441 /* Get theta3=p3+lambda */
442 if(t3file[0]) {
443 if(nnls_wp[2]==0.0) t3out.m[pi][yi][xi][0]=nnls_x[2]+lambda;
444 else t3out.m[pi][yi][xi][0]=0.0;
445 }
446 /* Get k2' (k2 of reference region), when BP>0 */
447 if(k2sfile[0] || model==MODEL_SRTM2) {
448 if(nnls_x[2]>0.0) f=nnls_x[1]/nnls_x[2]; else f=0.0; // f=BP+1
449 if(f>1.0 && nnls_x[0]>0.0 && nnls_x[1]>0.0)
450 k2sout.m[pi][yi][xi][0]=nnls_x[1]/nnls_x[0];
451 }
452 }
453
454 /* Estimate BP without division, unless using SRTM2 model */
455 if(model==MODEL_SRTM2) continue;
456 /* Set regression coefs to zero */
457 for(n=0; n<nnls_n; n++) tout.m[0][yi][xi][n]=0.0;
458
459 /* Fill A matrix: */
460 /* function #1: */
461 for(m=0; m<nnls_m; m++) nnls_a[0][m]=cr[m];
462 /* function #2: */
463 for(m=0; m<nnls_m; m++) nnls_a[1][m]=cri[m];
464 /* function #3: */
465 for(m=0; m<nnls_m; m++) nnls_a[2][m]=-ct[m];
466 /* Fill B array: */
467 for(m=0; m<nnls_m; m++) nnls_b[m]=cti[m];
468 /* Apply data weights */
469 if(pet.isWeight) nnlsWght(nnls_n, nnls_m, nnls_a, nnls_b, tac.w);
470 if(verbose>6 && pi==pet.dimz/2 && yi==pet.dimy/3 && xi==pet.dimx/3) {
471 printf("Matrix A Array B\n");
472 for(m=0; m<nnls_m; m++) {
473 printf("%12.3f %12.3f %12.3f %12.3f\n",
474 nnls_a[0][m], nnls_a[1][m], nnls_a[2][m], nnls_b[m]);
475 }
476 }
477
478 /* NNLS */
479 ret=nnls(nnls_a, nnls_m, nnls_n, nnls_b, nnls_x, &nnls_rnorm,
480 nnls_wp, nnls_zz, nnls_index);
481 if(ret>1) continue; /* no solution is possible */
482 for(n=0; n<nnls_n; n++) tout.m[pi][yi][xi][n]=nnls_x[n];
483 /* Get BP */
484 bpout.m[pi][yi][xi][0]=nnls_x[1];
485 if(!bp_plus_one) bpout.m[pi][yi][xi][0]-=1.0;
486 if(verbose>6 && pi==pet.dimz/2 && yi==pet.dimy/3 && xi==pet.dimx/3) {
487 for(n=0; n<nnls_n; n++) printf(" nnls_x[%d]=%g", n, nnls_x[n]);
488 printf(" bpout.m[%d][%d][%d][0]=%g\n",
489 pi, yi, xi, bpout.m[pi][yi][xi][0]);
490 }
491 /* Count the number of i in set p in NNLS solution */
492 for(n=m=0; n<nnls_n; n++) if(nnls_wp[n]==0.0) m++;
493 if(dualfile[0]) dualout.m[pi][yi][xi][0]=m;
494 } /* next column */
495 } /* next row */
496 } /* next plane */
497 fitFinish=clock();
498 free(nnls_mat);
499 if(verbose>0) {
500 fprintf(stdout, "\n");
501 if(model==MODEL_SRTM2) fprintf(stdout, "first step ");
502 fprintf(stdout, "done.\n");
503 }
504 if(verbose>1 || thresholded_nr>0)
505 fprintf(stdout, "%d pixels were not fitted due to threshold.\n",
506 thresholded_nr);
507 if(verbose>1 || nosolution_nr>0)
508 fprintf(stdout, "no NNLS solution for %d pixels.\n", nosolution_nr);
509
510
511 /*
512 * Compute next step of SRTM2 pixel-by-pixel
513 */
514 if(model==MODEL_SRTM2) {
515
516 if(verbose>0) fprintf(stdout, "calculating median of k2'\n");
517 /* In how many pixels k2'>0 (and BP>0 as well)? */
518 for(n=pi=0; pi<pet.dimz; pi++)
519 for(yi=0; yi<pet.dimy; yi++) for(xi=0; xi<pet.dimx; xi++)
520 if(k2sout.m[pi][yi][xi][0]>0.0001) n++;
521 if(verbose>1) fprintf(stdout, "BP>0 and k2'>0 in %d pixels.\n", n);
522 /* Allocate memory for n k2' values */
523 double *k2sarray, k2smedian, sd;
524 k2sarray=(double*)malloc(n*sizeof(double));
525 if(k2sarray==NULL) {
526 fprintf(stderr, "Error: cannot allocate memory for k2' values.\n");
527 imgEmpty(&pet); dftEmpty(&tac);
528 imgEmpty(&tout); imgEmpty(&bpout); imgEmpty(&r1out); imgEmpty(&k2out);
529 imgEmpty(&t3out); imgEmpty(&dualout);
530 imgEmpty(&k2sout);
531 return 6;
532 }
533 /* Calculate the median of k2' */
534 for(n=pi=0; pi<pet.dimz; pi++)
535 for(yi=0; yi<pet.dimy; yi++) for(xi=0; xi<pet.dimx; xi++)
536 if(k2sout.m[pi][yi][xi][0]>0.0001)
537 k2sarray[n++]=k2sout.m[pi][yi][xi][0];
538 k2smedian=dmedian(k2sarray, n);
539 if(verbose>0) fprintf(stdout, "k2s_median := %g\n", k2smedian);
540 if(verbose>1) {
541 f=dmean(k2sarray, n, &sd);
542 fprintf(stdout, "k2s_mean := %g +- %g\n", f, sd);
543 }
544 free(k2sarray);
545
546 /* Allocate memory for NNLS */
547 if(verbose>1) fprintf(stdout, "allocating memory for the second NNLS\n");
548 nnls_n=2; nnls_m=fitdimt;
549 nnls_mat=(double*)malloc(((nnls_n+2)*nnls_m)*sizeof(double));
550 if(nnls_mat==NULL) {
551 fprintf(stderr, "Error: cannot allocate memory for NNLS.\n");
552 imgEmpty(&pet); dftEmpty(&tac); imgEmpty(&tout); imgEmpty(&bpout);
553 imgEmpty(&r1out); imgEmpty(&k2out); imgEmpty(&t3out); imgEmpty(&dualout);
554 imgEmpty(&k2sout);
555 return(5);
556 }
557 for(n=0, dptr=nnls_mat; n<nnls_n; n++) {nnls_a[n]=dptr; dptr+=nnls_m;}
558 nnls_b=dptr; dptr+=nnls_m; nnls_zz=dptr;
559
560 if(verbose>0) fprintf(stdout, "computing SRTM2 2nd step pixel-by-pixel\n");
561
562 cr=tac.voi[0].y; cri=tac.voi[0].y2;
563 ct=tac.voi[1].y; cti=tac.voi[1].y2;
564 thresholded_nr=0; nosolution_nr=0;
565 for(pi=0; pi<pet.dimz; pi++) {
566 if(verbose>2) printf("computing plane %d\n", pet.planeNumber[pi]);
567 else if(pet.dimz>1 && verbose>0) {fprintf(stdout, "."); fflush(stdout);}
568 for(yi=0; yi<pet.dimy; yi++) {
569 for(xi=0; xi<pet.dimx; xi++) {
570 /* Set regression coefs to zero */
571 for(n=0; n<(nnls_n+1); n++) tout.m[0][yi][xi][n]=0.0;
572 bpout.m[pi][yi][xi][0]=0.0;
573 /* Calculate pixel integral */
574 for(fi=0; fi<tac.frameNr; fi++) ct[fi]=pet.m[pi][yi][xi][fi];
575 ret=petintegral(tac.x1, tac.x2, ct, tac.frameNr, cti, NULL);
576 /* if AUC at the end is less than threshold value, then do nothing */
577 if(cti[fitdimt-1]<threshold) {
578 thresholded_nr++; continue;
579 }
580
581 /* Estimate BP without division */
582
583 /* Fill A matrix: */
584 for(m=0; m<nnls_m; m++) nnls_a[0][m]=cr[m]+k2smedian*cri[m];
585 for(m=0; m<nnls_m; m++) nnls_a[1][m]=-ct[m];
586 /* Fill B array */
587 for(m=0; m<nnls_m; m++) nnls_b[m]=k2smedian*cti[m];
588 /* Apply data weights */
589 if(pet.isWeight) nnlsWght(nnls_n, nnls_m, nnls_a, nnls_b, tac.w);
590
591 /* NNLS */
592 ret=nnls(nnls_a, nnls_m, nnls_n, nnls_b, nnls_x, &nnls_rnorm,
593 nnls_wp, nnls_zz, nnls_index);
594 if(ret>1) { /* no solution is possible */
595 nosolution_nr++; continue;
596 }
597 for(n=0; n<nnls_n; n++) tout.m[pi][yi][xi][n]=nnls_x[n];
598 /* Get BP */
599 bpout.m[pi][yi][xi][0]=nnls_x[0];
600 if(!bp_plus_one) bpout.m[pi][yi][xi][0]-=1.0;
601 if(verbose>6 && pi==pet.dimz/2 && yi==pet.dimy/3 && xi==pet.dimx/3) {
602 for(n=0; n<nnls_n; n++) printf("\n nnls_x[%d]=%g", n, nnls_x[n]);
603 printf(" bpout.m[%d][%d][%d][0]=%g\n",
604 pi, yi, xi, bpout.m[pi][yi][xi][0]);
605 }
606
607 /* Estimate R1 without division, if needed */
608 if(!r1file[0]) continue;
609
610 /* Fill A matrix: */
611 for(m=0; m<nnls_m; m++) nnls_a[0][m]=cr[m]+k2smedian*cri[m];
612 for(m=0; m<nnls_m; m++) nnls_a[1][m]=-k2smedian*cti[m];
613 /* Fill B array */
614 for(m=0; m<nnls_m; m++) nnls_b[m]=ct[m];
615 /* Apply data weights */
616 if(pet.isWeight) nnlsWght(nnls_n, nnls_m, nnls_a, nnls_b, tac.w);
617
618 /* NNLS */
619 ret=nnls(nnls_a, nnls_m, nnls_n, nnls_b, nnls_x, &nnls_rnorm,
620 nnls_wp, nnls_zz, nnls_index);
621 if(ret>1) continue; /* no solution is possible */
622 /* Get R1 */
623 r1out.m[pi][yi][xi][0]=nnls_x[0];
624
625 } /* next column */
626 } /* next row */
627 } /* next plane */
628 fitFinish=clock();
629 free(nnls_mat);
630 if(verbose>0) {
631 fprintf(stdout, "\ndone.\n");
632 }
633 if(verbose>1 || thresholded_nr>0)
634 fprintf(stdout, "%d pixels were not fitted due to threshold.\n",
635 thresholded_nr);
636 if(verbose>1 || nosolution_nr>0)
637 fprintf(stdout, "no NNLS solution for %d pixels.\n", nosolution_nr);
638 }
639
640
641 /* No need for dynamic image or input tac anymore */
642 imgEmpty(&pet); dftEmpty(&tac);
643
644
645 /*
646 * Save parametric image(s)
647 */
648 if(verbose>1) fprintf(stdout, "writing parametric images\n");
649 ret=imgWrite(bpfile, &bpout);
650 if(ret) {
651 fprintf(stderr, "Error: %s\n", bpout.statmsg);
652 imgEmpty(&tout); imgEmpty(&bpout); imgEmpty(&r1out); imgEmpty(&k2out);
653 imgEmpty(&t3out); imgEmpty(&dualout);
654 imgEmpty(&k2sout);
655 return(13);
656 }
657 if(verbose>0) {
658 if(!bp_plus_one) fprintf(stdout, "BP image written in %s\n", bpfile);
659 else fprintf(stdout, "(BP+1) image written in %s\n", bpfile);
660 }
661 if(r1file[0]) {
662 ret=imgWrite(r1file, &r1out);
663 if(ret) {
664 fprintf(stderr, "Error: %s\n", r1out.statmsg);
665 imgEmpty(&tout); imgEmpty(&bpout); imgEmpty(&r1out); imgEmpty(&k2out);
666 imgEmpty(&t3out); imgEmpty(&dualout);
667 imgEmpty(&k2sout);
668 return(14);
669 }
670 if(verbose>0) fprintf(stdout, "R1 image written in %s\n", r1file);
671 }
672 if(k2file[0]) {
673 ret=imgWrite(k2file, &k2out);
674 if(ret) {
675 fprintf(stderr, "Error: %s\n", k2out.statmsg);
676 imgEmpty(&tout); imgEmpty(&bpout); imgEmpty(&r1out); imgEmpty(&k2out);
677 imgEmpty(&t3out); imgEmpty(&dualout);
678 imgEmpty(&k2sout);
679 return(15);
680 }
681 if(verbose>0) fprintf(stdout, "k2 image written in %s\n", k2file);
682 }
683 if(k2sfile[0]) {
684 ret=imgWrite(k2sfile, &k2sout);
685 if(ret) {
686 fprintf(stderr, "Error: %s\n", k2sout.statmsg);
687 imgEmpty(&tout); imgEmpty(&bpout); imgEmpty(&r1out); imgEmpty(&k2out);
688 imgEmpty(&t3out); imgEmpty(&dualout);
689 imgEmpty(&k2sout);
690 return(16);
691 }
692 if(verbose>0) fprintf(stdout, "k2' image written in %s\n", k2sfile);
693 }
694 if(t3file[0]) {
695 ret=imgWrite(t3file, &t3out);
696 if(ret) {
697 fprintf(stderr, "Error: %s\n", t3out.statmsg);
698 imgEmpty(&tout); imgEmpty(&bpout); imgEmpty(&r1out); imgEmpty(&k2out);
699 imgEmpty(&t3out); imgEmpty(&dualout);
700 imgEmpty(&k2sout);
701 return(17);
702 }
703 if(verbose>0) fprintf(stdout, "theta3 image written in %s\n", t3file);
704 }
705 if(dualfile[0]) {
706 ret=imgWrite(dualfile, &dualout);
707 if(ret) {
708 fprintf(stderr, "Error: %s\n", dualout.statmsg);
709 imgEmpty(&tout); imgEmpty(&bpout); imgEmpty(&r1out); imgEmpty(&k2out);
710 imgEmpty(&t3out); imgEmpty(&dualout);
711 imgEmpty(&k2sout);
712 return(18);
713 }
714 if(verbose>0)
715 fprintf(stdout, "dual solution image written in %s\n", dualfile);
716 }
717 if(regfile[0]) {
718 ret=imgWrite(regfile, &tout);
719 if(ret) {
720 fprintf(stderr, "Error: %s\n", tout.statmsg);
721 imgEmpty(&tout); imgEmpty(&bpout); imgEmpty(&r1out); imgEmpty(&k2out);
722 imgEmpty(&t3out); imgEmpty(&dualout);
723 imgEmpty(&k2sout);
724 return(19);
725 }
726 if(verbose>0)
727 fprintf(stdout, "Regression parameter image written in %s\n", regfile);
728 }
729
730 imgEmpty(&tout); imgEmpty(&bpout); imgEmpty(&r1out); imgEmpty(&k2out);
731 imgEmpty(&t3out); imgEmpty(&dualout); imgEmpty(&k2sout);
732
733
734 /* How long did the fitting take */
735 if(verbose>1) fprintf(stdout, "parameter estimation time := %.1f [s]\n",
736 (double)(fitFinish-fitStart) / CLOCKS_PER_SEC );
737
738 return(0);
739}
740/*****************************************************************************/
741
742/*****************************************************************************/
int atof_with_check(char *double_as_string, double *result_value)
Definition decpoint.c:107
double atof_dpi(char *str)
Definition decpoint.c:59
void dftInit(DFT *data)
Definition dft.c:38
int dftAddmem(DFT *dft, int voiNr)
Definition dft.c:107
void dftEmpty(DFT *data)
Definition dft.c:20
int dftTimeunitConversion(DFT *dft, int tunit)
Definition dftunit.c:119
int IMG_TEST
Definition img.c:6
void imgInfo(IMG *image)
Definition img.c:359
unsigned long long imgNaNs(IMG *img, int fix)
Definition img.c:658
int imgAllocateWithHeader(IMG *image, int planes, int rows, int columns, int frames, IMG *image_from)
Definition img.c:279
void imgEmpty(IMG *image)
Definition img.c:121
void imgInit(IMG *image)
Definition img.c:60
int imgWrite(const char *fname, IMG *img)
Definition imgfile.c:136
int imgReadModelingData(char *petfile, char *siffile, char *inputfile1, char *inputfile2, char *inputfile3, double *fitdur, int *fitframeNr, IMG *img, DFT *inp, DFT *iinp, int verifypeak, FILE *loginfo, int verbose, char *status)
Definition imginput.c:24
int petintegral(double *x1, double *x2, double *y, int nr, double *ie, double *iie)
Integrate PET TAC data to frame mid times.
Definition integr.c:771
Header file for libtpccurveio.
Header file for libtpcimgio.
Header file for libtpcimgp.
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:40
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition strext.c:245
#define M_LN2
Definition libtpcmisc.h:90
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:213
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:383
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:158
Header file for libtpcmodel.
int nnls(double **a, int m, int n, double *b, double *x, double *rnorm, double *w, double *zz, int *index)
Definition nnls.c:37
int nnlsWght(int N, int M, double **A, double *b, double *weight)
Definition nnls.c:257
double dmean(double *data, int n, double *sd)
Definition median.c:73
double dmedian(double *data, int n)
Definition median.c:48
Header file for libtpcmodext.
Voi * voi
int timeunit
double * w
double * x1
double * x2
int frameNr
unsigned short int dimx
float **** m
char unit
int * planeNumber
float * weight
float * start
unsigned short int dimz
unsigned short int dimy
float * end
const char * statmsg
float isotopeHalflife
char isWeight
double * y2
char voiname[MAX_REGIONSUBNAME_LEN+1]
double * y