10#include "tpcclibConfig.h"
28static char *info[] = {
29 "Calculates the distribution volume (Vt, DV) or distribution volume ratio (DVR)",
30 "from dynamic PET image in ECAT, NIfTI-1, or Analyze 7.5 format,",
31 "applying the multiple time graphical analysis (MTGA) approach for reversible",
32 "tracer uptake (Logan plot) (1, 2, 3).",
33 "Simple non-iterative perpendicular line fitting algorithm (4) is applied",
34 "in determination of the slope of the Logan plot.",
36 "Usage: @P [Options] input image starttime resultimage",
38 "Input can be either a TAC file containing arterial plasma PTAC or reference",
39 "region TTAC. Data must be in the same concentration units as the data in",
40 "image, and times in min; however, if units are specified inside the input",
41 "and image file, the program can automatically convert units.",
42 "Start time of the linear fit must be given in minutes; set to zero to",
43 "let the program automatically determine the start time (not recommended).",
46 " -k2=<k2 of reference region>",
47 " With reference region input it may be necessary to specify also the",
48 " population average for reference region k2 (2).",
50 " Pixels with AUC less than (threshold/100 x input) are set to zero.",
53 " Upper limit for Vt or DVR values; by default max is set pixel-wise",
54 " to 10 times the AUC ratio.",
56 " Lower limit for Vt or DVR values; 0 by default.",
58 " Remove parametric pixel values that are over 4x higher than",
59 " their closest neighbours.",
60 " -end=<Fit end time (min)>",
61 " By default line is fitted to the end of data. Use this option to enter",
64 " Y axis intercepts times -1 are written as an image in specified file.",
66 " Numbers of selected plot data points are written as an image.",
70 " @P ua3818ap.kbq ua3818dy1.v 20 ua3818dv.v",
72 "The unit of pixel values in the parametric Vt image is",
73 "(mL plasma)/(mL tissue). Data in DVR image are unitless.",
75 "In theory, DVR equals BPnd+1, and therefore a binding potential image can",
76 "be computed from DVR image by subtraction of unity, e.g. using program",
77 "imgcalc. However, this may lead to a large number of pixels with negative",
78 "values that may hamper the further statistical or visual analysis.",
81 "1. Logan J, Fowler JS, Volkow ND, Wolf AP, Dewey SL, Schlyer DJ,",
82 " MacGregor RR, Hitzemann R, Bendriem B, Gatley SJ, Christman DR.",
83 " Graphical analysis of reversible radioligand binding from time-activity",
84 " measurements applied to [N-11C-methyl]-(-)-cocaine PET studies in human",
85 " subjects. J Cereb Blood Flow Metab 1990; 10: 740-747.",
86 "2. Logan J, Fowler JS, Volkow ND, Wang GJ, Ding YS, Alexoff DL.",
87 " Distribution volume ratios without blood sampling from graphical",
88 " analysis of PET data. J Cereb Blood Flow Metab. 1996; 16: 834-840.",
89 "3. Logan J. Graphical analysis of PET data applied to reversible and",
90 " irreversible tracers. Nucl Med Biol 2000; 27:661-670.",
91 "4. Varga J & Szabo Z. Modified regression model for the Logan plot.",
92 " J Cereb Blood Flow Metab 2002; 22:240-244.",
94 "See also: imgbfbp, imglhdv, img2tif, logan, imgki, imgcalc",
96 "Keywords: image, MTGA, Logan plot, modelling, Vt, DVR, distribution volume",
115int main(
int argc,
char **argv)
117 int ai, help=0, version=0, verbose=1;
122 double startTime=-1.0, lowerLimit=0.0, upperLimit=-1.0, fittime=-1.0;
123 float calcThreshold=0.0;
124 char inpfile[FILENAME_MAX], petfile[FILENAME_MAX];
125 char outfile[FILENAME_MAX], icfile[FILENAME_MAX];
126 char nrfile[FILENAME_MAX];
127 char tmp[1024], *cptr;
128 IMG img, out, icimg, nrimg;
130 int startSample=0, endSample=0, fitdimt=0;
136 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
137 inpfile[0]=petfile[0]=outfile[0]=icfile[0]=nrfile[0]=(char)0;
141 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
143 cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(cptr==NULL)
continue;
144 if(strncasecmp(cptr,
"V=", 2)==0) {
145 strcpy(icfile, cptr+2);
if(strlen(icfile)>1)
continue;
146 }
else if(strncasecmp(cptr,
"N=", 2)==0) {
147 strcpy(nrfile, cptr+2);
if(strlen(nrfile)>1)
continue;
148 }
else if(strncasecmp(cptr,
"K2=", 3)==0) {
149 k2=
atof_dpi(cptr+3);
if(k2>0.0)
continue;
150 }
else if(strncasecmp(cptr,
"MIN=", 4)==0) {
152 }
else if(strncasecmp(cptr,
"MAX=", 4)==0) {
153 upperLimit=
atof_dpi(cptr+4);
if(upperLimit>0.0)
continue;
154 }
else if(strncasecmp(cptr,
"E=", 2)==0) {
155 fittime=60.0*
atof_dpi(cptr+2);
if(fittime>0.0)
continue;
156 }
else if(strncasecmp(cptr,
"END=", 4)==0) {
157 fittime=60.0*
atof_dpi(cptr+4);
if(fittime>0.0)
continue;
158 }
else if(strncasecmp(cptr,
"FILTER", 4)==0) {
159 param_filt=1;
continue;
160 }
else if(strncasecmp(cptr,
"THR=", 4)==0) {
162 if(ret==0) {calcThreshold=0.01*v;
continue;}
164 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
169 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
174 if(ai<argc)
strlcpy(inpfile, argv[ai++], FILENAME_MAX);
175 if(ai<argc)
strlcpy(petfile, argv[ai++], FILENAME_MAX);
176 if(ai<argc) {startTime=
atof_dpi(argv[ai++]);
if(startTime<0.0) startTime=0.0;}
177 if(ai<argc)
strlcpy(outfile, argv[ai++], FILENAME_MAX);
179 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
185 fprintf(stderr,
"Error: missing result file name.\n");
188 if(upperLimit>0.0 && upperLimit<=lowerLimit) {
189 fprintf(stderr,
"Error: invalid -min or -max setting.\n");
195 printf(
"inpfile := %s\n", inpfile);
196 printf(
"petfile := %s\n", petfile);
197 printf(
"outfile := %s\n", outfile);
198 printf(
"startTime := %g min\n", startTime);
199 if(k2>0.0) printf(
"k2 := %g\n", k2);
200 printf(
"lowerLimit := %g\n", lowerLimit);
201 if(upperLimit>0.0) printf(
"upperLimit := %g\n", upperLimit);
202 printf(
"icfile := %s\n", icfile);
203 printf(
"nrfile := %s\n", nrfile);
204 printf(
"fittime := %g\n", fittime);
205 printf(
"param_filt := %d\n", param_filt);
206 printf(
"calcThreshold := %g%%\n", 100.*calcThreshold);
216 petfile, NULL, inpfile, NULL, NULL, &fittime, &fitdimt, &img,
217 &input, NULL, 1, NULL, verbose-2, tmp);
219 fprintf(stderr,
"Error in reading data: %s.\n", tmp);
224 if(verbose>0) fprintf(stderr,
"Warning: missing pixel values.\n");
228 printf(
"fittimeFinal := %g [min]\n", fittime/60.0);
229 printf(
"fitdimt := %d\n", fitdimt);
230 printf(
"endSampleIndex := %d\n", endSample);
231 printf(
"endSample := %d\n", endSample+1);
234 for(fi=startSample=0; fi<fitdimt; fi++)
235 if((img.
mid[fi]/60.0)>startTime)
break;
else startSample++;
237 printf(
"startSampleIndex := %d\n", startSample);
238 printf(
"startSample := %d\n", startSample+1);
239 printf(
"startTimeFinal := %g [min]\n", img.
start[startSample]/60.0);
241 if((fitdimt-startSample)<2) {
242 fprintf(stderr,
"Error: too few time frames to fit.\n");
251 if(verbose>1) fprintf(stdout,
"thresholding\n");
254 fprintf(stderr,
"Error in thresholding the dynamic image: %s\n", img.
statmsg);
259 fprintf(stdout,
"threshold_cutoff_nr := %d / %d\n", n, img.
dimx*img.
dimy*img.
dimz);
268 if(startTime>0.0) fit_range=PRESET;
else fit_range=EXCLUDE_BEGIN;
269 if(verbose>1) printf(
"fit_range := %d\n", (
int)fit_range);
271 IMG *picimg=NULL, *pnrimg=NULL;
272 if(icfile[0]) picimg=&icimg;
273 if(nrfile[0]) pnrimg=&nrimg;
275 if(verbose>0) fprintf(stdout,
"computing MTGA pixel-by-pixel\n");
276 clock_t fitStart, fitFinish;
278 ret=
img_logan(&input, &img, startSample, endSample, fit_range, calcThreshold, k2,
279 &out, picimg, pnrimg, tmp, verbose-5);
281 fprintf(stderr,
"Error (%d): %s\n", ret, tmp);
286 if(fitFinish>fitStart) fprintf(stdout,
"done in %g seconds.\n",
287 (
double)(fitFinish - fitStart) / (
double)CLOCKS_PER_SEC );
288 else fprintf(stdout,
"done.\n");
300 if(verbose>0) fprintf(stdout,
"filtering out pixel values exceeding %g\n", upperLimit);
305 fprintf(stdout,
"filtering out pixel values lower than %g\n", lowerLimit);
312 if(verbose>0) printf(
"filtering extreme values from parametric images\n");
322 fprintf(stderr,
"Error: %s\n", tmp);
325 if(verbose>1) printf(
"%s\n", tmp);
328 fprintf(stderr,
"Error: %s\n", out.
statmsg);
332 fprintf(stdout,
"Vt or DVR image %s saved.\n", outfile);
340 fprintf(stderr,
"Error: %s\n", tmp);
343 if(verbose>1) printf(
"%s\n", tmp);
344 ret=
imgWrite(icfile, &icimg);
if(ret) {
345 fprintf(stderr,
"Error: %s\n", icimg.
statmsg);
348 if(verbose>0) fprintf(stdout,
"Intercept image %s saved.\n", icfile);
356 fprintf(stderr,
"Error: %s\n", tmp);
359 if(verbose>1) printf(
"%s\n", tmp);
360 ret=
imgWrite(nrfile, &nrimg);
if(ret) {
361 fprintf(stderr,
"Error: %s\n", nrimg.
statmsg);
364 if(verbose>0) fprintf(stdout,
"Nr image %s saved.\n", nrfile);
int backupExistingFile(char *filename, char *backup_ext, char *status)
int atof_with_check(char *double_as_string, double *result_value)
double atof_dpi(char *str)
unsigned long long imgNaNs(IMG *img, int fix)
void imgEmpty(IMG *image)
int img_logan(DFT *input, IMG *dyn_img, int start, int end, linefit_range fit_range, float thrs, double k2, IMG *vt_img, IMG *ic_img, IMG *nr_img, char *status, int verbose)
int imgWrite(const char *fname, IMG *img)
void imgCutoff(IMG *image, float cutoff, int mode)
int imgThresholding(IMG *img, float threshold_level, long long *thr_nr)
int imgOutlierFilter(IMG *img, float limit)
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.
Header file for libtpcmodext.