10#include "tpcclibConfig.h"
30static char *info[] = {
31 "Computation of parametric image of blood and distribution volume (Vb and Vt)",
32 "from dynamic PET image in ECAT, NIfTI, or Analyze format applying",
33 "one-tissue compartmental model with arterial blood input.",
34 "The compartmental models are transformed to general linear least squares",
35 "functions, which are solved using Lawson-Hanson non-negative least squares",
36 "(NNLS) algorithm (1). Vt is estimated directly without division (2, 3, 4).",
38 "Dynamic PET image and plasma time-activity curve (PTAC) must be corrected",
39 "for decay to the tracer injection time.",
41 "Usage: @P [Options] btacfile imgfile vbfile vtfile",
45 " Pixels with AUC less than (threshold/100 x BTAC AUC) are set to zero",
47 " -end=<Fit end time (min)>",
48 " Use data from 0 to end time; by default, model is fitted to all frames.",
50 " Upper limit for Vt values; by default 1000.",
52 " Vt includes Vb; by default not.",
54 " Set Vt to zero in pixels which seem to have irreversible uptake.",
56 " Dynamic image with Vb correction is saved.",
59 "The unit of voxel values in the Vt image is (ml blood)/(ml tissue).",
62 " @P ua3818ab.kbq ua3818dy1.v ua3818vb.v ua3818vt.v",
65 "1. Lawson CL & Hanson RJ. Solving least squares problems.",
66 " Prentice-Hall, 1974, ISBN 0-89871-356-0.",
67 "2. Zhou Y, Brasic J, Endres CJ, Kuwabara H, Kimes A, Contoreggi C, Maini A,",
68 " Ernst M, Wong DF. Binding potential image based statistical mapping for",
69 " detection of dopamine release by [11C]raclopride dynamic PET.",
70 " NeuroImage 2002;16(3):S91.",
71 "3. Zhou Y, Brasic JR, Ye W, Dogan AS, Hilton J, Singer HS, Wong DF.",
72 " Quantification of cerebral serotonin binding in normal controls and",
73 " subjects with Tourette's syndrome using [11C]MDL 100,907 and",
74 " (+)[11C]McN 5652 dynamic PET with parametric imaging approach.",
75 " NeuroImage 2004;22(Suppl 2):T98.",
76 "4. Hagelberg N, Aalto S, Kajander J, Oikonen V, Hinkka S, NĂ¥gren K,",
77 " Hietala J, Scheinin H. Alfentanil increases cortical dopamine D2/D3",
78 " receptor binding in healthy subjects. Pain 2004;109:86-93.",
80 "See also: imglhdv, imglhk3, lhsol, imgdv, imgratio, img2tif",
82 "Keywords: image, modelling, distribution volume, vascular fraction, NNLS",
101int main(
int argc,
char **argv)
103 int ai, help=0, version=0, verbose=1;
105 char inpfile[FILENAME_MAX], petfile[FILENAME_MAX];
106 char vtfile[FILENAME_MAX], vbfile[FILENAME_MAX];
107 char bcfile[FILENAME_MAX];
108 float calcThreshold=0.0;
109 double upperLimit=1000.0;
120 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
121 inpfile[0]=petfile[0]=vtfile[0]=vbfile[0]=bcfile[0]=(char)0;
123 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
125 cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(cptr==NULL)
continue;
126 if(strncasecmp(cptr,
"THR=", 4)==0) {
128 if(!ret && v>=0.0 && v<=200.0) {calcThreshold=(float)(0.01*v);
continue;}
129 }
else if(strncasecmp(cptr,
"END=", 4)==0) {
130 fittime=
atof_dpi(cptr+4);
if(fittime>0.0)
continue;
131 }
else if(strncasecmp(cptr,
"WITHVB=", 5)==0) {
132 withoutVb=0;
continue;
133 }
else if(strncasecmp(cptr,
"WITHOUTVB=", 5)==0) {
134 withoutVb=1;
continue;
135 }
else if(*cptr==
'w' || *cptr==
'W') {
137 }
else if(strncasecmp(cptr,
"MAX=", 4)==0) {
138 upperLimit=
atof_dpi(cptr+4);
if(upperLimit>0.0)
continue;
139 }
else if(strcasecmp(cptr,
"IRRZ")==0) {
140 irrevZero=1;
continue;
141 }
else if(strncasecmp(cptr,
"BC=", 3)==0) {
142 strlcpy(bcfile, cptr+3, FILENAME_MAX);
continue;
144 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
149 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
154 if(ai<argc)
strlcpy(inpfile, argv[ai++], FILENAME_MAX);
155 if(ai<argc)
strlcpy(petfile, argv[ai++], FILENAME_MAX);
156 if(ai<argc)
strlcpy(vbfile, argv[ai++], FILENAME_MAX);
157 if(ai<argc)
strlcpy(vtfile, argv[ai++], FILENAME_MAX);
158 if(ai<argc) {fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
return(1);}
161 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
164 if(strcasecmp(petfile, vtfile)==0 || strcasecmp(petfile, vbfile)==0 ||
165 strcasecmp(vtfile, vbfile)==0 || strcasecmp(inpfile, vbfile)==0)
167 fprintf(stderr,
"Error: check the output filenames.\n");
172 printf(
"inpfile := %s\n", inpfile);
173 printf(
"petfile := %s\n", petfile);
174 printf(
"vbfile := %s\n", vbfile);
175 printf(
"vtfile := %s\n", vtfile);
176 if(bcfile[0]) printf(
"bcfile := %s\n", bcfile);
177 printf(
"calcThreshold :=%g\n", calcThreshold);
178 if(upperLimit>0.0) printf(
"upperLimit := %g\n", upperLimit);
179 printf(
"weight := %d\n", weight);
180 printf(
"withoutVb := %d\n", withoutVb);
181 if(fittime>0.0) printf(
"required_fittime := %g min\n", fittime);
182 printf(
"irrevZero := %d\n", irrevZero);
191 if(verbose>0) printf(
"reading data files\n");
198 petfile, NULL, inpfile, NULL, NULL, &fittime, &dataNr, &img,
199 NULL, &tac, 1, stdout, verbose-2, tmp);
201 fprintf(stderr,
"Error: %s.\n", tmp);
202 if(verbose>1) printf(
" ret := %d\n", ret);
206 if(verbose>0) fprintf(stderr,
"Warning: missing pixel values.\n");
210 for(
int fi=0; fi<tac.
frameNr; fi++) tac.
voi[0].
y2[fi]/=60.0;
211 for(
int fi=0; fi<tac.
frameNr; fi++) tac.
voi[0].
y3[fi]/=3600.0;
215 printf(
"fittimeFinal := %g min\n", fittime);
216 printf(
"dataNr := %d\n", dataNr);
220 fprintf(stderr,
"Error: too few time frames for fitting.\n");
227 if(verbose>1) fprintf(stdout,
"allocating working memory for pixel TACs\n");
230 fprintf(stderr,
"Error: cannot allocate memory.\n");
231 if(verbose>0) printf(
"ret := %d\n", ret);
234 strcpy(tac.
voi[0].
name,
"input");
235 strcpy(tac.
voi[1].
name,
"tissue");
241 if(verbose>1) fprintf(stdout,
"allocating memory for parametric image data\n");
247 fprintf(stderr,
"Error: cannot allocate memory for result image.\n");
252 vbimg.
end[0]=vtimg.
end[0]=60.*fittime;
253 vbimg.
unit=vtimg.
unit=CUNIT_ML_PER_ML;
259 if(verbose>1) fprintf(stdout,
"allocating memory for NNLS\n");
260 int n, m, nnls_n, nnls_m, nnls_index[NNLS_N];
261 double *nnls_a[NNLS_N], *nnls_b, *nnls_zz, nnls_x[NNLS_N], *nnls_mat,
262 nnls_wp[NNLS_N], *dptr, nnls_rnorm;
263 nnls_n=NNLS_N; nnls_m=dataNr;
264 nnls_mat=(
double*)malloc(((nnls_n+2)*nnls_m)*
sizeof(
double));
266 fprintf(stderr,
"Error: cannot allocate memory for NNLS.\n");
270 for(n=0, dptr=nnls_mat; n<nnls_n; n++) {nnls_a[n]=dptr; dptr+=nnls_m;}
271 nnls_b=dptr; dptr+=nnls_m; nnls_zz=dptr;
281 for(m=0; m<nnls_m; m++) tac.
w[m]=img.
weight[m];
282 for(m=0; m<nnls_m; m++) {
283 if(tac.
w[m]<=1.0e-20) tac.
w[m]=0.0;
else tac.
w[m]=sqrt(tac.
w[m]);
292 double threshold=calcThreshold*tac.
voi[0].
y2[dataNr-1];
293 if(verbose>1) printf(
"threshold_AUC := %g\n", threshold);
294 if(verbose>0) {fprintf(stdout,
"computing NNLS pixel-by-pixel\n"); fflush(stdout);}
296 for(
int pi=0; pi<img.
dimz; pi++) {
297 if(verbose>1) printf(
"computing plane %d\n", img.
planeNumber[pi]);
298 else if(verbose>0 && img.
dimz>2) fprintf(stdout,
".");
299 if(verbose>0) fflush(stdout);
300 for(
int yi=0; yi<img.
dimy; yi++) {
301 for(
int xi=0; xi<img.
dimx; xi++) {
303 vbimg.
m[pi][yi][xi][0]=0.0;
304 vtimg.
m[pi][yi][xi][0]=0.0;
306 for(
int fi=0; fi<tac.
frameNr; fi++)
307 tac.
voi[1].
y[fi]=img.
m[pi][yi][xi][fi];
311 if(tac.
voi[1].
y2[dataNr-1]<threshold)
continue;
314 for(m=0; m<nnls_m; m++) {
315 nnls_a[0][m]=tac.
voi[0].
y[m];
316 nnls_a[1][m]=tac.
voi[0].
y2[m];
317 nnls_a[2][m]=-tac.
voi[1].
y2[m];
318 nnls_b[m]=tac.
voi[1].
y[m];
321 for(m=0; m<nnls_m; m++) {
323 for(n=0; n<nnls_n; n++) nnls_a[n][m]*=tac.
w[m];
327 ret=
nnls(nnls_a, nnls_m, nnls_n, nnls_b, nnls_x, &nnls_rnorm, nnls_wp, nnls_zz, nnls_index);
329 for(n=0; n<nnls_n; n++) nnls_x[n]=0.0;
331 }
else if(ret==1) { }
334 vbimg.
m[pi][yi][xi][0]=nnls_x[0];
337 for(
int i=0; i<tac.
frameNr; i++) tac.
voi[1].
y[i]-=nnls_x[0]*tac.
voi[0].
y[i];
340 for(m=0; m<nnls_m; m++) {
341 nnls_a[0][m]=tac.
voi[0].
y2[m];
342 nnls_a[1][m]=-tac.
voi[1].
y[m];
343 nnls_b[m]=tac.
voi[1].
y2[m];
346 for(m=0; m<nnls_m; m++) {
348 for(n=0; n<2; n++) nnls_a[n][m]*=tac.
w[m];
352 ret=
nnls(nnls_a, nnls_m, 2, nnls_b, nnls_x, &nnls_rnorm, nnls_wp, nnls_zz, nnls_index);
354 for(n=0; n<2; n++) nnls_x[n]=0.0;
356 }
else if(ret==1) { }
359 vtimg.
m[pi][yi][xi][0]=nnls_x[0];
361 if(nnls_x[1]<1.0E-20 && nnls_x[0]>1.0E-03) {
362 if(irrevZero) vtimg.
m[pi][yi][xi][0]=0.0;
else vtimg.
m[pi][yi][xi][0]=upperLimit;
366 vtimg.
m[pi][yi][xi][0]+=vbimg.
m[pi][yi][xi][0];
367 if(vtimg.
m[pi][yi][xi][0]<0.0) vtimg.
m[pi][yi][xi][0]=0.0;
373 if(!(nnls_x[1]>1.0E-10)) {
374 vtimg.
m[pi][yi][xi][0]=0.0;
378 if((!(nnls_x[1]>1.0E-04) && !(nnls_x[2]>1.0E-04)) || !((nnls_x[1]+nnls_x[2])>1.0E-03)) {
379 vtimg.
m[pi][yi][xi][0]=0.0;
383 if(!(nnls_x[2]>1.0E-06)) {
385 if(nnls_x[1]>1.0E-03) vtimg.
m[pi][yi][xi][0]=upperLimit;
386 else vtimg.
m[pi][yi][xi][0]=0.0;
390 for(m=0; m<nnls_m; m++) {
391 nnls_a[0][m]=tac.
voi[0].
y2[m];
392 nnls_a[1][m]=tac.
voi[0].
y[m];
393 nnls_a[2][m]=-tac.
voi[1].
y[m];
394 nnls_b[m]=tac.
voi[1].
y2[m];
397 for(m=0; m<nnls_m; m++) {
399 for(n=0; n<nnls_n; n++) nnls_a[n][m]*=tac.
w[m];
403 ret=
nnls(nnls_a, nnls_m, nnls_n, nnls_b, nnls_x, &nnls_rnorm, nnls_wp, nnls_zz, nnls_index);
405 for(n=0; n<nnls_n; n++) nnls_x[n]=0.0;
407 }
else if(ret==1) { }
410 vtimg.
m[pi][yi][xi][0]=nnls_x[0];
413 vtimg.
m[pi][yi][xi][0]-=vbimg.
m[pi][yi][xi][0];
414 if(vtimg.
m[pi][yi][xi][0]<0.0) vtimg.
m[pi][yi][xi][0]=0.0;
419 if(vtimg.
m[pi][yi][xi][0]>upperLimit) vtimg.
m[pi][yi][xi][0]=upperLimit;
425 if(verbose>0) {fprintf(stdout,
" done.\n"); fflush(stdout);}
437 fprintf(stderr,
"Error: cannot allocate memory.\n");
441 for(
int pi=0; pi<img.
dimz; pi++) {
442 for(
int yi=0; yi<img.
dimy; yi++) {
443 for(
int xi=0; xi<img.
dimx; xi++) {
444 for(
int ti=0; ti<img.
dimt; ti++) {
445 double v=img.
m[pi][yi][xi][ti]-vbimg.
m[pi][yi][xi][ti]*tac.
voi[0].
y[ti];
447 bcimg.
m[pi][yi][xi][ti]=v;
453 fprintf(stderr,
"Error: %s\n", bcimg.
statmsg);
457 if(verbose>0) {fprintf(stdout,
"Vb corrected image %s saved.\n", bcfile); fflush(stdout);}
471 fprintf(stderr,
"Error: %s\n", vbimg.
statmsg);
475 if(verbose>0) {fprintf(stdout,
"Vb image %s saved.\n", vbfile); fflush(stdout);}
478 fprintf(stderr,
"Error: %s\n", vtimg.
statmsg);
482 if(verbose>0) {fprintf(stdout,
"Vt image %s saved.\n", vtfile); fflush(stdout);}
int atof_with_check(char *double_as_string, double *result_value)
double atof_dpi(char *str)
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.
char name[MAX_REGIONNAME_LEN+1]