TPCCLIB
Loading...
Searching...
No Matches
imgfur.c
Go to the documentation of this file.
1
7/*****************************************************************************/
8#include "tpcclibConfig.h"
9/*****************************************************************************/
10#include <stdio.h>
11#include <stdlib.h>
12#include <unistd.h>
13#include <string.h>
14#include <math.h>
15#include <time.h>
16/*****************************************************************************/
17#include "libtpcmisc.h"
18#include "libtpcmodel.h"
19#include "libtpccurveio.h"
20#include "libtpcimgio.h"
21#include "libtpcimgp.h"
22#include "libtpcmodext.h"
23/*****************************************************************************/
24
25/*****************************************************************************/
26#ifndef DEFAULT_LC
27#define DEFAULT_LC 1.00
28#endif
29#ifndef DEFAULT_DENSITY
30#define DEFAULT_DENSITY 1.00
31#endif
32/*****************************************************************************/
33
34/*****************************************************************************/
35static char *info[] = {
36 "Calculates of Fractional Uptake Rate (FUR) or FUR-based Metabolic Rate (MR)",
37 "image from static or dynamic PET image in ECAT 6.3 or 7.2, NIfTI, or",
38 "Analyze 7.5 format. Information on FUR in:",
39 "https://www.turkupetcentre.net/petanalysis/model_fur.html",
40 " ",
41 "Usage: @P [Options] inputfile image starttime endtime furimage",
42 " ",
43 "FUR calculation start and stop time must be entered in minutes;",
44 "set both to zero to use the whole time range from image data.",
45 " ",
46 "Options:",
47 " -Ca=<value>",
48 " Concentration of native substrate in arterial plasma (mM),",
49 " for example plasma glucose in [18F]FDG studies.",
50 " With this option the metabolic rate (umol/(min*100 g)) is calculated.",
51 " -LC=<value>",
52 " Lumped Constant in MR calculation; default is 1.0.",
53 " -density=<value>",
54 " Tissue density in MR calculation; default is 1.0 g/ml.",
55 " -stdoptions", // List standard options like --help, -v, etc
56 " ",
57 "Example 1. Calculation of FUR image from a dynamic image from 45 to 60 min:",
58 " @P ua2918ap.kbq ua2918dy1.v 45 60 ua2918fur.v",
59 " ",
60 "Example 2. Calculation of glucose uptake image, when tissue density is 1.04,",
61 "plasma glucose concentration is 5.2 mM, lumped constant is 0.52, from",
62 "a static (one frame) image:",
63 " @P -density=1.04 -Ca=5.2 -LC=0.52 a864ap.kbq a864dy1.v 0 0 a864mrglu.v",
64 " ",
65 "The unit of pixel values in the FUR image is",
66 "(mL plasma)/(min*(mL tissue)) by default, and umol/(min*100 g) in metabolic",
67 "rate image.",
68 " ",
69 "See also: imgki, imginteg, imgcalc, ecattime, img2tif, regfur",
70 " ",
71 "Keywords: image, modelling, FUR, retention index, irreversible uptake",
72 0};
73/*****************************************************************************/
74
75/*****************************************************************************/
76/* Turn on the globbing of the command line, since it is disabled by default in
77 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
78 In Unix&Linux wildcard command line processing is enabled by default. */
79/*
80#undef _CRT_glob
81#define _CRT_glob -1
82*/
83int _dowildcard = -1;
84/*****************************************************************************/
85
86/*****************************************************************************/
90int main(int argc, char **argv)
91{
92 int ai, help=0, version=0, verbose=1;
93 int ret;
94 char inpfile[FILENAME_MAX], petfile[FILENAME_MAX], outfile[FILENAME_MAX];
95 char tmp[1024], *cptr;
96 DFT input, auc;
97 IMG img, out;
98 double startTime=-1.0, endTime=-1.0;
99 double LC=-1.0, Ca=-1.0, density=-1.0;
100
101
102 /*
103 * Get arguments
104 */
105 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
106 inpfile[0]=petfile[0]=outfile[0]=(char)0;
107 imgInit(&img); imgInit(&out);
108 dftInit(&input); dftInit(&auc);
109 /* Get options */
110 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
111 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
112 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
113 if(strncasecmp(cptr, "CA=", 3)==0) {
114 Ca=atof_dpi(cptr+3); if(Ca>0.0) continue;
115 } else if(strncasecmp(cptr, "LC=", 3)==0) {
116 LC=atof_dpi(cptr+3); if(LC>0.0) continue;
117 } else if(strncasecmp(cptr, "D=", 2)==0) {
118 density=atof_dpi(cptr+2); if(density>0.0) continue;
119 } else if(strncasecmp(cptr, "DENSITY=", 8)==0) {
120 density=atof_dpi(cptr+8); if(density>0.0) continue;
121 }
122 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
123 return(1);
124 } else break;
125
126 /* Print help or version? */
127 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
128 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
129 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
130
131 /* Process other arguments, starting from the first non-option */
132 for(; ai<argc; ai++) {
133 if(!inpfile[0]) {
134 strcpy(inpfile, argv[ai]); continue;
135 } else if(!petfile[0]) {
136 strcpy(petfile, argv[ai]); continue;
137 } else if(startTime<0.0) {
138 startTime=atof_dpi(argv[ai]); if(startTime<0.0) startTime=0.0;
139 continue;
140 } else if(endTime<0.0) {
141 endTime=atof_dpi(argv[ai]); if(endTime<0.0) endTime=0.0;
142 continue;
143 } else if(!outfile[0]) {
144 strcpy(outfile, argv[ai]); continue;
145 }
146 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
147 return(1);
148 }
149
150 /* Is something missing? */
151 if(!outfile[0]) {
152 fprintf(stderr, "Error: missing result file name.\n");
153 return(1);
154 }
155 /* If MR will be calculated, set defaults and give warnings as necessary */
156 if(Ca>0.0) {
157 if(LC<0.0) {
158 LC=DEFAULT_LC;
159 fprintf(stderr, "Warning: LC not set, using default %g\n", LC);
160 }
161 if(density<0.0) {
162 density=DEFAULT_DENSITY;
163 fprintf(stderr, "Warning: tissue density not set, using default %g\n",
164 density);
165 }
166 } else { /* Warnings if density or LC set when MR will not be calculated */
167 if(LC>0.0) fprintf(stderr, "Warning: LC was set but is not used.\n");
168 if(density>0.0)
169 fprintf(stderr, "Warning: tissue density was set but is not used.\n");
170 }
171 /* Check the time range */
172 if(endTime<startTime) {
173 fprintf(stderr, "Error: invalid time range.\n");
174 return(1);
175 }
176 if(startTime==endTime && startTime>0.5) {
177 startTime-=0.5; endTime+=0.5;
178 }
179
180
181 /* In verbose mode print arguments and options */
182 if(verbose>1) {
183 printf("inpfile := %s\n", inpfile);
184 printf("petfile := %s\n", petfile);
185 printf("outfile := %s\n", outfile);
186 if(endTime>0.0) {
187 printf("startTime := %g min\n", startTime);
188 printf("endTime := %g min\n", endTime);
189 }
190 if(Ca>0.0) {
191 printf("Ca := %g\n", Ca);
192 printf("LC := %g\n", LC);
193 printf("density := %g\n", density);
194 }
195 }
196 if(verbose>9) IMG_TEST=verbose-9; else IMG_TEST=0;
197
198
199 /*
200 * Read image
201 */
202 if(verbose>0) fprintf(stdout, "reading image %s\n", petfile);
203 ret=imgRead(petfile, &img);
204 if(ret) {
205 fprintf(stderr, "Error: %s\n", img.statmsg); if(verbose>1) imgInfo(&img);
206 return(2);
207 }
208 if(imgNaNs(&img, 1)>0)
209 if(verbose>0) fprintf(stderr, "Warning: missing pixel values.\n");
210 /* Check if PET data is raw or image */
211 if(img.type!=IMG_TYPE_IMAGE) {
212 fprintf(stderr, "Error: %s is not an image.\n", petfile);
213 imgEmpty(&img); return(2);
214 }
215 /* Check that frame times are available */
216 if(imgExistentTimes(&img)==0) {
217 fprintf(stderr, "Error: %s does not contain frame times.\n", petfile);
218 imgEmpty(&img); return(2);
219 }
220 //imgInfo(&img);
221 /* Make sure that there is no overlap in image frames */
222 if(img.dimt>1) {
223 if(verbose>1) fprintf(stdout, "checking frame overlap in %s\n", petfile);
224 ret=imgDeleteFrameOverlap(&img);
225 if(ret) {
226 fprintf(stderr, "Error: image %s has overlapping frame times.\n", petfile);
227 imgEmpty(&img); return(2);
228 }
229 }
230
231 /* If image is in NIfTI or Analyze format, it does not contain calibration
232 unit; then assume that it is kBq/mL, and warn user about that */
235 {
236 if(img.unit==IMGUNIT_UNKNOWN) {
237 img.unit=IMGUNIT_KBQ_PER_ML;
238 fprintf(stderr, "Warning: image calibration unit assumed to be %s.\n",
239 imgUnit(img.unit));
240 }
241 }
242
243 /* If user did not specify start and end times, then get those from data */
244 if(endTime<=0.0) {
245 startTime=img.start[0]/60.0;
246 endTime=img.end[img.dimt-1]/60.0;
247 if(verbose>0) {
248 printf("startTime := %g min\n", startTime);
249 printf("endTime := %g min\n", endTime);
250 }
251 }
252
253 /*
254 * Calculate the average over specified time range
255 */
256 if(verbose>1) fprintf(stdout, "calculating average image\n");
257 ret=imgTimeIntegral(&img, startTime*60.0, endTime*60.0, &out, 1, tmp,
258 verbose-4);
259 if(ret!=0) {
260 fprintf(stderr, "Error: %s.\n", tmp);
261 imgEmpty(&img); imgEmpty(&out); return(3);
262 }
263 if(verbose>1) fprintf(stdout, "%s.\n", tmp);
264
265 /* Original dynamic image is not needed anymore */
266 imgEmpty(&img);
267
268
269 /*
270 * Read input data
271 */
272 if(verbose>1) printf("Reading input file %s\n", inpfile);
273 if(dftRead(inpfile, &input)) {
274 fprintf(stderr, "Error in reading '%s': %s\n", inpfile, dfterrmsg);
275 imgEmpty(&out); return(4);
276 }
277 if(input.voiNr>1) {
278 fprintf(stderr, "Warning: only first TAC is used as input.\n");
279 input.voiNr=1;
280 }
281 if(dft_nr_of_NA(&input)>0) { // check if file contains NAs (missing values)
282 fprintf(stderr, "Error: missing values in %s\n", inpfile);
283 imgEmpty(&out); dftEmpty(&input); return(4);
284 }
285 /* Set time unit to min */
286 ret=dftTimeunitConversion(&input, TUNIT_MIN);
287 if(ret) fprintf(stderr, "Warning: check that input times are in minutes.\n");
288
289 /*
290 * Check the image and plasma concentration units
291 */
292 ret=cunit_check_dft_vs_img(&input, &out, tmp, verbose-4);
293 if(ret==0) {if(verbose>0) fprintf(stdout, "%s\n", tmp);
294 } else if(ret<0) {fprintf(stderr, "Warning: %s\n", tmp);
295 } else {
296 fprintf(stderr, "Error: %s.\n", tmp);
297 imgEmpty(&out); dftEmpty(&input); return(5);
298 }
299
300 /*
301 * Calculate input integral from 0 to PET middle time point
302 */
303 if(verbose>1) printf("calculating input AUC\n");
304 ret=dftTimeIntegral(&input, 0.0, 0.5*(startTime+endTime), &auc, 0, tmp,
305 verbose-4);
306 if(ret!=0) {
307 fprintf(stderr, "Error: %s.\n", tmp);
308 if(verbose>1) printf("error_code := %d\n", ret);
309 imgEmpty(&out); dftEmpty(&input); dftEmpty(&auc); return(6);
310 }
311 if(verbose>0)
312 printf("AUC[%g-%g] := %g\n", auc.x1[0], auc.x2[0], auc.voi[0].y[0]);
313
314 /* Original input curve is not needed anymore */
315 dftEmpty(&input);
316
317
318 /*
319 * Divide average PET data by input AUC
320 */
321 ret=imgArithmConst(&out, auc.voi[0].y[0], ':', 1.0E+12, verbose-5);
322 if(ret!=0) {
323 fprintf(stderr, "Error: cannot calculate of FUR.\n");
324 imgEmpty(&out); dftEmpty(&auc);
325 return(7);
326 }
327 out.unit=IMGUNIT_PER_MIN;
328
329 /* Input AUC is not needed anymore */
330 dftEmpty(&auc);
331
332
333 /*
334 * Calculate metabolic rate, if necessary
335 */
336 if(Ca>0.0) {
337 double MRf;
338 MRf=100.*Ca/(density*LC);
339 if(verbose>0)
340 fprintf(stdout, "converting FUR to metabolic rate with factor %g\n", MRf);
341 ret=imgArithmConst(&out, MRf, '*', 1.0E+06, verbose-5);
342 if(ret!=0) {
343 fprintf(stderr, "Error: cannot calculate metabolic rate.\n");
344 imgEmpty(&out); return(8);
345 }
346 out.unit=IMGUNIT_UMOL_PER_MIN_PER_100G;
347 }
348
349
350 /*
351 * Save parametric Ki image
352 */
353 if(backupExistingFile(outfile, NULL, tmp)!=0) {
354 fprintf(stderr, "Error: %s\n", tmp);
355 imgEmpty(&out); return(11);
356 }
357 if(verbose>0) printf("%s\n", tmp);
358 ret=imgWrite(outfile, &out);
359 if(ret) {
360 fprintf(stderr, "Error: %s\n", out.statmsg);
361 imgEmpty(&out); return(12);
362 }
363 if(verbose>0) {
364 if(Ca<=0.0) fprintf(stdout, "FUR image %s saved.\n", outfile);
365 else fprintf(stdout, "MR image %s saved.\n", outfile);
366 }
367
368 /* Free memory */
369 imgEmpty(&out);
370
371 return(0);
372}
373/*****************************************************************************/
374
375/*****************************************************************************/
int backupExistingFile(char *filename, char *backup_ext, char *status)
Definition backup.c:14
double atof_dpi(char *str)
Definition decpoint.c:59
void dftInit(DFT *data)
Definition dft.c:38
char dfterrmsg[64]
Definition dft.c:6
void dftEmpty(DFT *data)
Definition dft.c:20
int dft_nr_of_NA(DFT *dft)
Definition dft.c:905
int dftTimeIntegral(DFT *dft, double t1, double t2, DFT *idft, int calc_mode, char *status, int verbose)
Definition dftint.c:382
int dftRead(char *filename, DFT *data)
Definition dftio.c:22
int dftTimeunitConversion(DFT *dft, int tunit)
Definition dftunit.c:119
int IMG_TEST
Definition img.c:6
int imgExistentTimes(IMG *img)
Definition img.c:613
void imgInfo(IMG *image)
Definition img.c:359
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 imgArithmConst(IMG *img, float operand, char operation, float ulimit, int verbose)
Definition imgarithm.c:100
int imgRead(const char *fname, IMG *img)
Definition imgfile.c:26
int imgWrite(const char *fname, IMG *img)
Definition imgfile.c:136
int imgDeleteFrameOverlap(IMG *img)
Definition imgframe.c:77
char * imgUnit(int dunit)
Definition imgunits.c:315
Header file for libtpccurveio.
Header file for libtpcimgio.
#define IMG_NIFTI_1S
#define IMG_ANA_L
#define IMG_ANA
#define IMG_NIFTI_1D
#define IMG_TYPE_IMAGE
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
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.
Header file for libtpcmodext.
int imgTimeIntegral(IMG *img, float t1, float t2, IMG *iimg, int calc_mode, char *status, int verbose)
Definition misc_model.c:147
int cunit_check_dft_vs_img(DFT *dft, IMG *img, char *errmsg, int verbose)
Definition units_check.c:18
Voi * voi
double * x1
int voiNr
double * x2
char type
char unit
int _fileFormat
unsigned short int dimt
float * start
float * end
const char * statmsg
double * y