TPCCLIB
Loading...
Searching...
No Matches
imglhk3.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 4
27/*****************************************************************************/
28
29/*****************************************************************************/
30static char *info[] = {
31 "Computation of parametric image of k3 from dynamic PET image in ECAT, NIfTI,",
32 "or Analyze format applying irreversible two-tissue compartmental model with",
33 "arterial plasma input.",
34 "The compartmental models are transformed to general linear least squares",
35 "functions (1), which are solved using Lawson-Hanson non-negative least",
36 "squares (NNLS) algorithm (2).",
37 " ",
38 "Dynamic PET image and plasma time-activity curve (PTAC) must be corrected",
39 "for decay to the tracer injection time.",
40 " ",
41 "Usage: @P [Options] ptacfile imgfile k3file",
42 " ",
43 "Options:",
44 " -thr=<threshold%>",
45 " Pixels with AUC less than (threshold/100 x PTAC AUC) are set to zero;",
46 " default is 1%.",
47 " -end=<Fit end time (min)>",
48 " Use data from 0 to end time; by default, model is fitted to all frames.",
49 " -dv=<filename>",
50 " Parametric K1/(k2+k3) image is saved.",
51 " -K1=<filename>",
52 " Parametric K1 image is saved.",
53 " -k2=<filename>",
54 " Parametric k2 image is saved.",
55 " -Ki=<filename>",
56 " Parametric Ki image is saved.",
57 " -Vb=<filename>",
58 " Vb is fitted, and parametric Vb image is saved; without this,",
59 " Vb is assumed to be zero (or precorrected).",
60 " -k2k3=<filename>",
61 " Parametric k2+k3 image is saved.",
62//" -NNLS or -BVLS",
63//" LLSQ method.",
64//" -w1, -wf, -wfa",
65//" By default, all weights are set to 1.0 (no weighting, option -w1); option -wf",
66//" sets weights based on frame lengths, and option -wfa based on both frame lengths",
67//" and mean activity during each frame.",
68 " -stdoptions", // List standard options like --help, -v, etc
69 " ",
70 "The vascular volume is considered in the model setting only if file name for",
71 "Vb image is given. Otherwise the contribution of vasculature to the total",
72 "radioactivity concentration is assumed to be negligible, or pre-corrected.",
73 "Note that this model can correctly estimate Vb only if",
74 "1) plasma does not contain any labelled metabolites, and",
75 "2) plasma and blood curves are similar in shape.",
76 "Vascular volume can be pre-corrected with imgcbv.",
77 " ",
78 "The units of pixel values in the parametric images are 1/min for k3,",
79 "ml/(min*ml) for K1 and Ki, and ml/ml for DV and Vb.",
80 " ",
81 "Example 1b: Vb is assumed negligible:",
82 " @P ua2917ap.kbq ua2917dy1.v ua2917k3.v",
83 "Example 1b: Vb is fitted as one of the model parameters:",
84 " @P -Vb=ua2917vb.v ua2917ap.kbq ua2917dy1.v ua2917k3.v",
85 "Example 1c: Vb is pre-corrected:",
86 " imgcbv ua2917dy1.v ua2917ab.kbq 0.04 ua2917dy1_cbv.v",
87 " @P ua2917ap.kbq ua2917dy1_cbv.v ua2917k3.v",
88 "Example 2: K1, DV, and k3 images are saved:",
89 " @P -K1=ua2917k1.v -DV=ua2917dv.v ua2917ap.kbq ua2917dy1.v ua2917k3.v",
90 " ",
91 "References:",
92 "1. Blomqvist G. On the construction of functional maps in positron",
93 " emission tomography. J Cereb Blood Flow Metab 1984;4:629-632.",
94 "2. Lawson CL & Hanson RJ. Solving least squares problems.",
95 " Prentice-Hall, 1974, ISBN 0-89871-356-0.",
96 " ",
97 "See also: imgcbv, imgki, fitk3",
98 " ",
99 "Keywords: image, modelling, irreversible uptake, Ki, NNLS",
100 0};
101/*****************************************************************************/
102
103/*****************************************************************************/
104/* Turn on the globbing of the command line, since it is disabled by default in
105 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
106 In Unix&Linux wildcard command line processing is enabled by default. */
107/*
108#undef _CRT_glob
109#define _CRT_glob -1
110*/
111int _dowildcard = -1;
112/*****************************************************************************/
113
114/*****************************************************************************/
115enum {METHOD_UNKNOWN, METHOD_NNLS, METHOD_BVLS};
116static char *method_str[] = {"unknown", "NNLS", "BVLS", 0};
117/*****************************************************************************/
118
119/*****************************************************************************/
123int main(int argc, char **argv)
124{
125 int ai, help=0, version=0, verbose=1;
126 char inpfile[FILENAME_MAX], petfile[FILENAME_MAX], k3file[FILENAME_MAX];
127 char k1file[FILENAME_MAX], k2file[FILENAME_MAX], vbfile[FILENAME_MAX];
128 char dvfile[FILENAME_MAX], kifile[FILENAME_MAX], k2k3file[FILENAME_MAX];
129 float calcThreshold=0.01;
130 int fitVb=0; // 0=not fitted, 1=fitted
131 double fittime=-1.0;
132 int weights=2; // 1=frame lengths and activity, 2=frame lengths, 2=no weighting
133 int method=METHOD_NNLS;
134 int ret;
135
136 /*
137 * Get arguments
138 */
139 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
140 inpfile[0]=petfile[0]=k3file[0]=kifile[0]=(char)0;
141 vbfile[0]=k1file[0]=k2file[0]=k2k3file[0]=dvfile[0]=(char)0;
142 /* Get options */
143 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
144 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
145 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
146 if(strncasecmp(cptr, "K1=", 3)==0) {
147 strlcpy(k1file, cptr+3, FILENAME_MAX); continue;
148 } else if(strncasecmp(cptr, "K2=", 3)==0) {
149 strlcpy(k2file, cptr+3, FILENAME_MAX); continue;
150 } else if(strncasecmp(cptr, "K2K3=", 5)==0) {
151 strlcpy(k2k3file, cptr+5, FILENAME_MAX); continue;
152 } else if(strncasecmp(cptr, "KI=", 3)==0) {
153 strlcpy(kifile, cptr+3, FILENAME_MAX); continue;
154 } else if(strncasecmp(cptr, "VB=", 3)==0) {
155 strlcpy(vbfile, cptr+3, FILENAME_MAX); fitVb=1; continue;
156 } else if(strncasecmp(cptr, "DV=", 3)==0) {
157 strlcpy(dvfile, cptr+3, FILENAME_MAX); continue;
158 } else if(strncasecmp(cptr, "THR=", 4)==0) {
159 double v; ret=atof_with_check(cptr+4, &v);
160 if(!ret && v>=0.0 && v<=200.0) {calcThreshold=(float)(0.01*v); continue;}
161 } else if(strncasecmp(cptr, "END=", 4)==0) {
162 ret=atof_with_check(cptr+4, &fittime); if(!ret && fittime>0.0) continue;
163 } else if(strcasecmp(cptr, "WFA")==0) {
164 weights=0; continue;
165 } else if(strcasecmp(cptr, "WF")==0) {
166 weights=1; continue;
167 } else if(strcasecmp(cptr, "W1")==0) {
168 weights=2; continue;
169 } else if(strcasecmp(cptr, "NNLS")==0) {
170 method=METHOD_NNLS; continue;
171 } else if(strcasecmp(cptr, "BVLS")==0) {
172 method=METHOD_BVLS; continue;
173 }
174 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
175 return(1);
176 } else break;
177
178
179 /* Print help or version? */
180 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
181 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
182 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
183
184 /* Process other arguments, starting from the first non-option */
185 if(ai<argc) strlcpy(inpfile, argv[ai++], FILENAME_MAX);
186 if(ai<argc) strlcpy(petfile, argv[ai++], FILENAME_MAX);
187 if(ai<argc) strlcpy(k3file, argv[ai++], FILENAME_MAX);
188 if(ai<argc) {fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]); return(1);}
189 /* Did we get all the information that we need? */
190 if(!k3file[0]) {
191 fprintf(stderr, "Error: missing command-line argument; use option --help\n"); return(1);}
192 if(strcasecmp(petfile, k3file)==0 || strcasecmp(petfile, k1file)==0 ||
193 strcasecmp(petfile, vbfile)==0 || strcasecmp(inpfile, dvfile)==0)
194 {
195 fprintf(stderr, "Error: check the output filenames.\n");
196 return(1);
197 }
198 /* In verbose mode print arguments and options */
199 if(verbose>1) {
200 printf("inpfile := %s\n", inpfile);
201 printf("petfile := %s\n", petfile);
202 printf("k3file := %s\n", k3file);
203 if(vbfile[0]) printf("vbfile := %s\n", vbfile);
204 if(k1file[0]) printf("k1file := %s\n", k1file);
205 if(k2file[0]) printf("k2file := %s\n", k2file);
206 if(k2k3file[0]) printf("k2k3file := %s\n", k2k3file);
207 if(kifile[0]) printf("kifile := %s\n", kifile);
208 if(dvfile[0]) printf("dvfile := %s\n", dvfile);
209 printf("calcThreshold :=%g\n", calcThreshold);
210 printf("weights := %d\n", weights);
211 printf("fitVb := %d\n", fitVb);
212 printf("method := %s\n", method_str[method]);
213 if(fittime>0.0) printf("required_fittime := %g min\n", fittime);
214 }
215 if(verbose>8) IMG_TEST=verbose-8; else IMG_TEST=0;
216 if(verbose>20) ECAT63_TEST=ECAT7_TEST=verbose-20; else ECAT63_TEST=ECAT7_TEST=0;
217
218
219 /*
220 * Read PET image and input TAC
221 */
222 if(verbose>0) printf("reading data files\n");
223 DFT tac; dftInit(&tac);
224 IMG img; imgInit(&img);
225 int dataNr=0;
226 char errmsg[512];
228 petfile, NULL, inpfile, NULL, NULL, &fittime, &dataNr, &img,
229 NULL, &tac, 1, stdout, verbose-2, errmsg);
230 if(ret!=0) {
231 fprintf(stderr, "Error: %s.\n", errmsg);
232 if(verbose>1) printf(" ret := %d\n", ret);
233 return(2);
234 }
235 if(imgNaNs(&img, 1)>0)
236 if(verbose>0) fprintf(stderr, "Warning: missing pixel values.\n");
237 /* Set time unit to min, also for integrals in y2[] */
238 if(tac.timeunit==TUNIT_SEC) {
239 for(int fi=0; fi<tac.frameNr; fi++) tac.voi[0].y2[fi]/=60.0;
240 for(int fi=0; fi<tac.frameNr; fi++) tac.voi[0].y3[fi]/=3600.0;
241 }
242 ret=dftTimeunitConversion(&tac, TUNIT_MIN);
243 if(verbose>1) {
244 printf("fittimeFinal := %g min\n", fittime);
245 printf("dataNr := %d\n", dataNr);
246 }
247 /* Check that image is dynamic */
248 if(dataNr<4) {
249 fprintf(stderr, "Error: too few time frames for fitting.\n");
250 if(verbose>1) imgInfo(&img);
251 imgEmpty(&img); dftEmpty(&tac); return(2);
252 }
253
254
255 /* Add place for tissue TACs too */
256 if(verbose>1) fprintf(stdout, "allocating working memory for pixel TACs\n");
257 ret=dftAddmem(&tac, 1);
258 if(ret) {
259 fprintf(stderr, "Error: cannot allocate memory.\n");
260 if(verbose>0) printf("ret := %d\n", ret);
261 imgEmpty(&img); dftEmpty(&tac); return(3);
262 }
263 strcpy(tac.voi[0].name, "input");
264 strcpy(tac.voi[1].name, "tissue");
265
266 /* Set weights as requested */
267 if(imgSetWeights(&img, weights, verbose-5)!=0) {
268 fprintf(stderr, "Error: cannot calculate weights.\n");
269 imgEmpty(&img); dftEmpty(&tac); return(3);
270 }
271 for(int i=0; i<dataNr; i++) tac.w[i]=img.weight[i];
272
273 /* Determine the threshold */
274 double threshold=calcThreshold*tac.voi[0].y2[dataNr-1];
275 if(verbose>1) printf("threshold_AUC := %g\n", threshold);
276
277
278 /*
279 * Allocate result images (allocate all, even if user did not want to save those)
280 */
281 if(verbose>1) fprintf(stdout, "allocating memory for parametric image data\n");
282 IMG k3img; imgInit(&k3img);
283 IMG k1img; imgInit(&k1img);
284 IMG k2img; imgInit(&k2img);
285 IMG k2k3img; imgInit(&k2k3img);
286 IMG kiimg; imgInit(&kiimg);
287 IMG dvimg; imgInit(&dvimg);
288 IMG vbimg; imgInit(&vbimg);
289 ret=imgAllocateWithHeader(&k3img, img.dimz, img.dimy, img.dimx, 1, &img);
290 if(!ret) ret=imgAllocateWithHeader(&k1img, img.dimz, img.dimy, img.dimx, 1, &img);
291 if(!ret) ret=imgAllocateWithHeader(&k2img, img.dimz, img.dimy, img.dimx, 1, &img);
292 if(!ret) ret=imgAllocateWithHeader(&k2k3img, img.dimz, img.dimy, img.dimx, 1, &img);
293 if(!ret) ret=imgAllocateWithHeader(&kiimg, img.dimz, img.dimy, img.dimx, 1, &img);
294 if(!ret) ret=imgAllocateWithHeader(&dvimg, img.dimz, img.dimy, img.dimx, 1, &img);
295 if(!ret) ret=imgAllocateWithHeader(&vbimg, img.dimz, img.dimy, img.dimx, 1, &img);
296 if(ret) {
297 fprintf(stderr, "Error: cannot allocate memory for result image.\n");
298 imgEmpty(&img); dftEmpty(&tac); imgEmpty(&k3img); imgEmpty(&kiimg);
299 imgEmpty(&k1img); imgEmpty(&k2img); imgEmpty(&dvimg); imgEmpty(&vbimg); imgEmpty(&k2k3img);
300 return(4);
301 }
302 /* set 'frame time' for parametric images */
303 k3img.start[0]=k1img.start[0]=k2img.start[0]=kiimg.start[0]=vbimg.start[0]=
304 dvimg.start[0]=k2k3img.start[0]=0.0;
305 k3img.end[0]=k1img.end[0]=k2img.end[0]=kiimg.end[0]=vbimg.end[0]=
306 dvimg.end[0]=k2k3img.end[0]=60.*fittime;
307 /* set units in parametric images */
308 k3img.unit=k2img.unit=k2k3img.unit=CUNIT_PER_MIN;
309 dvimg.unit=vbimg.unit=CUNIT_ML_PER_ML;
310 k1img.unit=kiimg.unit=CUNIT_ML_PER_ML_PER_MIN;
311 /* and set the more or less necessary things */
314 k3img.isWeight=k1img.isWeight=k2img.isWeight=kiimg.isWeight=
315 vbimg.isWeight=dvimg.isWeight=k2k3img.isWeight=0;
316
317
318 /* Fitting */
319
320 int fittedNr=0, fittedokNr=0, thresholdNr=0;
321
322 if(method==METHOD_NNLS) {
323
324 /* Compute weights for NNLS */
325 for(int m=0; m<dataNr; m++) {
326 if(tac.w[m]<=1.0e-20) tac.w[m]=0.0; else tac.w[m]=sqrt(tac.w[m]);
327 }
328
329 /*
330 * Allocate memory required by NNLS
331 */
332 if(verbose>1) fprintf(stdout, "allocating memory for NNLS\n");
333 int nnls_n=NNLS_N; if(fitVb==0) nnls_n--;
334 int nnls_m=dataNr;
335 int n, m, nnls_index[nnls_n];
336 double **nnls_a, nnls_b[nnls_m], nnls_zz[nnls_m], nnls_x[nnls_n], *nnls_mat,
337 nnls_wp[nnls_n], nnls_rnorm;
338 nnls_mat=(double*)malloc((nnls_n*nnls_m)*sizeof(double));
339 nnls_a=(double**)malloc(nnls_n*sizeof(double*));
340 if(nnls_mat==NULL || nnls_a==NULL) {
341 fprintf(stderr, "Error: cannot allocate memory for NNLS.\n");
342 imgEmpty(&img); dftEmpty(&tac); imgEmpty(&k3img); imgEmpty(&kiimg);
343 imgEmpty(&k1img); imgEmpty(&k2img); imgEmpty(&dvimg); imgEmpty(&vbimg); imgEmpty(&k2k3img);
344 return(4);
345 }
346 for(n=0; n<nnls_n; n++) nnls_a[n]=nnls_mat+n*nnls_m;
347
348
349 /*
350 * Compute pixel-by-pixel
351 */
352 if(verbose>0) fprintf(stdout, "computing NNLS pixel-by-pixel\n");
353 double K1, k3, Vb, Ki, K1k2k3, k2k3;
354 double *ct, *cti, *cp, *cpi, *cpii;
355 cp=tac.voi[0].y; cpi=tac.voi[0].y2; cpii=tac.voi[0].y3;
356 ct=tac.voi[1].y; cti=tac.voi[1].y2;
357 for(int pi=0; pi<img.dimz; pi++) {
358 if(verbose>0) {fprintf(stdout, "."); fflush(stdout);}
359 for(int yi=0; yi<img.dimy; yi++) {
360 for(int xi=0; xi<img.dimx; xi++) {
361 nnls_n=NNLS_N; if(fitVb==0) nnls_n--;
362 /* Set pixel results to zero */
363 k3img.m[pi][yi][xi][0]=0.0;
364 k1img.m[pi][yi][xi][0]=0.0;
365 k2img.m[pi][yi][xi][0]=0.0;
366 k2k3img.m[pi][yi][xi][0]=0.0;
367 kiimg.m[pi][yi][xi][0]=0.0;
368 dvimg.m[pi][yi][xi][0]=0.0;
369 vbimg.m[pi][yi][xi][0]=0.0;
370 /* Copy and integrate pixel curve */
371 for(int fi=0; fi<tac.frameNr; fi++) ct[fi]=img.m[pi][yi][xi][fi];
372 ret=petintegral(tac.x1, tac.x2, ct, tac.frameNr, cti, NULL);
373 if(ret) continue;
374 /* if AUC at the end is less than threshold value, then do nothing more */
375 if(cti[dataNr-1]<threshold) {thresholdNr++; continue;}
376
377 /*
378 * Estimate parameters K1 and possibly Vb
379 */
380
381 /* Fill the NNLS data matrix */
382 for(int m=0; m<nnls_m; m++) {
383 nnls_a[0][m]=-cti[m];
384 nnls_a[1][m]=cpii[m];
385 nnls_a[2][m]=cpi[m];
386 if(fitVb!=0) nnls_a[3][m]=cp[m];
387 nnls_b[m]=ct[m];
388 }
389 if(img.isWeight)
390 for(int m=0; m<nnls_m; m++) {
391 nnls_b[m]*=tac.w[m];
392 for(int n=0; n<nnls_n; n++) nnls_a[n][m]*=tac.w[m];
393 }
394 if(verbose>5 && pi==img.dimz/2 && yi==img.dimy/3 && xi==img.dimx/3) {
395 printf("Matrix A Array B\n");
396 for(m=0; m<nnls_m; m++) {
397 printf("%12.3f %12.3f %12.3f %12.3f\n",
398 nnls_a[0][m], nnls_a[1][m], nnls_a[2][m], nnls_b[m]);
399 }
400 }
401 /* NNLS */
402 ret=nnls(nnls_a, nnls_m, nnls_n, nnls_b, nnls_x, &nnls_rnorm, nnls_wp, nnls_zz, nnls_index);
403 if(ret!=0) { /* no solution is possible */
404 if(verbose>3) printf("no solution possible (%d)\n", ret);
405 if(verbose>4) printf("nnls_n=%d nnls_m=%d\n", nnls_n, nnls_m);
406 for(int n=0; n<nnls_n; n++) nnls_x[n]=0.0;
407 nnls_rnorm=0.0;
408 continue;
409 }
410
411 if(fitVb!=0) Vb=nnls_x[3]; else Vb=0.0;
412 if(Vb>=0.99) {
413 fittedNr++;
414 vbimg.m[pi][yi][xi][0]=Vb;
415 continue; // leave other parameters to zero
416 }
417 k2k3=nnls_x[0]; // k2+k3
418 K1=nnls_x[2]-Vb*k2k3;
419 if(Vb<0.99) k3=nnls_x[1]/K1; else k3=0.0;
420 if(Vb<0.99) K1k2k3=K1/k2k3; else K1k2k3=0.0;
421 if(Vb<0.99) Ki=nnls_x[1]/k2k3; else Ki=0.0;
422 if(Vb<0.9) { // If Vb was fitted, then scale to tissue volume without blood
423 K1/=(1.0-Vb);
424 Ki/=(1.0-Vb);
425 K1k2k3/=(1.0-Vb);
426 }
427 fittedNr++;
428
429 /* Subtract vascular contribution from tissue data */
430 if(fitVb!=0 && Vb>0.0 && Vb<1.0) {
431 for(int fi=0; fi<tac.frameNr; fi++) ct[fi]-=Vb*cp[fi];
432 for(int fi=0; fi<tac.frameNr; fi++) ct[fi]/=(1.0-Vb);
433 ret=petintegral(tac.x1, tac.x2, ct, tac.frameNr, cti, NULL);
434 if(ret) continue;
435 }
436
437 /*
438 * Estimate Ki and Vd=K1/(k2+k3)
439 */
440 if(fitVb!=0) {
441 nnls_n--; /* Vb is not fitted, already corrected */
442 for(int n=0; n<nnls_n; n++) nnls_a[n]=nnls_mat+n*nnls_m;
443 }
444 /* Fill the NNLS data matrix */
445 for(m=0; m<nnls_m; m++) {
446 nnls_a[0][m]=-ct[m];
447 nnls_a[1][m]=cpii[m];
448 nnls_a[2][m]=cpi[m];
449 nnls_b[m]=cti[m];
450 }
451 if(img.isWeight) for(m=0; m<nnls_m; m++) {
452 nnls_b[m]*=tac.w[m];
453 for(n=0; n<nnls_n; n++) nnls_a[n][m]*=tac.w[m];
454 }
455 if(verbose>5 && pi==img.dimz/2 && yi==img.dimy/3 && xi==img.dimx/3) {
456 printf("Matrix A Array B\n");
457 for(m=0; m<nnls_m; m++) {
458 printf("%12.3f %12.3f %12.3f %12.3f\n",
459 nnls_a[0][m], nnls_a[1][m], nnls_a[2][m], nnls_b[m]);
460 }
461 }
462 /* NNLS */
463 ret=nnls(nnls_a, nnls_m, nnls_n, nnls_b, nnls_x, &nnls_rnorm, nnls_wp, nnls_zz, nnls_index);
464 if(ret!=0) { /* no solution is possible */
465 if(verbose>3) printf(" no solution possible\n");
466 for(n=0; n<nnls_n; n++) nnls_x[n]=0.0;
467 nnls_rnorm=0.0;
468 continue;
469 }
470 Ki=nnls_x[1]; K1k2k3=nnls_x[2];
471
472 /*
473 * Estimate k3
474 */
475 k3=0.0;
476 /* Fill the NNLS data matrix */
477 for(m=0; m<nnls_m; m++) {
478 nnls_a[0][m]=-cpii[m];
479 nnls_a[1][m]=cti[m];
480 nnls_a[2][m]=ct[m];
481 nnls_b[m]=cpi[m];
482 }
483 if(img.isWeight) for(m=0; m<nnls_m; m++) {
484 nnls_b[m]*=tac.w[m];
485 for(n=0; n<nnls_n; n++) nnls_a[n][m]*=tac.w[m];
486 }
487 if(verbose>5 && pi==img.dimz/2 && yi==img.dimy/3 && xi==img.dimx/3) {
488 printf("Matrix A Array B\n");
489 for(m=0; m<nnls_m; m++) {
490 printf("%12.3f %12.3f %12.3f %12.3f\n",
491 nnls_a[0][m], nnls_a[1][m], nnls_a[2][m], nnls_b[m]);
492 }
493 }
494 /* NNLS */
495 ret=nnls(nnls_a, nnls_m, nnls_n, nnls_b, nnls_x, &nnls_rnorm, nnls_wp, nnls_zz, nnls_index);
496 if(ret!=0) { /* no solution is possible */
497 if(verbose>3) printf(" no solution possible\n");
498 for(n=0; n<nnls_n; n++) nnls_x[n]=0.0;
499 nnls_rnorm=0.0;
500 continue;
501 }
502 k3=nnls_x[0]; fittedNr++;
503
504 /* Put results to output images */
505 k3img.m[pi][yi][xi][0]=k3; if(k3>0.0) fittedokNr++;
506 k1img.m[pi][yi][xi][0]=K1;
507 vbimg.m[pi][yi][xi][0]=Vb;
508 dvimg.m[pi][yi][xi][0]=K1k2k3;
509 kiimg.m[pi][yi][xi][0]=Ki;
510 k2k3img.m[pi][yi][xi][0]=k2k3;
511 if(Ki>0.0) k2img.m[pi][yi][xi][0]=k3*(K1/Ki-1.0);
512 else if(K1k2k3>0.0) k2img.m[pi][yi][xi][0]=K1/K1k2k3;
513 } /* next column */
514 } /* next row */
515 } /* next plane */
516 if(verbose>0) {fprintf(stdout, " done.\n"); fflush(stdout);}
517 free(nnls_mat); free(nnls_a);
518 /* Show statistics on how we succeeded */
519 n=(int)img.dimx*(int)img.dimy*(int)img.dimz;
520 if(verbose>0) {
521 fprintf(stdout, "%d out of %d pixels were fitted; %d pixels ok.\n", fittedokNr, n, fittedNr);
522 fprintf(stdout, "%d pixels were thresholded.\n", thresholdNr);
523 }
524
525 } else {
526
527 fprintf(stderr, "Error: selected method not available.");
528 imgEmpty(&img); dftEmpty(&tac); imgEmpty(&k3img); imgEmpty(&kiimg);
529 imgEmpty(&k1img); imgEmpty(&k2img); imgEmpty(&dvimg); imgEmpty(&vbimg); imgEmpty(&k2k3img);
530 return(1);
531
532 }
533
534 /* No need for dynamic image any more */
535 imgEmpty(&img); dftEmpty(&tac);
536
537
538 /*
539 * Save parametric images
540 */
541
542 ret=imgWrite(k3file, &k3img);
543 if(!ret && k1file[0]) ret=imgWrite(k1file, &k1img);
544 if(!ret && k2file[0]) ret=imgWrite(k2file, &k2img);
545 if(!ret && k2k3file[0]) ret=imgWrite(k2k3file, &k2k3img);
546 if(!ret && kifile[0]) ret=imgWrite(kifile, &kiimg);
547 if(!ret && vbfile[0]) ret=imgWrite(vbfile, &vbimg);
548 if(!ret && dvfile[0]) ret=imgWrite(dvfile, &dvimg);
549 imgEmpty(&k3img); imgEmpty(&kiimg); imgEmpty(&k1img);
550 imgEmpty(&k2img); imgEmpty(&dvimg); imgEmpty(&vbimg); imgEmpty(&k2k3img);
551 if(ret) {
552 fprintf(stderr, "Error: cannot write parametric image.\n");
553 return(11);
554 }
555 if(verbose>0) fprintf(stdout, "Parametric image(s) saved.\n");
556
557 return(0);
558}
559/*****************************************************************************/
560
561/*****************************************************************************/
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
Header file for libtpcmodext.
int imgSetWeights(IMG *img, int wmet, int verbose)
Voi * voi
int timeunit
double * w
double * x1
double * x2
int frameNr
unsigned short int dimx
float **** m
char decayCorrection
char unit
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