TPCCLIB
Loading...
Searching...
No Matches
imgledif.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/*****************************************************************************/
26static char *info[] = {
27 "Calculates a difference image from late and early time frames of a dynamic",
28 "PET image in ECAT 6.3, 7.x, NIfTI-1, or Analyze 7.5 format.",
29 "Analyze and NIfTI image must have SIF in the same folder for frame time",
30 "information.",
31 " ",
32 "Usage: @P [Options] image earlytime latetime diffimage",
33 " ",
34 "For each image pixel, program will calculate the average concentration",
35 "from time zero to the early time (min), and the average from late time (min)",
36 "to the end of PET, and subtract the early average from the late average",
37 "(or optionally vice versa).",
38 " ",
39 "Options:",
40 " -EL",
41 " Late average is subtracted from early average to reveal arterial pools.",
42 " -frames",
43 " Frame numbers are given instead of times.",
44 " -noneg",
45 " Negative differences are set to zero.",
46 " -abs",
47 " Absolute differences are calculated.",
48 " -efile=<filename>",
49 " Write early average image in given file.",
50 " -lfile=<filename>",
51 " Write late average image in given file.",
52 " -stdoptions", // List standard options like --help, -v, etc
53 " ",
54 "See also: imginteg, imgsuv, imgcalc, imgthrs, imgfrdyn, imgcutof",
55 " ",
56 "Keywords: image, dynamics, input, mask, time",
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;
79 int useFrames=0; // 0=no, 1=yes
80 int workNegatives=0; // 0=leave, 1=set to zero, 2=absolute values
81 int difType=0; // 0=late-early, 1=early-late
82 char petfile[FILENAME_MAX], diffile[FILENAME_MAX];
83 char earlyfile[FILENAME_MAX], latefile[FILENAME_MAX];
84 float tearly, tlate;
85
86
87
88 /*
89 * Get arguments
90 */
91 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
92 petfile[0]=diffile[0]=earlyfile[0]=latefile[0]=(char)0;
93 tearly=tlate=-1.0;
94 /* Get options */
95 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
96 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
97 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
98 if(strncasecmp(cptr, "FRAMES", 5)==0) {
99 useFrames=1; continue;
100 } else if(strncasecmp(cptr, "NONEGATIVES", 5)==0) {
101 workNegatives=1; continue;
102 } else if(strncasecmp(cptr, "ABSOLUTE", 3)==0) {
103 workNegatives=2; continue;
104 } else if(strcasecmp(cptr, "EL")==0) {
105 difType=1; continue;
106 } else if(strcasecmp(cptr, "LE")==0) {
107 difType=0; continue;
108 } else if(strncasecmp(cptr, "EFILE=", 6)==0) {
109 strlcpy(earlyfile, cptr+6, FILENAME_MAX); continue;
110 } else if(strncasecmp(cptr, "LFILE=", 6)==0) {
111 strlcpy(latefile, cptr+6, FILENAME_MAX); continue;
112 }
113 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
114 return(1);
115 } else break;
116
117 /* Print help or version? */
118 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
119 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
120 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
121
122 /* Process other arguments, starting from the first non-option */
123 if(ai<argc) {strlcpy(petfile, argv[ai], FILENAME_MAX); ai++;}
124 if(ai<argc) {
125 double v;
126 if(atof_with_check(argv[ai], &v)!=0 || !(v>0.0)) {
127 if(!useFrames) fprintf(stderr, "Error: invalid early time '%s'.\n", argv[ai]);
128 else fprintf(stderr, "Error: invalid early frame '%s'.\n", argv[ai]);
129 return(1);
130 }
131 tearly=v; ai++;
132 }
133 if(ai<argc) {
134 double v;
135 if(atof_with_check(argv[ai], &v)!=0 || !(v>0.0)) {
136 if(!useFrames) fprintf(stderr, "Error: invalid late time '%s'.\n", argv[ai]);
137 else fprintf(stderr, "Error: invalid late frame '%s'.\n", argv[ai]);
138 return(1);
139 }
140 tlate=v; ai++;
141 }
142 if(ai<argc) {strlcpy(diffile, argv[ai], FILENAME_MAX); ai++;}
143 if(ai<argc) {fprintf(stderr, "Error: too many arguments.\n"); return(1);}
144
145
146 /* Did we get all the information that we need? */
147 if(!diffile[0]) {
148 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
149 return(1);
150 }
151 /* Convert times to seconds */
152 if(!useFrames) {tearly*=60.0; tlate*=60.0;}
153
154
155 /* In verbose mode print arguments and options */
156 if(verbose>1) {
157 printf("petfile := %s\n", petfile);
158 printf("diffile := %s\n", diffile);
159 printf("useFrames := %d\n", useFrames);
160 if(!useFrames) {
161 printf("earlytime := %g s\n", tearly);
162 printf("latetime := %g s\n", tlate);
163 } else {
164 printf("earlyframe := %d\n", (int)roundf(tearly));
165 printf("lateframe := %d\n", (int)roundf(tlate));
166 }
167 printf("difType := %d\n", difType);
168 printf("workNegatives := %d\n", workNegatives);
169 if(earlyfile[0]) printf("earlyfile := %s\n", earlyfile);
170 if(latefile[0]) printf("latefile := %s\n", latefile);
171 fflush(stdout);
172 }
173 if(verbose>9) IMG_TEST=verbose-9; else IMG_TEST=0;
174
175
176 /*
177 * Read image
178 */
179 if(verbose>0) {fprintf(stdout, "reading image %s\n", petfile); fflush(stdout);}
180 IMG img; imgInit(&img);
181 ret=imgRead(petfile, &img);
182 if(ret) {
183 fprintf(stderr, "Error: %s\n", img.statmsg); if(verbose>1) imgInfo(&img);
184 return(2);
185 }
186 /* Check if PET data is raw or image */
187 if(img.type!=IMG_TYPE_IMAGE) {
188 fprintf(stderr, "Error: %s is not an image.\n", petfile);
189 imgEmpty(&img); return(2);
190 }
191 if(img.dimt<2) {
192 fprintf(stderr, "Error: %s is static image.\n", petfile);
193 imgEmpty(&img); return(2);
194 }
195 if(imgNaNs(&img, 1)>0)
196 if(verbose>0) fprintf(stderr, "Warning: missing pixel values.\n");
197 if(verbose>0 && !useFrames) {
198 printf("image time range: %g - %g s\n", img.start[0], img.end[img.dimt-1]);
199 fflush(stdout);
200 }
201
202 /* Check that frame times are available */
203 if(!imgExistentTimes(&img)) {
204 fprintf(stderr, "Error: image does not contain frame times.\n"); fflush(stderr);
205 imgEmpty(&img); return(2);
206 }
207
208 /* Make sure that there is no overlap in image frames */
209 if(img.dimt>1) {
210 if(verbose>1) {fprintf(stdout, "checking frame overlap in %s\n", petfile); fflush(stdout);}
211 ret=imgDeleteFrameOverlap(&img);
212 if(ret) {
213 fprintf(stderr, "Error: image %s has overlapping frame times.\n", petfile);
214 imgEmpty(&img); return(2);
215 }
216 }
217
218 /* Convert frame numbers to times */
219 if(useFrames) {
220 int i=(int)roundf(tearly);
221 if(i<1) {
222 fprintf(stderr, "Error: invalid early frame.\n");
223 imgEmpty(&img); return(2);
224 }
225 if(i>img.dimt) i=img.dimt;
226 tearly=img.end[i-1];
227
228 i=(int)roundf(tlate);
229 if(i<1 || i>img.dimt) {
230 fprintf(stderr, "Error: invalid late frame.\n");
231 imgEmpty(&img); return(2);
232 }
233 tlate=img.start[i-1];
234
235 if(verbose>1) {
236 printf("earlytime := %g s\n", tearly);
237 printf("latetime := %g s\n", tlate);
238 fflush(stdout);
239 }
240 }
241
242 /* Check that times fit inside image time range */
243 if(tearly<=img.start[0] || tearly>img.end[img.dimt-1]) {
244 fprintf(stderr, "Error: invalid early time.\n");
245 imgEmpty(&img); return(2);
246 }
247 if(tlate<img.start[0] || tlate>=img.end[img.dimt-1]) {
248 fprintf(stderr, "Error: invalid late time.\n");
249 imgEmpty(&img); return(2);
250 }
251
252
253 /* Calculate early average */
254 char tmp[256];
255 IMG img1; imgInit(&img1);
256 if(verbose>1) {fprintf(stdout, "calculating the first average image\n"); fflush(stdout);}
257 ret=imgTimeIntegral(&img, 0.0, tearly, &img1, 1, tmp, verbose-2);
258 if(ret!=0) {
259 fprintf(stderr, "Error: %s.\n", tmp);
260 imgEmpty(&img); imgEmpty(&img1); return(4);
261 }
262 if(verbose>1) {fprintf(stdout, "%s.\n", tmp); fflush(stdout);}
263 if(earlyfile[0]) {
264 ret=imgWrite(earlyfile, &img1);
265 if(ret) {
266 fprintf(stderr, "Error: %s\n", img1.statmsg);
267 imgEmpty(&img); imgEmpty(&img1); return(21);
268 }
269 if(verbose>0) {fprintf(stdout, "early average image written in %s\n", earlyfile); fflush(stdout);}
270 }
271
272 /* Calculate late average */
273 IMG img2; imgInit(&img2);
274 if(verbose>1) {fprintf(stdout, "calculating the second average image\n"); fflush(stdout);}
275 ret=imgTimeIntegral(&img, tlate, img.end[img.dimt-1], &img2, 1, tmp, verbose-2);
276 if(ret!=0) {
277 fprintf(stderr, "Error: %s.\n", tmp);
278 imgEmpty(&img); imgEmpty(&img1); imgEmpty(&img2); return(5);
279 }
280 if(verbose>1) {fprintf(stdout, "%s.\n", tmp); fflush(stdout);}
281 if(latefile[0]) {
282 ret=imgWrite(latefile, &img2);
283 if(ret) {
284 fprintf(stderr, "Error: %s\n", img2.statmsg);
285 imgEmpty(&img); imgEmpty(&img1); imgEmpty(&img2); return(22);
286 }
287 if(verbose>0) {fprintf(stdout, "late average image written in %s\n", latefile); fflush(stdout);}
288 }
289
290 /* Set time range */
291 img1.start[0]=img.start[0];
292 img1.end[0]=img.end[img.dimt-1];
293
294 imgEmpty(&img);
295
296 /* Calculate early - late */
297 if(verbose>1) {fprintf(stdout, "calculating the difference\n"); fflush(stdout);}
298 ret=imgArithm(&img1, &img2, '-', -1.0, verbose-6);
299 if(ret!=0) {
300 if(verbose>1) fprintf(stderr, "imgArithm()=%d\n", ret);
301 fprintf(stderr, "Error: cannot calculate difference image.\n");
302 imgEmpty(&img1); imgEmpty(&img2); return(6);
303 }
304 imgEmpty(&img2);
305
306 /* If requested, convert to late - early difference */
307 if(difType==0) {
308 ret=imgArithmConst(&img1, -1.0, '*', -1.0, verbose-6);
309 if(ret!=0) {
310 if(verbose>1) fprintf(stderr, "imgArithmConst()=%d\n", ret);
311 fprintf(stderr, "Error: cannot calculate difference image.\n");
312 imgEmpty(&img1); return(7);
313 }
314 }
315
316 /* If requested, store absolute values of differences */
317 if(workNegatives==2) {
318 ret=imgAbs(&img1);
319 if(ret!=0) {
320 if(verbose>1) fprintf(stderr, "imgAbs()=%d\n", ret);
321 fprintf(stderr, "Error: cannot calculate absolute differences.\n");
322 imgEmpty(&img1); return(8);
323 }
324 }
325
326 /* If requested, set negative difference to zero */
327 if(workNegatives==1) imgCutoff(&img1, 0.0, 1);
328
329
330 /*
331 * Save difference image
332 */
333 if(verbose>1) {fprintf(stdout, "writing difference image\n"); fflush(stdout);}
334 ret=imgWrite(diffile, &img1);
335 if(ret) {
336 fprintf(stderr, "Error: %s\n", img1.statmsg);
337 imgEmpty(&img1); return(11);
338 }
339 if(verbose>0) {fprintf(stdout, "difference image written in %s\n", diffile); fflush(stdout);}
340 imgEmpty(&img1);
341
342 return(0);
343}
344/*****************************************************************************/
345
346/*****************************************************************************/
int atof_with_check(char *double_as_string, double *result_value)
Definition decpoint.c:107
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 imgArithm(IMG *img1, IMG *img2, char operation, float ulimit, int verbose)
Definition imgarithm.c:16
int imgAbs(IMG *img)
Definition imgarithm.c:292
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
void imgCutoff(IMG *image, float cutoff, int mode)
Header file for libtpccurveio.
Header file for libtpcimgio.
#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
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.
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
unsigned short int dimt
float * start
float * end
const char * statmsg