TPCCLIB
Loading...
Searching...
No Matches
imgmtrap.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
27/*****************************************************************************/
28static char *info[] = {
29 "Computation of parametric images of K1 and Vb from dynamic PET image in",
30 "ECAT, NIfTI, or Analyze format, applying NNLS.",
31 "The multilinear model is either",
32 " Cpet(t) = Vb*Cb(t) + ((1-Vb)*K1+Vb*k2)*Integral[Cb(t)]",
33 " - k2*Integral[Cpet(t)]",
34 "or if plasma data is available",
35 " Cpet(t) = Vb*Cb(t) + (1-Vb)*K1*Integral[(1-HCT)*Cp(t)]",
36 " ",
37 "The program needs the blood curve and dynamic PET image, and optionally",
38 "plasma curve, multiplied by (1-HCT).",
39 "The name for the resulting parametric K1 image must be given.",
40 " ",
41 "Usage: @P [Options] btacfile imgfile k1file [vbfile]",
42 " ",
43 "Options:",
44 " -k2=<value> | -k2=median",
45 " Parameter k2 is fixed to a known value, or to a median k2 from",
46 " initial fitting of unconstrained model.",
47 " -ptac=<filename>",
48 " Use plasma curve, multiplied by (1-HCT), as input function;",
49 " the -k2 options are not available with this.",
50 " -thr=<threshold%>",
51 " Pixels with last frame concentration less than (threshold/100 x BTAC)",
52 " are set to zero; default is 1%.",
53 " -end=<fit end time (min)>",
54 " Use data from 0 to end time; by default, model is fitted to all frames.",
55 " -w1, -wf, -wfa",
56 " By default, all weights are set to 1.0 (no weighting, option -w1);",
57 " option -wf sets weights based on frame lengths, and option -wfa based",
58 " on both frame lengths and mean activity during each frame.",
59 " -p2=<filename>",
60 " Image with pixel values of the second fitted parameter, (1-Vb)*K1.",
61 " -p3=<filename>",
62 " Image with pixel values of the third fitted parameter, HCT*kc;",
63 " only available with the first model setting (with unknown PTAC).",
64 " -cbv=<filename>",
65 " Image with pixel values corrected for estimated blood volume,",
66 " Cpet(t) - (1-Vb)*Cb(t).",
67 " -stdoptions", // List standard options like --help, -v, etc
68 " ",
69 "The units of pixel values in the parametric images are ml/(min*ml) for K1",
70 "and ml/ml for Vb.",
71 " ",
72 "See also: fitmtrap, b2ptrap, img2dft",
73 " ",
74 "Keywords: image, modelling, irreversible uptake, perfusion",
75 0};
76/*****************************************************************************/
77
78/*****************************************************************************/
79/* Turn on the globbing of the command line, since it is disabled by default in
80 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
81 In Unix&Linux wildcard command line processing is enabled by default. */
82/*
83#undef _CRT_glob
84#define _CRT_glob -1
85*/
86int _dowildcard = -1;
87/*****************************************************************************/
88
89/*****************************************************************************/
93int main(int argc, char **argv)
94{
95 int ai, help=0, version=0, verbose=1;
96 char ptacfile[FILENAME_MAX], btacfile[FILENAME_MAX], petfile[FILENAME_MAX];
97 char k1file[FILENAME_MAX], vbfile[FILENAME_MAX], cbvfile[FILENAME_MAX];
98 char p2file[FILENAME_MAX], p3file[FILENAME_MAX];
99 float calcThreshold=0.01;
100 double fittime=-1.0;
101 double fixedk2=nan("");
102 int fixk2=0; // Fix k2: 0=no; 1=fix to value given by user; 2=fix to median from fit
103 int weights=2; // 1=frame lengths and activity, 2=frame lengths, 2=no weighting
104 int ret;
105
106
107 /*
108 * Get arguments
109 */
110 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
111 ptacfile[0]=btacfile[0]=petfile[0]=k1file[0]=vbfile[0]=p2file[0]=p3file[0]=cbvfile[0]=(char)0;
112 /* Get options */
113 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
114 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
115 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
116 if(strncasecmp(cptr, "THR=", 4)==0) {
117 double v; ret=atof_with_check(cptr+4, &v);
118 if(!ret && v>=0.0 && v<=200.0) {calcThreshold=(float)(0.01*v); continue;}
119 } else if(strncasecmp(cptr, "END=", 4)==0) {
120 ret=atof_with_check(cptr+4, &fittime); if(!ret && fittime>0.0) continue;
121 } else if(strcasecmp(cptr, "WFA")==0) {
122 weights=0; continue;
123 } else if(strcasecmp(cptr, "WF")==0) {
124 weights=1; continue;
125 } else if(strcasecmp(cptr, "W1")==0) {
126 weights=2; continue;
127 } else if(strncasecmp(cptr, "K2=MEDIAN", 4)==0) {
128 fixk2=2; fixedk2=nan(""); continue;
129 } else if(strncasecmp(cptr, "K2=", 3)==0) {
130 ret=atof_with_check(cptr+3, &fixedk2);
131 if(!ret && fixedk2>=0.0) {fixk2=1; continue;}
132 } else if(strncasecmp(cptr, "PTAC=", 5)==0) {
133 strlcpy(ptacfile, cptr+5, FILENAME_MAX); if(strlen(ptacfile)>0) continue;
134 } else if(strncasecmp(cptr, "P2=", 3)==0) {
135 strlcpy(p2file, cptr+3, FILENAME_MAX); if(strlen(p2file)>0) continue;
136 } else if(strncasecmp(cptr, "P3=", 3)==0) {
137 strlcpy(p3file, cptr+3, FILENAME_MAX); if(strlen(p3file)>0) continue;
138 } else if(strncasecmp(cptr, "CBV=", 4)==0) {
139 strlcpy(cbvfile, cptr+4, FILENAME_MAX); if(strlen(cbvfile)>0) continue;
140 }
141 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
142 return(1);
143 } else break;
144
145
146 /* Print help or version? */
147 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
148 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
149 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
150
151 /* Process other arguments, starting from the first non-option */
152 if(ai<argc) strlcpy(btacfile, argv[ai++], FILENAME_MAX);
153 if(ai<argc) strlcpy(petfile, argv[ai++], FILENAME_MAX);
154 if(ai<argc) strlcpy(k1file, argv[ai++], FILENAME_MAX);
155 if(ai<argc) strlcpy(vbfile, argv[ai++], FILENAME_MAX);
156 if(ai<argc) {fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]); return(1);}
157
158 /* Did we get all the information that we need? */
159 if(!k1file[0]) {
160 fprintf(stderr, "Error: missing command-line argument; use option --help\n"); return(1);}
161
162 /* Check that the options do not clash */
163 if(ptacfile[0] && fixk2>0) {
164 fprintf(stderr, "Error: -k2 option not available with PTAC.\n");
165 return(1);
166 }
167 if(p3file[0]) {
168 if(ptacfile[0]) {
169 fprintf(stderr, "Warning: p3 not available with PTAC.\n");
170 p3file[0]=(char)0;
171 }
172 if(fixk2==1) {
173 fprintf(stderr, "Warning: p3 not available with k2.\n");
174 p3file[0]=(char)0;
175 }
176 }
177
178 /* In verbose mode print arguments and options */
179 if(verbose>1) {
180 printf("btacfile := %s\n", btacfile);
181 if(ptacfile[0]) printf("ptacfile := %s\n", ptacfile);
182 printf("petfile := %s\n", petfile);
183 printf("k1file := %s\n", k1file);
184 if(vbfile[0]) printf("vbfile := %s\n", vbfile);
185 if(p2file[0]) printf("p2file := %s\n", p2file);
186 if(p3file[0]) printf("p3file := %s\n", p3file);
187 if(cbvfile[0]) printf("cbvfile := %s\n", cbvfile);
188 printf("calcThreshold :=%g\n", calcThreshold);
189 printf("weights := %d\n", weights);
190 printf("fixk2 := %d\n", fixk2);
191 if(!isnan(fixedk2)) printf("fixedk2 := %g\n", fixedk2);
192 if(fittime>0.0) printf("required_fittime := %g min\n", fittime);
193 }
194 if(verbose>8) IMG_TEST=verbose-8; else IMG_TEST=0;
195 if(verbose>20) ECAT63_TEST=ECAT7_TEST=verbose-20; else ECAT63_TEST=ECAT7_TEST=0;
196
197
198 /*
199 * Read PET image and input TACs
200 */
201 if(verbose>0) printf("reading data files\n");
202 DFT tac; dftInit(&tac);
203 IMG img; imgInit(&img);
204 int dataNr=0;
205 char errmsg[512];
207 petfile, NULL, btacfile, ptacfile, NULL, &fittime, &dataNr, &img,
208 NULL, &tac, 1, stdout, verbose-2, errmsg);
209 if(ret!=0) {
210 fprintf(stderr, "Error: %s.\n", errmsg);
211 if(verbose>1) printf(" ret := %d\n", ret);
212 return(2);
213 }
214 if(imgNaNs(&img, 1)>0)
215 if(verbose>0) fprintf(stderr, "Warning: missing pixel values.\n");
216 strcpy(tac.voi[0].name, "blood");
217 if(tac.voiNr>1) strcpy(tac.voi[1].name, "plasma");
218 /* Set time unit to min, also for integrals in y2[] */
219 if(tac.timeunit==TUNIT_SEC) {
220 for(int ti=0; ti<tac.voiNr; ti++) {
221 for(int fi=0; fi<tac.frameNr; fi++) tac.voi[ti].y2[fi]/=60.0;
222 for(int fi=0; fi<tac.frameNr; fi++) tac.voi[ti].y3[fi]/=3600.0;
223 }
224 }
225 ret=dftTimeunitConversion(&tac, TUNIT_MIN);
226 if(verbose>1) {
227 printf("fittimeFinal := %g min\n", fittime);
228 printf("dataNr := %d\n", dataNr);
229 printf("image_matrix_size := %dx%dx%d\n", img.dimx, img.dimy, img.dimz);
230 printf("frames := %d\n", img.dimt);
231 }
232 /* Check that image is dynamic */
233 if(dataNr<4) {
234 fprintf(stderr, "Error: too few time frames for fitting.\n");
235 if(verbose>1) imgInfo(&img);
236 imgEmpty(&img); dftEmpty(&tac); return(2);
237 }
238
239
240 /* Add place for tissue TACs too */
241 if(verbose>1) fprintf(stdout, "allocating working memory for pixel TACs\n");
242 ret=dftAddmem(&tac, 1);
243 if(ret) {
244 fprintf(stderr, "Error: cannot allocate memory.\n");
245 if(verbose>0) printf("ret := %d\n", ret);
246 imgEmpty(&img); dftEmpty(&tac); return(3);
247 }
248 strcpy(tac.voi[tac.voiNr].name, "tissue");
249
250 /* Set weights as requested */
251 if(imgSetWeights(&img, weights, verbose-5)!=0) {
252 fprintf(stderr, "Error: cannot calculate weights.\n");
253 imgEmpty(&img); dftEmpty(&tac); return(3);
254 }
255 for(int i=0; i<dataNr; i++) tac.w[i]=img.weight[i];
256
257 /* Determine the threshold */
258 double threshold=calcThreshold*tac.voi[0].y[dataNr-1];
259 if(verbose>1) printf("threshold_AUC := %g\n", threshold);
260
261
262 /*
263 * Allocate result images (allocate all, even if user did not want to save those)
264 */
265 if(verbose>1) fprintf(stdout, "allocating memory for parametric image data\n");
266 IMG k1img; imgInit(&k1img);
267 IMG vbimg; imgInit(&vbimg);
268 IMG p2img; imgInit(&p2img);
269 IMG p3img; imgInit(&p3img);
270 ret=imgAllocateWithHeader(&k1img, img.dimz, img.dimy, img.dimx, 1, &img);
271 if(!ret) ret=imgAllocateWithHeader(&vbimg, img.dimz, img.dimy, img.dimx, 1, &img);
272 if(!ret) ret=imgAllocateWithHeader(&p2img, img.dimz, img.dimy, img.dimx, 1, &img);
273 if(!ret) ret=imgAllocateWithHeader(&p3img, img.dimz, img.dimy, img.dimx, 1, &img);
274 if(ret) {
275 fprintf(stderr, "Error: cannot allocate memory for result image.\n");
276 imgEmpty(&img); dftEmpty(&tac); imgEmpty(&k1img); imgEmpty(&vbimg);
277 imgEmpty(&p2img); imgEmpty(&p3img);
278 return(4);
279 }
280 /* set 'frame time' for parametric images */
281 k1img.start[0]=vbimg.start[0]=p2img.start[0]=p3img.start[0]=0.0;
282 k1img.end[0]=vbimg.end[0]=p2img.end[0]=p3img.end[0]=60.*fittime;
283 /* set units in parametric images */
284 k1img.unit=CUNIT_ML_PER_ML_PER_MIN;
285 vbimg.unit=CUNIT_ML_PER_ML;
286 p2img.unit=p3img.unit=CUNIT_PER_MIN;
287 /* and set the more or less necessary things */
290 k1img.isWeight=vbimg.isWeight=p2img.isWeight=p3img.isWeight=0;
291
292
293 /* Fitting */
294
295 int fittedNr=0, fittedokNr=0, thresholdNr=0;
296
297 /* Compute weights for NNLS */
298 for(int m=0; m<dataNr; m++) {
299 if(tac.w[m]<=1.0e-20) tac.w[m]=0.0; else tac.w[m]=sqrt(tac.w[m]);
300 }
301
302 /*
303 * Compute full 3-parameter model, if needed
304 */
305 if(!ptacfile[0] && fixk2!=1) {
306 if(verbose>0) fprintf(stdout, "fitting 3-parameter model\n");
307 int nnls_n=3;
308
309 /* Allocate memory required by NNLS */
310 if(verbose>1) fprintf(stdout, "allocating memory for NNLS\n");
311 int nnls_m=dataNr;
312 int nnls_index[nnls_n];
313 double **nnls_a, nnls_b[nnls_m], nnls_zz[nnls_m], nnls_x[nnls_n], *nnls_mat,
314 nnls_wp[nnls_n], nnls_rnorm;
315 nnls_mat=(double*)malloc((nnls_n*nnls_m)*sizeof(double));
316 nnls_a=(double**)malloc(nnls_n*sizeof(double*));
317 if(nnls_mat==NULL || nnls_a==NULL) {
318 fprintf(stderr, "Error: cannot allocate memory for NNLS.\n");
319 imgEmpty(&img); dftEmpty(&tac); imgEmpty(&k1img); imgEmpty(&vbimg);
320 imgEmpty(&p2img); imgEmpty(&p3img);
321 return(4);
322 }
323 for(int n=0; n<nnls_n; n++) nnls_a[n]=nnls_mat+n*nnls_m;
324
325 double *ct, *cti, *cb, *cbi;
326 cb=tac.voi[0].y; cbi=tac.voi[0].y2;
327 ct=tac.voi[tac.voiNr].y; cti=tac.voi[tac.voiNr].y2;
328 /* Median of p3 from reasonable pixel results will be computed */
329 double *p3list=(double*)malloc(sizeof(double)*img.dimz*img.dimy*img.dimx);
330 if(p3list==NULL) {
331 fprintf(stderr, "Error: out of memory.\n");
332 imgEmpty(&img); dftEmpty(&tac); imgEmpty(&k1img); imgEmpty(&vbimg);
333 imgEmpty(&p2img); imgEmpty(&p3img);
334 return(4);
335 }
336 int p3nr=0;
337 /* pixel-by-pixel */
338 for(int pi=0; pi<img.dimz; pi++) {
339 if(verbose>0) {fprintf(stdout, "."); fflush(stdout);}
340 for(int yi=0; yi<img.dimy; yi++) {
341 for(int xi=0; xi<img.dimx; xi++) {
342 double K1=0.0, Vb=0.0, p2=0.0, p3=0.0;
343 /* Set pixel results to zero */
344 k1img.m[pi][yi][xi][0]=0.0;
345 vbimg.m[pi][yi][xi][0]=0.0;
346 p2img.m[pi][yi][xi][0]=0.0;
347 p3img.m[pi][yi][xi][0]=0.0;
348 /* if value at the end is less than threshold value, then do nothing more */
349 if(img.m[pi][yi][xi][dataNr-1]<threshold) {thresholdNr++; continue;}
350 /* Copy pixel curve */
351 for(int fi=0; fi<tac.frameNr; fi++) ct[fi]=img.m[pi][yi][xi][fi];
352 /* Integrate it */
353 ret=petintegral(tac.x1, tac.x2, ct, tac.frameNr, cti, NULL);
354 if(ret) continue;
355
356 /* Fill the NNLS data matrix */
357 for(int m=0; m<nnls_m; m++) {
358 nnls_a[0][m]=cb[m];
359 nnls_a[1][m]=cbi[m];
360 nnls_a[2][m]=-cti[m];
361 nnls_b[m]=ct[m];
362 }
363 if(img.isWeight)
364 for(int m=0; m<nnls_m; m++) {
365 nnls_b[m]*=tac.w[m];
366 for(int n=0; n<nnls_n; n++) nnls_a[n][m]*=tac.w[m];
367 }
368 /* NNLS */
369 ret=nnls(nnls_a, nnls_m, nnls_n, nnls_b, nnls_x, &nnls_rnorm, nnls_wp, nnls_zz, nnls_index);
370 if(ret!=0) { /* no solution is possible */
371 if(verbose>3) printf("no solution possible (%d)\n", ret);
372 if(verbose>4) printf("nnls_n=%d nnls_m=%d\n", nnls_n, nnls_m);
373 for(int n=0; n<nnls_n; n++) nnls_x[n]=0.0;
374 nnls_rnorm=0.0;
375 continue;
376 }
377 fittedNr++;
378
379 Vb=nnls_x[0];
380 p2=nnls_x[1];
381 p3=nnls_x[2];
382 if(Vb>0.98) {
383 K1=0.0; Vb=1.0;
384 } else {
385 K1=(p2-Vb*p3)/(1.0-Vb);
386 if(K1>0.1 && Vb<0.6 && p3>0.1 && p3<1.0) p3list[p3nr++]=p3;
387 if(K1>0.0 && K1<8.0) fittedokNr++;
388 }
389 if(K1<0.0) K1=0.0; else if(K1>8.0) K1=8.0;
390 if(p2>5.0) p2=5.0;
391 /* Put results to output images */
392 vbimg.m[pi][yi][xi][0]=Vb;
393 p2img.m[pi][yi][xi][0]=p2;
394 p3img.m[pi][yi][xi][0]=p3;
395 k1img.m[pi][yi][xi][0]=K1;
396
397 /* If cbvfile was requested, and we do not run 2-parameter model */
398 if(cbvfile[0] && fixk2==0) {
399 for(int ti=0; ti<img.dimt; ti++) {
400 img.m[pi][yi][xi][ti]-=nnls_x[0]*cb[ti];
401 if(img.m[pi][yi][xi][ti]<0.0) img.m[pi][yi][xi][ti]=0.0;
402 }
403 }
404
405 } /* next column */
406 } /* next row */
407 } /* next plane */
408 if(verbose>0) {fprintf(stdout, " done.\n"); fflush(stdout);}
409 free(nnls_mat); free(nnls_a);
410 /* Show statistics on how we succeeded */
411 {
412 int n=(int)img.dimx*(int)img.dimy*(int)img.dimz;
413 if(verbose>0) {
414 fprintf(stdout, "%d out of %d pixels were fitted; %d pixels ok.\n", fittedNr, n, fittedokNr);
415 fprintf(stdout, "%d pixels were thresholded.\n", thresholdNr);
416 }
417 }
418 /* Calculate p3 median */
419 if(p3nr>0) fixedk2=dmedian(p3list, p3nr);
420 free(p3list);
421 if(!isnan(fixedk2)) {
422 if(verbose>0) printf("Median k2 := %g\n", fixedk2);
423 if(verbose>1) printf("Median calculated from %d pixels\n", p3nr);
424 } else if(fixk2==2) {
425 fprintf(stderr, "Error: reasonable k2 median could not be calculated.\n");
426 imgEmpty(&k1img); imgEmpty(&vbimg); imgEmpty(&p2img); imgEmpty(&p3img);
427 imgEmpty(&img); dftEmpty(&tac);
428 return(6);
429 }
430 /* Save p3 image, if requested */
431 if(p3file[0]) {
432 if(imgWrite(p3file, &p3img)) {
433 fprintf(stderr, "Error: cannot write p3 image.\n");
434 imgEmpty(&k1img); imgEmpty(&vbimg); imgEmpty(&p2img); imgEmpty(&p3img);
435 imgEmpty(&img); dftEmpty(&tac);
436 return(11);
437 }
438 if(verbose>0) fprintf(stdout, "P3 image saved.\n");
439 }
440
441 /* If 2-parameter fitting is not needed, then save results and quit */
442 if(fixk2==0) {
443 /* Save cbv image if requested */
444 if(cbvfile[0]) {
445 if(imgWrite(cbvfile, &img)) fprintf(stderr, "Error: cannot write cbv image.\n");
446 }
447 imgEmpty(&img); dftEmpty(&tac);
448 ret=imgWrite(k1file, &k1img);
449 if(!ret && vbfile[0]) ret=imgWrite(vbfile, &vbimg);
450 if(!ret && p2file[0]) ret=imgWrite(p2file, &p2img);
451 imgEmpty(&k1img); imgEmpty(&vbimg); imgEmpty(&p2img); imgEmpty(&p3img);
452 if(ret) {
453 fprintf(stderr, "Error: cannot write parametric image.\n");
454 return(12);
455 }
456 if(verbose>0) fprintf(stdout, "Parametric image(s) saved.\n");
457 return(0);
458 }
459 imgEmpty(&p3img);
460 }
461
462
463
464 /*
465 * If still here, compute 2-parameter model
466 */
467 if(verbose>0) fprintf(stdout, "fitting 2-parameter model\n");
468 int nnls_n=2;
469
470 /* Allocate memory required by NNLS */
471 if(verbose>1) fprintf(stdout, "allocating memory for NNLS\n");
472 int nnls_m=dataNr;
473 int nnls_index[nnls_n];
474 double **nnls_a, nnls_b[nnls_m], nnls_zz[nnls_m], nnls_x[nnls_n], *nnls_mat,
475 nnls_wp[nnls_n], nnls_rnorm;
476 nnls_mat=(double*)malloc((nnls_n*nnls_m)*sizeof(double));
477 nnls_a=(double**)malloc(nnls_n*sizeof(double*));
478 if(nnls_mat==NULL || nnls_a==NULL) {
479 fprintf(stderr, "Error: cannot allocate memory for NNLS.\n");
480 imgEmpty(&img); dftEmpty(&tac); imgEmpty(&k1img); imgEmpty(&vbimg);
481 imgEmpty(&p2img); imgEmpty(&p3img);
482 return(4);
483 }
484 for(int n=0; n<nnls_n; n++) nnls_a[n]=nnls_mat+n*nnls_m;
485
486 double *ct, *cti, *cb, *cbi, *cpi=NULL;
487 cb=tac.voi[0].y; cbi=tac.voi[0].y2;
488 if(ptacfile[0]) cpi=tac.voi[1].y2;
489 ct=tac.voi[tac.voiNr].y; cti=tac.voi[tac.voiNr].y2;
490 /* pixel-by-pixel */
491 for(int pi=0; pi<img.dimz; pi++) {
492 if(verbose>0) {fprintf(stdout, "."); fflush(stdout);}
493 for(int yi=0; yi<img.dimy; yi++) {
494 for(int xi=0; xi<img.dimx; xi++) {
495 double K1=0.0, Vb=0.0, p2=0.0;
496 /* Set pixel results to zero */
497 k1img.m[pi][yi][xi][0]=0.0;
498 vbimg.m[pi][yi][xi][0]=0.0;
499 p2img.m[pi][yi][xi][0]=0.0;
500 /* if value at the end is less than threshold value, then do nothing more */
501 if(img.m[pi][yi][xi][dataNr-1]<threshold) {thresholdNr++; continue;}
502 /* Copy pixel curve */
503 for(int fi=0; fi<tac.frameNr; fi++) ct[fi]=img.m[pi][yi][xi][fi];
504 /* Integrate it */
505 ret=petintegral(tac.x1, tac.x2, ct, tac.frameNr, cti, NULL);
506 if(ret) continue;
507
508 /*
509 * Estimate parameters K1 and Vb
510 */
511
512 /* Fill the NNLS data matrix */
513 if(ptacfile[0]) {
514 for(int m=0; m<nnls_m; m++) {
515 nnls_a[0][m]=cb[m];
516 nnls_a[1][m]=cpi[m];
517 nnls_b[m]=ct[m];
518 }
519 } else {
520 for(int m=0; m<nnls_m; m++) {
521 nnls_a[0][m]=cb[m]+fixedk2*cbi[m];
522 nnls_a[1][m]=cbi[m];
523 nnls_b[m]=ct[m]+fixedk2*cti[m];
524 }
525 }
526 if(img.isWeight)
527 for(int m=0; m<nnls_m; m++) {
528 nnls_b[m]*=tac.w[m];
529 for(int n=0; n<nnls_n; n++) nnls_a[n][m]*=tac.w[m];
530 }
531 /* NNLS */
532 ret=nnls(nnls_a, nnls_m, nnls_n, nnls_b, nnls_x, &nnls_rnorm, nnls_wp, nnls_zz, nnls_index);
533 if(ret!=0) { /* no solution is possible */
534 if(verbose>3) printf("no solution possible (%d)\n", ret);
535 if(verbose>4) printf("nnls_n=%d nnls_m=%d\n", nnls_n, nnls_m);
536 for(int n=0; n<nnls_n; n++) nnls_x[n]=0.0;
537 nnls_rnorm=0.0;
538 continue;
539 }
540 fittedNr++;
541
542 Vb=nnls_x[0];
543 p2=nnls_x[1];
544 if(Vb>0.98) {
545 K1=p2; Vb=1.0; //K1=0.0; Vb=1.0;
546 } else {
547 K1=p2/(1.0-Vb);
548 if(K1>0.0 && K1<8.0) fittedokNr++;
549 }
550 if(K1<0.0) K1=0.0; else if(K1>8.0) K1=8.0;
551 if(p2>5.0) p2=5.0;
552 /* Put results to output images */
553 vbimg.m[pi][yi][xi][0]=Vb;
554 p2img.m[pi][yi][xi][0]=p2;
555 k1img.m[pi][yi][xi][0]=K1;
556
557 /* If cbvfile was requested, then calculate it */
558 if(cbvfile[0]) {
559 for(int ti=0; ti<img.dimt; ti++) {
560 img.m[pi][yi][xi][ti]-=nnls_x[0]*cb[ti];
561 if(img.m[pi][yi][xi][ti]<0.0) img.m[pi][yi][xi][ti]=0.0;
562 }
563 }
564
565 } /* next column */
566 } /* next row */
567 } /* next plane */
568 if(verbose>0) {fprintf(stdout, " done.\n"); fflush(stdout);}
569 free(nnls_mat); free(nnls_a);
570 /* Show statistics on how we succeeded */
571 {
572 int n=(int)img.dimx*(int)img.dimy*(int)img.dimz;
573 if(verbose>0) {
574 fprintf(stdout, "%d out of %d pixels were fitted; %d pixels ok.\n", fittedNr, n, fittedokNr);
575 fprintf(stdout, "%d pixels were thresholded.\n", thresholdNr);
576 }
577 }
578
579 /*
580 * Save cbv image if requested
581 */
582 if(cbvfile[0]) {
583 if(imgWrite(cbvfile, &img)) fprintf(stderr, "Error: cannot write cbv image.\n");
584 }
585
586
587 /* No need for dynamic data any more */
588 imgEmpty(&img); dftEmpty(&tac);
589
590
591 /*
592 * Save parametric images
593 */
594
595 ret=imgWrite(k1file, &k1img);
596 if(!ret && vbfile[0]) ret=imgWrite(vbfile, &vbimg);
597 if(!ret && p2file[0]) ret=imgWrite(p2file, &p2img);
598 imgEmpty(&k1img); imgEmpty(&vbimg); imgEmpty(&p2img);
599 if(ret) {
600 fprintf(stderr, "Error: cannot write parametric image.\n");
601 return(13);
602 }
603 if(verbose>0) fprintf(stdout, "Parametric image(s) saved.\n");
604
605 return(0);
606}
607/*****************************************************************************/
608
609/*****************************************************************************/
int atof_with_check(char *double_as_string, double *result_value)
Definition decpoint.c:107
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 ECAT63_TEST
Definition ecat63h.c:6
int ECAT7_TEST
Definition ecat7h.c:6
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.
#define IMG_DC_NONCORRECTED
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
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
double dmedian(double *data, int n)
Definition median.c:48
Header file for libtpcmodext.
int imgSetWeights(IMG *img, int wmet, int verbose)
Voi * voi
int timeunit
double * w
double * x1
int voiNr
double * x2
int frameNr
unsigned short int dimx
float **** m
char decayCorrection
char unit
unsigned short int dimt
float * weight
float * start
unsigned short int dimz
unsigned short int dimy
float * end
char isWeight
double * y2
double * y
char name[MAX_REGIONNAME_LEN+1]
double * y3