12#include "tpcclibConfig.h"
32static char *info[] = {
33 "Computation of parametric images of K1A, VbA, K1B, VbB, and k2, from",
34 "dynamic PET image in ECAT, NIfTI, or Analyze format applying",
35 "reversible on1-tissue compartmental model with two input functions:",
36 " Cpet(t) = VbA*CbA(t) + VbB*CbB(t) + Ct(t)",
37 " dCt(t) = K1A*CbA(t) + K1B*CbB(t) - k2*Ct(t)",
39 "The compartmental models are transformed to general linear least squares",
40 "functions (1), which are solved using Lawson-Hanson non-negative least",
41 "squares (NNLS) algorithm (2).",
43 "Dynamic PET image and input TACs must be corrected for decay",
44 "to the tracer injection time.",
46 "Usage: @P [Options] iAfile iBfile imgfile k1Afile k1Bfile vbAfile vbBfile k2file",
50 " Pixels with AUC less than (threshold/100 x PTAC AUC) are set to zero;",
52 " -end=<Fit end time (min)>",
53 " Use data from 0 to end time; by default, model is fitted to all frames.",
62 "The units of pixel values in the parametric images are ml/(min*ml) for K1",
63 "1/min for k2, and ml/ml for Vb.",
66 "1. Blomqvist G. On the construction of functional maps in positron",
67 " emission tomography. J Cereb Blood Flow Metab 1984;4:629-632.",
68 "2. Lawson CL & Hanson RJ. Solving least squares problems.",
69 " Prentice-Hall, 1974, ISBN 0-89871-356-0.",
71 "See also: imglhk3, imgcbv, imgki, fitk3",
73 "Keywords: image, modelling, irreversible uptake, NNLS",
89enum {METHOD_UNKNOWN, METHOD_NNLS, METHOD_BVLS};
90static char *method_str[] = {
"unknown",
"NNLS",
"BVLS", 0};
97int main(
int argc,
char **argv)
99 int ai, help=0, version=0, verbose=1;
100 char inpAfile[FILENAME_MAX], inpBfile[FILENAME_MAX], petfile[FILENAME_MAX];
101 char k1Afile[FILENAME_MAX], vbAfile[FILENAME_MAX];
102 char k1Bfile[FILENAME_MAX], vbBfile[FILENAME_MAX];
103 char k2file[FILENAME_MAX];
104 float calcThreshold=0.01;
107 int method=METHOD_NNLS;
113 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
114 inpAfile[0]=inpBfile[0]=petfile[0]=(char)0;
115 k1Afile[0]=k1Bfile[0]=k2file[0]=vbAfile[0]=vbBfile[0]=(char)0;
117 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
119 char *cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(cptr==NULL)
continue;
120 if(strncasecmp(cptr,
"THR=", 4)==0) {
122 if(!ret && v>=0.0 && v<=200.0) {calcThreshold=(float)(0.01*v);
continue;}
123 }
else if(strncasecmp(cptr,
"END=", 4)==0) {
124 ret=
atof_with_check(cptr+4, &fittime);
if(!ret && fittime>0.0)
continue;
125 }
else if(strcasecmp(cptr,
"WFA")==0) {
127 }
else if(strcasecmp(cptr,
"WF")==0) {
129 }
else if(strcasecmp(cptr,
"W1")==0) {
131 }
else if(strcasecmp(cptr,
"NNLS")==0) {
132 method=METHOD_NNLS;
continue;
133 }
else if(strcasecmp(cptr,
"BVLS")==0) {
134 method=METHOD_BVLS;
continue;
136 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
142 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
147 if(ai<argc)
strlcpy(inpAfile, argv[ai++], FILENAME_MAX);
148 if(ai<argc)
strlcpy(inpBfile, argv[ai++], FILENAME_MAX);
149 if(ai<argc)
strlcpy(petfile, argv[ai++], FILENAME_MAX);
150 if(ai<argc)
strlcpy(k1Afile, argv[ai++], FILENAME_MAX);
151 if(ai<argc)
strlcpy(k1Bfile, argv[ai++], FILENAME_MAX);
152 if(ai<argc)
strlcpy(vbAfile, argv[ai++], FILENAME_MAX);
153 if(ai<argc)
strlcpy(vbBfile, argv[ai++], FILENAME_MAX);
154 if(ai<argc)
strlcpy(k2file, argv[ai++], FILENAME_MAX);
155 if(ai<argc) {fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
return(1);}
158 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
return(1);}
161 printf(
"inpAfile := %s\n", inpAfile);
162 printf(
"inpBfile := %s\n", inpBfile);
163 printf(
"petfile := %s\n", petfile);
164 printf(
"k1Afile := %s\n", k1Afile);
165 printf(
"vbAfile := %s\n", vbAfile);
166 printf(
"k1Bfile := %s\n", k1Bfile);
167 printf(
"vbBfile := %s\n", vbBfile);
168 printf(
"k2file := %s\n", k2file);
169 printf(
"calcThreshold :=%g\n", calcThreshold);
170 printf(
"weights := %d\n", weights);
171 printf(
"method := %s\n", method_str[method]);
172 if(fittime>0.0) printf(
"required_fittime := %g min\n", fittime);
181 if(verbose>0) printf(
"reading data files\n");
187 petfile, NULL, inpAfile, inpBfile, NULL, &fittime, &dataNr, &img,
188 NULL, &tac, 1, stdout, verbose-2, errmsg);
190 fprintf(stderr,
"Error: %s.\n", errmsg);
191 if(verbose>1) printf(
" ret := %d\n", ret);
195 if(verbose>0) fprintf(stderr,
"Warning: missing pixel values.\n");
198 for(
int ri=0; ri<tac.
voiNr; ri++) {
199 for(
int fi=0; fi<tac.
frameNr; fi++) tac.
voi[ri].
y2[fi]/=60.0;
200 for(
int fi=0; fi<tac.
frameNr; fi++) tac.
voi[ri].
y3[fi]/=3600.0;
205 printf(
"fittimeFinal := %g min\n", fittime);
206 printf(
"dataNr := %d\n", dataNr);
210 fprintf(stderr,
"Error: too few time frames for fitting.\n");
217 if(verbose>1) fprintf(stdout,
"allocating working memory for pixel TACs\n");
220 fprintf(stderr,
"Error: cannot allocate memory.\n");
221 if(verbose>0) printf(
"ret := %d\n", ret);
224 strcpy(tac.
voi[0].
name,
"inputA");
225 strcpy(tac.
voi[1].
name,
"inputB");
226 strcpy(tac.
voi[2].
name,
"tissue");
230 fprintf(stderr,
"Error: cannot calculate weights.\n");
233 for(
int i=0; i<dataNr; i++) tac.
w[i]=img.
weight[i];
236 double threshold=calcThreshold*tac.
voi[0].
y2[dataNr-1];
237 if(verbose>1) printf(
"threshold_AUC := %g\n", threshold);
243 if(verbose>1) fprintf(stdout,
"allocating memory for parametric image data\n");
255 fprintf(stderr,
"Error: cannot allocate memory for result image.\n");
262 k1Aimg.
end[0]=k1Bimg.
end[0]=vbAimg.
end[0]=vbBimg.
end[0]=k2img.
end[0]=60.*fittime;
264 k1Aimg.
unit=k1Bimg.
unit=CUNIT_ML_PER_ML_PER_MIN;
265 vbAimg.
unit=vbBimg.
unit=CUNIT_ML_PER_ML;
266 k2img.
unit=CUNIT_PER_MIN;
271 int fittedNr=0, fittedokNr=0, thresholdNr=0;
273 if(method==METHOD_NNLS) {
276 for(
int m=0; m<dataNr; m++) {
277 if(tac.
w[m]<=1.0e-20) tac.
w[m]=0.0;
else tac.
w[m]=sqrt(tac.
w[m]);
283 if(verbose>1) fprintf(stdout,
"allocating memory for NNLS\n");
286 int n, m, nnls_index[nnls_n];
287 double **nnls_a, nnls_b[nnls_m], nnls_zz[nnls_m], nnls_x[nnls_n], *nnls_mat,
288 nnls_wp[nnls_n], nnls_rnorm;
289 nnls_mat=(
double*)malloc((nnls_n*nnls_m)*
sizeof(
double));
290 nnls_a=(
double**)malloc(nnls_n*
sizeof(
double*));
291 if(nnls_mat==NULL || nnls_a==NULL) {
292 fprintf(stderr,
"Error: cannot allocate memory for NNLS.\n");
297 for(n=0; n<nnls_n; n++) nnls_a[n]=nnls_mat+n*nnls_m;
303 if(verbose>0) fprintf(stdout,
"computing NNLS pixel-by-pixel\n");
304 double *ct, *cti, *cpA, *cpAi, *cpB, *cpBi;
308 for(
int pi=0; pi<img.
dimz; pi++) {
309 if(verbose>0) {fprintf(stdout,
"."); fflush(stdout);}
310 for(
int yi=0; yi<img.
dimy; yi++) {
311 for(
int xi=0; xi<img.
dimx; xi++) {
312 double K1A=0.0, K1B=0.0, k2=0.0, VbA=0.0, VbB=0.0;
314 k1Aimg.
m[pi][yi][xi][0]=0.0;
315 vbAimg.
m[pi][yi][xi][0]=0.0;
316 k1Bimg.
m[pi][yi][xi][0]=0.0;
317 vbBimg.
m[pi][yi][xi][0]=0.0;
318 k2img.
m[pi][yi][xi][0]=0.0;
320 for(
int fi=0; fi<tac.
frameNr; fi++) ct[fi]=img.
m[pi][yi][xi][fi];
324 if(cti[dataNr-1]<threshold) {thresholdNr++;
continue;}
331 for(
int m=0; m<nnls_m; m++) {
332 nnls_a[0][m]=cpAi[m];
333 nnls_a[1][m]=cpBi[m];
336 nnls_a[4][m]=-cti[m];
340 for(
int m=0; m<nnls_m; m++) {
342 for(
int n=0; n<nnls_n; n++) nnls_a[n][m]*=tac.
w[m];
344 if(verbose>5 && pi==img.
dimz/2 && yi==img.
dimy/3 && xi==img.
dimx/3) {
345 printf(
"Matrix A Array B\n");
346 for(m=0; m<nnls_m; m++) {
347 printf(
"%12.3f %12.3f %12.3f %12.3f %12.3f %12.3f\n",
348 nnls_a[0][m], nnls_a[1][m], nnls_a[2][m], nnls_a[3][m], nnls_a[4][m], nnls_b[m]);
352 ret=
nnls(nnls_a, nnls_m, nnls_n, nnls_b, nnls_x, &nnls_rnorm, nnls_wp, nnls_zz, nnls_index);
354 if(verbose>3) printf(
"no solution possible (%d)\n", ret);
355 if(verbose>4) printf(
"nnls_n=%d nnls_m=%d\n", nnls_n, nnls_m);
356 for(
int n=0; n<nnls_n; n++) nnls_x[n]=0.0;
365 K1A=nnls_x[0];
if(VbA<1.0) K1A-=VbA*k2;
366 K1B=nnls_x[1];
if(VbB<1.0) K1B-=-VbB*k2;
367 if((K1A+K1B)>=0.0 && (VbA+VbB)>=0.0 && (VbA+VbB)<=1.0) fittedokNr++;
369 k1Aimg.
m[pi][yi][xi][0]=K1A;
370 vbAimg.
m[pi][yi][xi][0]=VbA;
371 k1Bimg.
m[pi][yi][xi][0]=K1B;
372 vbBimg.
m[pi][yi][xi][0]=VbB;
373 k2img.
m[pi][yi][xi][0]=k2;
377 if(verbose>0) {fprintf(stdout,
" done.\n"); fflush(stdout);}
378 free(nnls_mat); free(nnls_a);
382 fprintf(stdout,
"%d out of %d pixels were fitted; %d pixels ok.\n", fittedokNr, n, fittedNr);
383 fprintf(stdout,
"%d pixels were thresholded.\n", thresholdNr);
388 fprintf(stderr,
"Error: selected method not available.");
404 if(!ret) ret=
imgWrite(vbAfile, &vbAimg);
405 if(!ret) ret=
imgWrite(k1Bfile, &k1Bimg);
406 if(!ret) ret=
imgWrite(vbBfile, &vbBimg);
407 if(!ret) ret=
imgWrite(k2file, &k2img);
410 fprintf(stderr,
"Error: cannot write parametric image.\n");
413 if(verbose>0) fprintf(stdout,
"Parametric image(s) saved.\n");
int atof_with_check(char *double_as_string, double *result_value)
int dftAddmem(DFT *dft, int voiNr)
int dftTimeunitConversion(DFT *dft, int tunit)
unsigned long long imgNaNs(IMG *img, int fix)
int imgAllocateWithHeader(IMG *image, int planes, int rows, int columns, int frames, IMG *image_from)
void imgEmpty(IMG *image)
int imgWrite(const char *fname, IMG *img)
int petintegral(double *x1, double *x2, double *y, int nr, double *ie, double *iie)
Integrate PET TAC data to frame mid times.
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)
size_t strlcpy(char *dst, const char *src, size_t dstsize)
int tpcHtmlUsage(const char *program, char *text[], const char *path)
void tpcPrintBuild(const char *program, FILE *fp)
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Header file for libtpcmodel.
int nnls(double **a, int m, int n, double *b, double *x, double *rnorm, double *w, double *zz, int *index)
Header file for libtpcmodext.
int imgSetWeights(IMG *img, int wmet, int verbose)
char name[MAX_REGIONNAME_LEN+1]