TPCCLIB
Loading...
Searching...
No Matches
imgsuv.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 <ctype.h>
15#include <math.h>
16#include <time.h>
17/*****************************************************************************/
18#include "libtpcmisc.h"
19#include "libtpcmodel.h"
20#include "libtpccurveio.h"
21#include "libtpcimgio.h"
22#include "libtpcimgp.h"
23#include "libtpcmodext.h"
24/*****************************************************************************/
25
26/*****************************************************************************/
27static char *info[] = {
28 "Calculates SUV (standardized uptake value) image from PET image",
29 "in ECAT 6.3 and 7.x, NIfTI, or Analyze 7.5 format.",
30 "SUV in image pixels is calculated as mean value in specified time range.",
31 "Before calculation, make sure that radioactivity concentration units in PET",
32 "image header are correct. Analyze and NIfTI images do not contain units,",
33 "therefore unit kBq/mL is assumed.",
34 "Analyze and NIfTI must be accompanied by SIF.",
35 "Image data and injected dose must be decay corrected to the same time",
36 "(usually the tracer injection time).",
37 " ",
38 "Usage: @P [Options] image starttime endtime dose weight suvimage",
39 " ",
40 "Options:",
41 " -stdoptions", // List standard options like --help, -v, etc
42 " ",
43 "SUV calculation start and stop time must be entered in minutes;",
44 "If SUV calculation start and end times are set to zero, then no average",
45 "over time is calculated, but the (dynamic) PET image is saved",
46 "in SUV or %i.d./L units.",
47 " ",
48 "Injected dose must be given in units MBq at the time of injection.",
49 " ",
50 "Subject weight must be given in kg or liters.",
51 "Instead of SUV, the percentage of injected dose per tissue volume ",
52 "(PID/L, %i.d./L) is calculated, if the subject weight is set to 0 (or below).",
53 " ",
54 "See also: imgunit, ecattime, imginteg, imgcalc, eframe, dftsuv",
55 " ",
56 "Keywords: image, SUV, DUR, DAR, PID, dose, modelling",
57 0};
58/*****************************************************************************/
59
60/*****************************************************************************/
61/* Turn on the globbing of the command line, since it is disabled by default in
62 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
63 In Unix&Linux wildcard command line processing is enabled by default. */
64/*
65#undef _CRT_glob
66#define _CRT_glob -1
67*/
68int _dowildcard = -1;
69/*****************************************************************************/
70
71/*****************************************************************************/
75int main(int argc, char **argv)
76{
77 int ai, help=0, version=0, verbose=1;
78 int ret, doAverage=1;
79 char petfile[FILENAME_MAX], suvfile[FILENAME_MAX];
80 char *cptr, tmp[512], output_name[64];
81 IMG pet, rout;
82 float tstart, tstop, f;
83 double dose, weight;
84
85
86
87 /*
88 * Get arguments
89 */
90 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
91 petfile[0]=suvfile[0]=(char)0;
92 tstart=tstop=-1.0; dose=weight=nan("");
93 imgInit(&pet); imgInit(&rout);
94 /* Get options */
95 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
96 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
97 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
98 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
99 return(1);
100 } else break;
101
102 /* Print help or version? */
103 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
104 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
105 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
106
107 /* Process other arguments, starting from the first non-option */
108 for(; ai<argc; ai++) {
109 if(!petfile[0]) {
110 strcpy(petfile, argv[ai]); continue;
111 } else if(tstart<0) {
112 tstart=atof_dpi(argv[ai]); continue;
113 } else if(tstop<0) {
114 tstop=atof_dpi(argv[ai]); continue;
115 } else if(isnan(dose)) {
116 ret=atof_with_check(argv[ai], &dose); if(ret==0 && dose>0.0) continue;
117 } else if(isnan(weight)) {
118 ret=atof_with_check(argv[ai], &weight); if(ret==0) continue;
119 } else if(!suvfile[0]) {
120 strcpy(suvfile, argv[ai]); continue;
121 }
122 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
123 return(1);
124 }
125
126 /* Is something missing? */
127 if(!suvfile[0]) {
128 fprintf(stderr, "Error: missing result file name.\n");
129 return(1);
130 }
131 if(weight<1.0E-100) weight=nan("");
132 if(strcasecmp(suvfile, petfile)==0) {
133 fprintf(stderr, "Error: check the output filenames.\n");
134 return(1);
135 }
136 if(tstop<tstart || tstart<0.0) {
137 fprintf(stderr, "Error: invalid time range arguments.\n");
138 return(1);
139 }
140 if(weight>0.0) strcpy(output_name, "SUV");
141 else strcpy(output_name, "%i.d./L");
142
143 /* In verbose mode print arguments and options */
144 if(verbose>1) {
145 printf("petfile := %s\n", petfile);
146 printf("suvfile := %s\n", suvfile);
147 printf("tstart := %g min\n", tstart);
148 printf("tstop := %g\n", tstop);
149 printf("dose := %g MBq\n", dose);
150 if(!isnan(weight)) printf("weight := %g kg\n", weight);
151 }
152 if(verbose>8) IMG_TEST=verbose-8; else IMG_TEST=0;
153
154 /* If time range was set to zero, then avg needs not to be calculated */
155 if(tstart<=0.0 && tstop<=0.0) doAverage=0;
156
157
158 /*
159 * Read dynamic image
160 */
161 if(verbose>0) fprintf(stdout, "reading image %s\n", petfile);
162 ret=imgRead(petfile, &pet);
163 if(ret) {
164 fprintf(stderr, "Error: %s\n", pet.statmsg); if(verbose>2) imgInfo(&pet);
165 return(2);
166 }
167 if(imgNaNs(&pet, 1)>0)
168 if(verbose>0) fprintf(stderr, "Warning: missing pixel values.\n");
169 /* Check if PET data is raw or image */
170 if(pet.type!=IMG_TYPE_IMAGE) {
171 fprintf(stderr, "Error: %s is not an image.\n", petfile);
172 imgEmpty(&pet); return(2);
173 }
174 if(verbose>6) imgInfo(&pet);
175 /* If image has only one frame, but time range was given, then assume that
176 user wants to use frame start and end times, but give a warning */
177 if(pet.dimt==1 && doAverage==1) {
178 doAverage=0;
179 tstart=tstop=0.0;
180 fprintf(stderr, "Warning: image has only one frame.\n");
181 fprintf(stderr, "Warning: user-specified time range is not used.\n");
182 }
183 /* Check that frame times are available, if needed */
184 if(imgExistentTimes(&pet)==0 && doAverage==1) {
185 fprintf(stderr, "Error: %s does not contain frame times.\n", petfile);
186 imgEmpty(&pet); return(2);
187 }
188 /* Make sure that there is no overlap in image frames */
189 if(pet.dimt>1) {
190 if(verbose>1) fprintf(stdout, "checking frame overlap in %s\n", petfile);
191 ret=imgDeleteFrameOverlap(&pet);
192 if(ret) {
193 fprintf(stderr, "Error: image %s has overlapping frame times.\n", petfile);
194 imgEmpty(&pet); return(2);
195 }
196 }
197
198
199 /* If image is in NIfTI or Analyze format, it does not contain calibration
200 unit; then assume that it is kBq/mL, and warn user about that */
203 {
204 if(pet.unit==IMGUNIT_UNKNOWN) {
205 pet.unit=IMGUNIT_KBQ_PER_ML;
206 fprintf(stderr, "Warning: image calibration unit assumed to be %s.\n",
207 imgUnit(pet.unit));
208 }
209 }
210
211 /* Convert image units to kBq/mL */
212 if(verbose>2) {
213 strcpy(tmp, imgUnit(pet.unit));
214 printf("image calibration unit := %s\n", tmp);
215 if(verbose>3) printf("img.unit := %d\n", pet.unit);
216 }
217 if(pet.unit==IMGUNIT_KBQ_PER_ML) ret=0;
218 else ret=imgConvertUnit(&pet, "kBq/mL");
219 if(ret!=0) {
220 fprintf(stderr, "Error: invalid calibration unit in image.\n");
221 imgEmpty(&pet); return(3);
222 }
223 if(verbose>2) {
224 strcpy(tmp, imgUnit(pet.unit));
225 printf("final image calibration unit := %s\n", tmp);
226 if(verbose>3) printf("final img.unit := %d\n", pet.unit);
227 }
228
229 /* Convert pixel values in image into SUV or %i.d./L */
230 if(verbose>1)
231 printf("converting radioactivity concentrations into %s\n", output_name);
232 if(weight>0.0) f=weight/dose; else f=100.0/dose;
233 if(verbose>1) printf("image is multiplied by factor %g\n", f);
234 ret=imgArithmConst(&pet, f, '*', 1.0E+20, verbose-4);
235 if(ret!=0) {
236 fprintf(stderr, "Error: cannot calculate %s.\n", output_name);
237 imgEmpty(&pet); return(4);
238 }
239 pet.unit=IMGUNIT_UNITLESS;
240 if(verbose>2) {
241 strcpy(tmp, imgUnit(pet.unit));
242 printf("converted image calibration unit := %s\n", tmp);
243 if(verbose>3) printf("converted img.unit := %d\n", pet.unit);
244 }
245
246
247 /*
248 * Save as result image and exit, if average-over-time was not needed
249 */
250 if(doAverage==0) {
251 if(verbose>1) fprintf(stdout, "writing %s image\n", output_name);
252 ret=imgWrite(suvfile, &pet);
253 if(ret) {
254 fprintf(stderr, "Error: %s\n", pet.statmsg);
255 imgEmpty(&pet); return(11);
256 }
257 if(verbose>0)
258 fprintf(stdout, "%s image written in %s\n", output_name, suvfile);
259
260 imgEmpty(&pet);
261 return(0);
262 }
263
264
265 /*
266 * Calculate the average-over-time image (if we still are here)
267 */
268 if(verbose>1) fprintf(stdout, "calculating average-over-time image\n");
269 ret=imgTimeIntegral(&pet, 60.0*tstart, 60.0*tstop, &rout, 1, tmp, verbose-2);
270 if(ret!=0) {
271 fprintf(stderr, "Error: %s.\n", tmp);
272 imgEmpty(&pet); imgEmpty(&rout); return(6);
273 }
274 if(verbose>1) fprintf(stdout, "%s.\n", tmp);
275 imgEmpty(&pet);
276
277 /*
278 * Save result image
279 */
280 if(verbose>1) fprintf(stdout, "writing static %s image\n", output_name);
281 ret=imgWrite(suvfile, &rout);
282 if(ret) {
283 fprintf(stderr, "Error: %s\n", rout.statmsg);
284 imgEmpty(&rout); return(12);
285 }
286 if(verbose>0)
287 fprintf(stdout, "static %s image written in %s\n", output_name, suvfile);
288
289 imgEmpty(&rout);
290 return(0);
291}
292/*****************************************************************************/
293
294/*****************************************************************************/
int atof_with_check(char *double_as_string, double *result_value)
Definition decpoint.c:107
double atof_dpi(char *str)
Definition decpoint.c:59
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 imgConvertUnit(IMG *img, char *unit)
Definition imgarithm.c:480
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
char type
char unit
int _fileFormat
unsigned short int dimt
const char * statmsg