TPCCLIB
Loading...
Searching...
No Matches
imgcalc.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 <math.h>
15#include <string.h>
16#include <unistd.h>
17#include <time.h>
18/*****************************************************************************/
19#include "libtpcmisc.h"
20#include "libtpcimgio.h"
21#include "libtpcimgp.h"
22/*****************************************************************************/
23
24/*****************************************************************************/
25static char *info[] = {
26 "Simple arithmetic calculations on PET images.",
27 " ",
28 "Usage: @P [Options] file1 operation constant|file2 outputfile",
29 " ",
30 ", where",
31 " Operation = +, -, x , :",
32 " Constant = Image 1 is operated with this value.",
33 " ",
34 "Options:",
35 " -frames",
36 " All frames in image 1 are processed with the 1st time frame of image 2.",
37 " -max=<value>",
38 " Upper limit for output pixels (may be necessary in division).",
39//" -scale = image2 data is scaled to image1 maximum before operation",
40 " -abs[olute]",
41 " Save absolute voxel values.",
42 " -stdoptions", // List standard options like --help, -v, etc
43 " ",
44 "Image 1 and 2 must be in the same format, and they must have same",
45 "matrix size and plane numbers.",
46 "Data is not interpolated or corrected for physical decay, and thus it is",
47 "on the responsibility of the user to check that PET time frames are similar",
48 "and that physical decay and other corrections are appropriately considered.",
49 " ",
50 "Constant can be given directly as value on the command line, or as name of",
51 "file containing only the value, or value with key 'constant'.",
52 " ",
53 "Input files must not be overwritten with the output file.",
54 " ",
55 "Examples:",
56 " @P a999.flow.img - a1000.flow.img subtr.img",
57//" @P -scale s1444dy1.img - s1445dy1.img s1444.subtr.img",
58 " @P o657dy1.v : 2.34 o657rda.v",
59//" @P -frames -max=0.25 l333dy1.scn x l333.nrm l333dy1.corr.scn",
60 " ",
61 "See also: imgdecay, imgunit, eframe, imginv, esplit, imginteg, imgthrs",
62 " ",
63 "Keywords: image, modelling, simulation, tool",
64 0};
65/*****************************************************************************/
66
67/*****************************************************************************/
68/* Turn on the globbing of the command line, since it is disabled by default in
69 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
70 In Unix&Linux wildcard command line processing is enabled by default. */
71/*
72#undef _CRT_glob
73#define _CRT_glob -1
74*/
75int _dowildcard = -1;
76/*****************************************************************************/
77
78/*****************************************************************************/
80
88 const char *file1,
90 const char *file2,
92 int verbose
93) {
94 int ii, mi, ret;
95 char tmp[1024];
96 ECAT_HEADERS ehdr;
97
98 if(verbose>1) printf("ecatCopyHeadersNoQuant(%s, %s)\n", file1, file2);
99 if(file1==NULL || file2==NULL) return(1);
100
101
102 /* Read headers */
103 ehdrInitiate(&ehdr);
104 ret=ecat7ReadHeaders(file1, &ehdr, verbose-1); if(ret!=0) return(10);
105 /* Remove main header information that should NOT be copied */
106 strcpy(tmp, "user_process_code");
107 ii=iftGet(&ehdr.mh, tmp, 0); iftDeleteItem(&ehdr.mh, ii, 0);
108 strcpy(tmp, "ecat_calibration_factor");
109 ii=iftGet(&ehdr.mh, tmp, 0); iftDeleteItem(&ehdr.mh, ii, 0);
110
111 /* Remove subheader information that should NOT be copied */
112 for(mi=0; mi<ehdr.nr; mi++) {
113 strcpy(tmp, "scale_factor");
114 ii=iftGet(&ehdr.m[mi].sh, tmp, 0); iftDeleteItem(&ehdr.m[mi].sh, ii, 0);
115 strcpy(tmp, "image_min");
116 ii=iftGet(&ehdr.m[mi].sh, tmp, 0); iftDeleteItem(&ehdr.m[mi].sh, ii, 0);
117 strcpy(tmp, "image_max");
118 ii=iftGet(&ehdr.m[mi].sh, tmp, 0); iftDeleteItem(&ehdr.m[mi].sh, ii, 0);
119 strcpy(tmp, "scan_min");
120 ii=iftGet(&ehdr.m[mi].sh, tmp, 0); iftDeleteItem(&ehdr.m[mi].sh, ii, 0);
121 strcpy(tmp, "scan_max");
122 ii=iftGet(&ehdr.m[mi].sh, tmp, 0); iftDeleteItem(&ehdr.m[mi].sh, ii, 0);
123 }
124
125 /* Write headers */
126 ret=ecat7WriteHeaders(file2, &ehdr, verbose-1);
127 ehdrEmpty(&ehdr);
128 if(ret!=0) return(10+ret);
129
130 return 0;
131}
133/*****************************************************************************/
134
135/*****************************************************************************/
139int main(int argc, char **argv)
140{
141 int ai, help=0, version=0, verbose=1;
142 int ret, fi;
143 int allframes_with_one=0;
144 int frame_nr=0;
145 char file1[FILENAME_MAX], file2[FILENAME_MAX], file3[FILENAME_MAX];
146 char *cptr;
147 char operation=0; // '+', '-', '*', '/'
148 int isvalue=0;
149 IMG img1, img2;
150 float opconst=nan("");
151 float ulimit=0.0;
152 int absolutes=0;
153
154
155 /*
156 * Get arguments
157 */
158 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
159 file1[0]=file2[0]=file3[0]=(char)0;
160 imgInit(&img1); imgInit(&img2);
161 /* Options */
162 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') { /* options */
163 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
164 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
165 if(strcasecmp(cptr, "FRAMES")==0) {
166 allframes_with_one=1; continue;
167 } else if(strncasecmp(cptr, "MAX=", 4)==0) {
168 ulimit=atof_dpi(cptr+4); if(ulimit>0.0) continue;
169 } else if(strncasecmp(cptr, "ABSOLUTES", 3)==0) {
170 absolutes=1; continue;
171 }
172 fprintf(stderr, "Error: invalid option '%s'\n", argv[ai]);
173 return(1);
174 } else break;
175
176 /* Print help or version? */
177 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
178 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
179 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
180
181
182 /* Process other arguments, starting from the first non-option */
183 if(ai<argc) {strlcpy(file1, argv[ai], FILENAME_MAX); ai++;}
184 if(ai<argc) {
185 if(strncasecmp(argv[ai], "DIVISION", 3)==0) {
186 operation='/';
187 } else if(strncasecmp(argv[ai], "MULTIPLICATION", 3)==0) {
188 operation='*';
189 } else if(strncasecmp(argv[ai], "MINUS", 3)==0) {
190 operation='-';
191 } else if(strncasecmp(argv[ai], "PLUS", 3)==0) {
192 operation='+';
193 } else if(strlen(argv[ai])==1) switch(*argv[ai]) {
194 case '+' : operation='+'; break;
195 case '-' : operation='-'; break;
196 case '*' : // this might be hard to use, but accept it anyway
197 case '.' :
198 case 'X' :
199 case 'x' : operation='*'; break;
200 case '/' : // MinGW does not work with '/', it requires '//'
201 case ':' : operation='/'; break;
202 }
203 if(operation==0) {fprintf(stderr, "Error: invalid operator.\n"); return(1);}
204 ai++;
205 }
206 if(ai<argc) {
207 double v;
208 char *s=iftReadValue(argv[ai], "constant", 0);
209 if(s!=NULL) {ret=atof_with_check(s, &v); free(s);}
210 else ret=atof_with_check(argv[ai], &v);
211 if(ret==0) {isvalue=1; opconst=v; allframes_with_one=1;}
212 else strlcpy(file2, argv[ai], FILENAME_MAX);
213 ai++;
214 }
215 if(ai<argc) {strlcpy(file3, argv[ai], FILENAME_MAX); ai++;}
216 if(ai<argc) {fprintf(stderr, "Error: too many arguments.\n"); return(1);}
217
218 /* Is something missing? */
219 if(!file3[0]) {tpcPrintUsage(argv[0], info, stdout); return(1);}
220
221
222 /* In verbose mode print arguments and options */
223 if(verbose>1) {
224 fflush(stdout);
225 for(ai=0; ai<argc; ai++) printf("%s ", argv[ai]);
226 printf("\n");
227 printf("file1 := %s\n", file1);
228 printf("operation := %c\n", operation);
229 if(isvalue) printf("value := %g\n", opconst);
230 else printf("file2 := %s\n", file2);
231 printf("ulimit := %g\n", ulimit);
232 printf("absolute_values := %d\n", absolutes);
233 printf("allframes_with_one := %d\n", allframes_with_one);
234 }
235 if(verbose>1) IMG_TEST=verbose-1;
236
237 /* Check that output file is not the same as either of input files */
238 if(strcasecmp(file3, file1)==0 || strcasecmp(file3, file2)==0) {
239 fprintf(stderr, "Error: original file must not be overwritten.\n");
240 return(1);
241 }
242
243
244 /*
245 * Read information about input files
246 */
247 if(verbose>0) printf("reading image(s)...\n");
248 ret=imgReadHeader(file1, &img1, IMG_UNKNOWN); if(verbose>10) imgInfo(&img1);
249 if(ret) {
250 fprintf(stderr, "Error in reading %s: %s\n", file1, imgStatus(ret));
251 return(2);
252 }
253 if(*file2) {
254 ret=imgReadHeader(file2, &img2, IMG_UNKNOWN); if(verbose>10) imgInfo(&img2);
255 if(ret) {
256 fprintf(stderr, "Error in reading %s: %s\n", file2, imgStatus(ret));
257 imgEmpty(&img1); return(2);
258 }
259 /* Check that file types, sizes etc are matching */
260 if(img1.type!=img2.type || img1.dimx!=img2.dimx || img1.dimy!=img2.dimy) {
261 fprintf(stderr, "Error: non-matching files.\n");
262 imgEmpty(&img1); imgEmpty(&img2); return(2);
263 }
264 if(img1.zoom!=img2.zoom) fprintf(stderr, "Warning: different zoom.\n");
265 /* If file1 has several frames and file2 has only one frame, */
266 /* set allframes_with_one=1 */
267 if(allframes_with_one==0 && img1.dimt>1 && img2.dimt==1) {
268 if(verbose>0) {
269 fprintf(stderr, "Warning: automatically applying option -frames\n"); fflush(stderr);}
270 allframes_with_one=1;
271 }
272 /* Error, if frame nr is different but allframes_with_one==0 */
273 if(allframes_with_one==0 && img1.dimt!=img2.dimt) {
274 fprintf(stderr, "Error: non-matching frame number.\n");
275 imgEmpty(&img1); imgEmpty(&img2); return(2);
276 }
277 }
278
279
280 /*
281 * Operation, one frame at a time
282 */
283 if(verbose>0) printf("computing");
284 frame_nr=img1.dimt;
285 imgEmpty(&img1); imgEmpty(&img2);
286 for(fi=0; fi<frame_nr; fi++) {
287 if(verbose>1) printf("\n frame %d\n", fi+1);
288 /* Read first/next frame in file1 */
289 ret=imgReadFrame(file1, fi+1, &img1, 0);
290 if(ret) {
291 fprintf(stderr, "\nError in reading %s: %s\n", file1, imgStatus(ret));
292 imgEmpty(&img1); imgEmpty(&img2); (void)remove(file3);
293 return(3);
294 }
295 if(*file2 && (fi==0 || allframes_with_one==0)) {
296 if(verbose>2) printf("\n reading frame %d in file2\n", fi+1);
297 /* Read first/next frame in file2 */
298 ret=imgReadFrame(file2, fi+1, &img2, 0);
299 if(ret) {
300 fprintf(stderr, "\nError in reading %s: %s\n", file2, imgStatus(ret));
301 imgEmpty(&img1); imgEmpty(&img2); (void)remove(file3);
302 return(4);
303 }
304 }
305 /* Do the operation */
306 if(verbose>2) printf("\noperating frame %d\n", fi+1);
307 if(*file2) {
308 if(allframes_with_one==0)
309 ret=imgArithm(&img1, &img2, operation, ulimit, verbose-3);
310 else
311 ret=imgArithmFrame(&img1, &img2, operation, ulimit, verbose-3);
312 } else {
313 ret=imgArithmConst(&img1, opconst, operation, ulimit, verbose-3);
314 }
315 if(ret) {
316 fprintf(stderr, "Error %d in calculation.\n", ret);
317 imgEmpty(&img1); imgEmpty(&img2); (void)remove(file3); return(6);
318 }
319 /* Convert result pixel values into absolute values, if requested */
320 if(absolutes && imgAbs(&img1)!=0) {
321 fprintf(stderr, "Error in calculation.\n");
322 imgEmpty(&img1); imgEmpty(&img2); (void)remove(file3); return(7);
323 }
324 /* Remove previous output image */
325 if(fi==0) (void)remove(file3);
326 /* Attenuation format cannot currently be saved from IMG */
327 if(img1.type==IMG_TYPE_ATTN) img1.type=IMG_TYPE_RAW;
328 /* Save the frame */
329 ret=imgWriteFrame(file3, fi+1, &img1, 0);
330 if(ret) {
331 fprintf(stderr, "\nError in writing %s: %s\n", file3, imgStatus(ret));
332 imgEmpty(&img1); imgEmpty(&img2); (void)remove(file3);
333 return(11);
334 }
335 if(verbose==1) {fprintf(stdout, "."); fflush(stdout);}
336 }
337 if(verbose==1) printf("\n");
338
339 if(img1._fileFormat==IMG_E7 || img1._fileFormat==IMG_E7_2D) {
340 if(verbose>1) printf("copying header information\n");
341 ret=ecat7CopyHeadersNoQuant(file1, file3, verbose-1);
342 if(verbose>0 && ret!=0) {printf("copying headers not successful (%d).\n", ret); fflush(stdout);}
343 }
344
345 imgEmpty(&img1); imgEmpty(&img2);
346 if(verbose>0) printf("done.\n");
347
348 return(0);
349}
350/*****************************************************************************/
351
352/*****************************************************************************/
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 ehdrEmpty(ECAT_HEADERS *ehdr)
Definition ecat7ift.c:47
int ecat7WriteHeaders(const char *fname, ECAT_HEADERS *ehdr, int verbose)
Definition ecat7ift.c:755
void ehdrInitiate(ECAT_HEADERS *ehdr)
Definition ecat7ift.c:21
int ecat7ReadHeaders(const char *fname, ECAT_HEADERS *ehdr, int verbose)
Definition ecat7ift.c:687
int iftDeleteItem(IFT *ift, int item, int verbose)
Definition ift.c:169
char * iftReadValue(char *filename, char *keystr, int verbose)
Definition iftfile.c:180
int iftGet(IFT *ift, char *key, int verbose)
Definition iftsrch.c:15
int IMG_TEST
Definition img.c:6
void imgInfo(IMG *image)
Definition img.c:359
char * imgStatus(int status_index)
Definition img.c:330
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 imgArithmFrame(IMG *img1, IMG *img2, char operation, float ulimit, int verbose)
Definition imgarithm.c:168
int ecat7CopyHeadersNoQuant(const char *file1, const char *file2, int verbose)
Definition imgcalc.c:86
int imgWriteFrame(const char *fname, int frame_to_write, IMG *img, int frame_index)
Definition imgfile.c:392
int imgReadFrame(const char *fname, int frame_to_read, IMG *img, int frame_index)
Definition imgfile.c:269
int imgReadHeader(const char *fname, IMG *img, int format)
Definition imgfile.c:199
Header file for libtpcimgio.
#define IMG_TYPE_ATTN
#define IMG_TYPE_RAW
#define IMG_E7
#define IMG_UNKNOWN
#define IMG_E7_2D
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
ECAT_MATRIX * m
unsigned short int dimx
char type
int _fileFormat
unsigned short int dimt
unsigned short int dimy
float zoom