TPCCLIB
Loading...
Searching...
No Matches
imgdv.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 "libtpcmisc.h"
20#include "libtpcmodel.h"
21#include "libtpccurveio.h"
22#include "libtpcimgio.h"
23#include "libtpcimgp.h"
24#include "libtpcmodext.h"
25/*****************************************************************************/
26
27/*****************************************************************************/
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.",
35 " ",
36 "Usage: @P [Options] input image starttime resultimage",
37 " ",
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).",
44 " ",
45 "Options:",
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).",
49 " -thr=<threshold%>",
50 " Pixels with AUC less than (threshold/100 x input) are set to zero.",
51 " Default is 0 %.",
52 " -max=<Max value>",
53 " Upper limit for Vt or DVR values; by default max is set pixel-wise",
54 " to 10 times the AUC ratio.",
55 " -min=<Min value>",
56 " Lower limit for Vt or DVR values; 0 by default.",
57 " -filter",
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",
62 " the fit end time.",
63 " -v=<filename>",
64 " Y axis intercepts times -1 are written as an image in specified file.",
65 " -n=<filename>",
66 " Numbers of selected plot data points are written as an image.",
67 " -stdoptions", // List standard options like --help, -v, etc
68 " ",
69 "Example:",
70 " @P ua3818ap.kbq ua3818dy1.v 20 ua3818dv.v",
71 " ",
72 "The unit of pixel values in the parametric Vt image is",
73 "(mL plasma)/(mL tissue). Data in DVR image are unitless.",
74 " ",
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.",
79 " ",
80 "References:",
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.",
93 " ",
94 "See also: imgbfbp, imglhdv, img2tif, logan, imgki, imgcalc",
95 " ",
96 "Keywords: image, MTGA, Logan plot, modelling, Vt, DVR, distribution volume",
97 0};
98/*****************************************************************************/
99
100/*****************************************************************************/
101/* Turn on the globbing of the command line, since it is disabled by default in
102 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
103 In Unix&Linux wildcard command line processing is enabled by default. */
104/*
105#undef _CRT_glob
106#define _CRT_glob -1
107*/
108int _dowildcard = -1;
109/*****************************************************************************/
110
111/*****************************************************************************/
115int main(int argc, char **argv)
116{
117 int ai, help=0, version=0, verbose=1;
118 linefit_range fit_range;
119 int fi, ret;
120 int param_filt=0;
121 double k2=-1.0;
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;
129 DFT input;
130 int startSample=0, endSample=0, fitdimt=0;
131
132
133 /*
134 * Get arguments
135 */
136 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
137 inpfile[0]=petfile[0]=outfile[0]=icfile[0]=nrfile[0]=(char)0;
138 dftInit(&input);
139 imgInit(&img); imgInit(&out); imgInit(&icimg); imgInit(&nrimg);
140 /* Get options */
141 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
142 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
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) {
151 if(atof_with_check(cptr+4, &lowerLimit)==0) continue;
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) {
161 double v; ret=atof_with_check(cptr+4, &v);
162 if(ret==0) {calcThreshold=0.01*v; continue;} // negative is ok
163 }
164 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
165 return(1);
166 } else break;
167
168 /* Print help or version? */
169 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
170 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
171 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
172
173 /* Process other arguments, starting from the first non-option */
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);
178 if(ai<argc) {
179 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
180 return(1);
181 }
182
183 /* Is something missing? */
184 if(!outfile[0]) {
185 fprintf(stderr, "Error: missing result file name.\n");
186 return(1);
187 }
188 if(upperLimit>0.0 && upperLimit<=lowerLimit) {
189 fprintf(stderr, "Error: invalid -min or -max setting.\n");
190 return(1);
191 }
192
193 /* In verbose mode print arguments and options */
194 if(verbose>1) {
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);
207 }
208 if(verbose>9) IMG_TEST=verbose-9; else IMG_TEST=0;
209
210
211 /*
212 * Read PET image and input TAC
213 */
214 fittime/=60.;
216 petfile, NULL, inpfile, NULL, NULL, &fittime, &fitdimt, &img,
217 &input, NULL, 1, NULL, verbose-2, tmp);
218 if(ret!=0) {
219 fprintf(stderr, "Error in reading data: %s.\n", tmp);
220 imgEmpty(&img); dftEmpty(&input);
221 return(2);
222 }
223 if(imgNaNs(&img, 1)>0)
224 if(verbose>0) fprintf(stderr, "Warning: missing pixel values.\n");
225 fittime*=60.;
226 endSample=fitdimt-1;
227 if(verbose>2) {
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);
232 }
233 /* Find out the first sample to use in the line fit */
234 for(fi=startSample=0; fi<fitdimt; fi++)
235 if((img.mid[fi]/60.0)>startTime) break; else startSample++;
236 if(verbose>2) {
237 printf("startSampleIndex := %d\n", startSample);
238 printf("startSample := %d\n", startSample+1);
239 printf("startTimeFinal := %g [min]\n", img.start[startSample]/60.0);
240 }
241 if((fitdimt-startSample)<2) {
242 fprintf(stderr, "Error: too few time frames to fit.\n");
243 imgEmpty(&img); dftEmpty(&input);
244 return(3);
245 }
246
247#if(0)
248 /*
249 * Thresholding
250 */
251 if(verbose>1) fprintf(stdout, "thresholding\n");
252 ret=imgThresholding(&img, calcThreshold, &n);
253 if(ret!=0) {
254 fprintf(stderr, "Error in thresholding the dynamic image: %s\n", img.statmsg);
255 imgEmpty(&img); dftEmpty(&input);
256 return(4);
257 }
258 if(verbose>1) {
259 fprintf(stdout, "threshold_cutoff_nr := %d / %d\n", n, img.dimx*img.dimy*img.dimz);
260 fflush(stdout);
261 }
262#endif
263
264 /*
265 * Calculate Logan plot
266 */
267 /* Fixed or free time range */
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);
270 /* Set optional output IMG struct pointers to NULL, if not needed */
271 IMG *picimg=NULL, *pnrimg=NULL;
272 if(icfile[0]) picimg=&icimg;
273 if(nrfile[0]) pnrimg=&nrimg;
274 /* MTGA */
275 if(verbose>0) fprintf(stdout, "computing MTGA pixel-by-pixel\n");
276 clock_t fitStart, fitFinish;
277 fitStart=clock();
278 ret=img_logan(&input, &img, startSample, endSample, fit_range, calcThreshold, k2,
279 &out, picimg, pnrimg, tmp, verbose-5);
280 if(ret!=0) {
281 fprintf(stderr, "Error (%d): %s\n", ret, tmp);
282 imgEmpty(&img); dftEmpty(&input); return(5);
283 }
284 fitFinish=clock();
285 if(verbose>0) {
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");
289 }
290 /* No need for the dynamic image or input data anymore */
291 imgEmpty(&img); dftEmpty(&input);
292
293
294
295 /*
296 * Filter the parametric images if required
297 */
298 /* Remove values that are higher than the user-defined limit */
299 if(upperLimit>0.0) {
300 if(verbose>0) fprintf(stdout, "filtering out pixel values exceeding %g\n", upperLimit);
301 imgCutoff(&out, (float)upperLimit, 0);
302 }
303 /* Remove values that are lower than the user-defined or default limit */
304 if(verbose>0)
305 fprintf(stdout, "filtering out pixel values lower than %g\n", lowerLimit);
306 imgCutoff(&out, (float)lowerLimit, 1);
307 /*
308 * Filter out pixels that are over 4x higher than their
309 * closest neighbours
310 */
311 if(param_filt>0) {
312 if(verbose>0) printf("filtering extreme values from parametric images\n");
313 imgOutlierFilter(&out, 4.0);
314 if(icfile[0]) imgOutlierFilter(&icimg, 4.0);
315 }
316
317
318 /*
319 * Save parametric Vt image
320 */
321 ret=backupExistingFile(outfile, NULL, tmp); if(ret!=0) {
322 fprintf(stderr, "Error: %s\n", tmp);
323 imgEmpty(&out); imgEmpty(&icimg); imgEmpty(&nrimg); return(11);
324 }
325 if(verbose>1) printf("%s\n", tmp);
326 ret=imgWrite(outfile, &out);
327 if(ret) {
328 fprintf(stderr, "Error: %s\n", out.statmsg);
329 imgEmpty(&out); imgEmpty(&icimg); imgEmpty(&nrimg); return(12);
330 }
331 if(verbose>0) {
332 fprintf(stdout, "Vt or DVR image %s saved.\n", outfile);
333 }
334
335 /*
336 * Save parametric Ic image
337 */
338 if(icfile[0]) {
339 ret=backupExistingFile(icfile, NULL, tmp); if(ret!=0) {
340 fprintf(stderr, "Error: %s\n", tmp);
341 imgEmpty(&out); imgEmpty(&icimg); imgEmpty(&nrimg); return(13);
342 }
343 if(verbose>1) printf("%s\n", tmp);
344 ret=imgWrite(icfile, &icimg); if(ret) {
345 fprintf(stderr, "Error: %s\n", icimg.statmsg);
346 imgEmpty(&out); imgEmpty(&icimg); imgEmpty(&nrimg); return(14);
347 }
348 if(verbose>0) fprintf(stdout, "Intercept image %s saved.\n", icfile);
349 }
350
351 /*
352 * Save parametric nr image
353 */
354 if(nrfile[0]) {
355 ret=backupExistingFile(nrfile, NULL, tmp); if(ret!=0) {
356 fprintf(stderr, "Error: %s\n", tmp);
357 imgEmpty(&out); imgEmpty(&icimg); imgEmpty(&nrimg); return(15);
358 }
359 if(verbose>1) printf("%s\n", tmp);
360 ret=imgWrite(nrfile, &nrimg); if(ret) {
361 fprintf(stderr, "Error: %s\n", nrimg.statmsg);
362 imgEmpty(&out); imgEmpty(&icimg); imgEmpty(&nrimg); return(16);
363 }
364 if(verbose>0) fprintf(stdout, "Nr image %s saved.\n", nrfile);
365 }
366
367 /* Free memory */
368 imgEmpty(&out); imgEmpty(&icimg); imgEmpty(&nrimg);
369
370 return(0);
371}
372/*****************************************************************************/
373
374/*****************************************************************************/
int backupExistingFile(char *filename, char *backup_ext, char *status)
Definition backup.c:14
int atof_with_check(char *double_as_string, double *result_value)
Definition decpoint.c:107
double atof_dpi(char *str)
Definition decpoint.c:59
void dftInit(DFT *data)
Definition dft.c:38
void dftEmpty(DFT *data)
Definition dft.c:20
int IMG_TEST
Definition img.c:6
unsigned long long imgNaNs(IMG *img, int fix)
Definition img.c:658
void imgEmpty(IMG *image)
Definition img.c:121
void imgInit(IMG *image)
Definition img.c:60
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)
Definition img_mtga.c:228
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
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)
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.
linefit_range
Header file for libtpcmodext.
unsigned short int dimx
float * start
unsigned short int dimz
unsigned short int dimy
const char * statmsg
float * mid