TPCCLIB
Loading...
Searching...
No Matches
flat2img.c
Go to the documentation of this file.
1
8/*****************************************************************************/
9#include "tpcclibConfig.h"
10/*****************************************************************************/
11#include <stdio.h>
12#include <stdlib.h>
13#include <math.h>
14#include <string.h>
15#include <time.h>
16#include <float.h>
17/*****************************************************************************/
18#include "libtpcmisc.h"
19#include "libtpcimgio.h"
20#include "libtpcimgp.h"
21/*****************************************************************************/
22/* Local functions */
23void zero_hot_spots(float *fdata, int dim);
25 char *fname, int *planeNr, int *frameNr, int *dim1, int *dim2);
26/*****************************************************************************/
27
28/*****************************************************************************/
29static char *info[] = {
30 "Construct an ECAT PET image or sinogram from pixel values stored as 4-byte",
31 "(32-bits) floating point values in a binary flat file.",
32 "Data must be stored in this matrix order: all planes of the 1st frame,",
33 "2nd frame, and so on.",
34 "The format of the output file is determined from its file name extension",
35 "(*.v, *.s, *.i, *.img or *.scn).",
36 "The byte order of binary data is assumed to be the same as in current",
37 "platform; use option -e to change the byte order, if necessary.",
38 " ",
39 "Usage: @P [Options] flatfile ecatfile [zdim tdim xdim ydim]",
40 " ",
41 "Options:",
42 " -mif=<Matrix information file>",
43 " ASCII file containing the number of planes and frames, and x and y",
44 " dimensions, unless these are given as command-line arguments.",
45 " -scanner=<Advance|931|HR+|HRRT>",
46 " Set scanner specific parameters in headers.",
47 " -zoom=<reconstruction zoom>",
48 " Set reconstruction zoom in image headers (only for images)",
49//" -if=<Interfile header>",
50//" Read certain information from a interfile-type header",
51 " -zero",
52 " Zero hot spots outside of FOV (only for images).",
53 " -bins=<Nr of bins>",
54 " Nr of bins in the output sinogram; use this to add (nr-dim1)/2 bins",
55 " filled with zeroes to both sides of sinogram.",
56 " -transpose",
57 " Transpose the data, i.e. switch x and y axis.",
58 " -e ",
59 " Switch the byte order between little and big endian",
60 " -stdoptions", // List standard options like --help, -v, etc
61 " ",
62 "Examples:",
63 " @P -scanner=Advance xyz.dat xyz.scn 35 1 281 336",
64 " @P -scanner=HRRT -mif=qwe.mif qwe.dat qwe.v",
65 " ",
66 "See also: img2flat, flat2nii, asc2flat, ana2ecat, nii2ecat, e7emhdr, eframe",
67 " ",
68 "Keywords: ECAT, image, sinogram, format conversion, simulation",
69 0};
70/*****************************************************************************/
71
72/*****************************************************************************/
73/* Turn on the globbing of the command line, since it is disabled by default in
74 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
75 In Unix&Linux wildcard command line processing is enabled by default. */
76/*
77#undef _CRT_glob
78#define _CRT_glob -1
79*/
80int _dowildcard = -1;
81/*****************************************************************************/
82
83/*****************************************************************************/
87int main(int argc, char **argv)
88{
89 int ai, help=0, version=0, verbose=1;
90 int pi, fi, xi, yi, n, ret, dim1=0, dim2=0;
91 int frameNr=0, planeNr=0, binNr=0;
92 int fov_corr=0, scanner_type=0, transpose=0, change_endian=0;
93 char imgfile[FILENAME_MAX], datfile[FILENAME_MAX],
94 miffile[FILENAME_MAX], iftfile[FILENAME_MAX];
95 FILE *fp;
96 float zoom=1.0;
97 size_t count;
98
99
100
101 /*
102 * Get arguments
103 */
104 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
105 imgfile[0]=datfile[0]=miffile[0]=iftfile[0]=(char)0;
106 /* Options */
107 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') { /* options */
108 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
109 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
110 cptr=argv[ai]+1;
111 if(strncasecmp(cptr, "ZERO", 2)==0) {
112 fov_corr=1; continue;
113 } else if(strncasecmp(cptr, "MIF=", 4)==0) {
114 strcpy(miffile, cptr+4); if(strlen(miffile)>0) continue;
115 } else if(strncasecmp(cptr, "INF=", 4)==0) {
116 strcpy(miffile, cptr+4); if(strlen(miffile)>0) continue;
117 } else if(strncasecmp(cptr, "ZOOM=", 5)==0) {
118 double f;
119 ret=atof_with_check(cptr+5, &f);
120 if(ret==0 && f>0.01) {zoom=f; continue;}
121 } else if(strncasecmp(cptr, "SCANNER=", 8)==0) {
122 cptr+=8;
123 if(*cptr=='9') {scanner_type=SCANNER_ECAT931; continue;}
124 if(*cptr=='A' || *cptr=='a') {scanner_type=SCANNER_ADVANCE; continue;}
125 if(strcasecmp(cptr, "HRRT")==0) {scanner_type=SCANNER_HRRT; continue;}
126 if(strncasecmp(cptr, "HR", 2)==0) {scanner_type=SCANNER_HRPLUS; continue;}
127 } else if(strncasecmp(cptr, "BINS=", 5)==0) {
128 binNr=atoi(cptr+5); if(binNr>0.0) continue;
129 } else if(strncasecmp(cptr, "TRANSPOSE", 2)==0) {
130 transpose=1; continue;
131 } else if(strcasecmp(cptr, "E")==0) {
132 change_endian=1; continue;
133 }
134 fprintf(stderr, "Error: invalid option '%s'\n", argv[ai]);
135 return(1);
136 } else break;
137
138 /* Print help or version? */
139 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
140 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
141 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
142
143 /* Process other arguments, starting from the first non-option */
144 if(ai<argc) {strlcpy(datfile, argv[ai], FILENAME_MAX); ai++;}
145 if(ai<argc) {strlcpy(imgfile, argv[ai], FILENAME_MAX); ai++;}
146 if(!imgfile[0]) {
147 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
148 return(1);
149 }
150 if(!miffile[0]) {
151 if(ai<argc) planeNr=atoi(argv[ai++]);
152 if(ai<argc) frameNr=atoi(argv[ai++]);
153 if(ai<argc) dim1=atoi(argv[ai++]);
154 if(ai<argc) dim2=atoi(argv[ai++]);
155 if(planeNr<=0 || frameNr<=0 || dim1<=0 || dim2<=0) {
156 fprintf(stderr, "Error: missing/invalid data size argument.\n"); return(1);}
157 }
158 if(ai<argc) {fprintf(stderr, "Error: too many arguments.\n"); return(1);}
159
160 /* Is something missing? */
161 if(strcasecmp(imgfile, datfile)==0) {
162 fprintf(stderr, "Error: same name for input and output file.\n");
163 return(1);
164 }
165 if(!miffile[0] && (planeNr==0 || frameNr==0 || dim1==0 || dim2==0)) {
166 fprintf(stderr, "Error: information on data size not given.\n");
167 return(1);
168 }
169
170 /* In verbose mode print arguments and options */
171 if(verbose>1) {
172 printf("datfile := %s\n", datfile);
173 printf("imgfile := %s\n", imgfile);
174 printf("miffile := %s\n", miffile);
175 //printf("iftfile := %s\n", iftfile);
176 printf("zoom := %g\n", zoom);
177 printf("scanner_type := %d\n", scanner_type);
178 printf("transpose := %d\n", transpose);
179 printf("change_endian := %d\n", change_endian);
180 printf("fov_corr := %d\n", fov_corr);
181 fflush(stdout);
182 }
183
184
185 /* Read matrix information file, if it was given */
186 if(miffile[0]) {
187 if(verbose>1) printf("reading %s\n", miffile);
188 ret=readMatrixInformation(miffile, &planeNr, &frameNr, &dim1, &dim2);
189 if(ret) {
190 fprintf(stderr, "Error: invalid matrix information file.\n");
191 return(1);
192 }
193 }
194 /* Check dimensions */
195 if(planeNr<1 || frameNr<1 || dim1<2 || dim2<2) {
196 fprintf(stderr, "Error: invalid matrix dimensions.\n");
197 return(1);
198 }
199
200 /* Set and check binNr vs dim1 */
201 if(binNr>0) {
202 if(binNr<=dim1) {
203 fprintf(stderr, "Error: binNr should be larger than dimx.\n");
204 return(1);
205 }
206 n=binNr; binNr=dim1; dim1=n; /* switch binNr and dimx */
207 } else {
208 binNr=dim1; /* If bin nr was not set; also for images ! */
209 }
210
211 if(verbose>1) {
212 printf("planeNr := %d\n", planeNr);
213 printf("frameNr := %d\n", frameNr);
214 printf("dimx := %d\n", dim1);
215 printf("dimy := %d\n", dim2);
216 printf("binNr := %d\n", binNr);
217 }
218
219
220 /*
221 * Decide output file type
222 */
223 if(verbose>1) printf("defining output file type\n");
224 IMG img; imgInit(&img);
225 {
226 char *cptr=strrchr(imgfile, '.'); if(cptr!=NULL) cptr++;
227 if(strcasecmp(cptr, "SCN")==0) {
228 img.type=IMG_TYPE_RAW;
230 } else if(strcasecmp(cptr, "IMG")==0) {
233 } else if(strcasecmp(cptr, "S")==0) {
234 img.type=IMG_TYPE_RAW;
236 } else if(strcasecmp(cptr, "I")==0) {
239 } else if(strcasecmp(cptr, "V")==0) {
242 } else if(strcasecmp(cptr, "NII")==0) {
245 } else {
246 fprintf(stderr, "Error: invalid output filename.\n");
247 return(1);
248 }
249 }
250 if(fov_corr && img.type==IMG_TYPE_RAW) {
251 fprintf(stderr, "Error: option -zero is available only for images.\n");
252 return(1);
253 }
254 if(binNr!=dim1 && img.type!=IMG_TYPE_RAW) {
255 fprintf(stderr, "Error: bin nr can be used only with sinograms.\n");
256 return(1);
257 }
258 if(verbose>0) {
259 printf("type := %d\n", img.type);
260 printf("_fileFormat := %d\n", img._fileFormat);
261 }
262
263
264 /*
265 * Allocate memory for one PET frame in IMG struct
266 */
267 if(verbose>1) printf("allocating memory for one PET time frame\n");
268 ret=imgAllocate(&img, planeNr, dim2, dim1, 1);
269 if(ret) {
270 fprintf(stderr, "Error: cannot allocate memory for PET data.\n");
271 return(3);
272 }
273 /* leave frame times to 0, since they are not known */
274 /* but set plane numbers */
275 for(pi=0; pi<planeNr; pi++) img.planeNumber[pi]=pi+1;
276
277
278 /*
279 * Set header
280 */
281 if(verbose>1) printf("setting header information\n");
282 /* unit unknown */
283 img.unit=IMGUNIT_UNKNOWN;
284 /* studynr from data filename */
285 studynr_from_fname(datfile, img.studyNr);
286 /* patient name unknown */
287 strcpy(img.patientName, "Unknown");
288 /* zoom */
289 img.zoom=zoom;
290 /* radiopharmaceutical unknown */
291 strcpy(img.radiopharmaceutical, "Unknown");
292 /* isotope halflife unknown, so set it to zero */
293 img.isotopeHalflife=0.0;
294 /* assume that sinogram is not decay corrected but image is */
297 /* cannot know the scan start time */
298 img.scanStart=(time_t)time(NULL);
299 /* set the scanner specific parameters */
300 if(scanner_type==0) {
301 if(dim1==281) scanner_type=SCANNER_ADVANCE;
302 else if(dim1==192) scanner_type=SCANNER_ECAT931;
303 else if(dim1==288) scanner_type=SCANNER_HRPLUS;
304 else if(planeNr==207) scanner_type=SCANNER_HRRT;
305 else fprintf(stderr, "Warning: scanner specific fields are left empty!\n");
306 }
307 if(scanner_type>0)
308 imgSetScanner(&img, scanner_type); // after IMG is allocated!
309 /* weighting is not known */
310 img.isWeight=0;
311 if(verbose>5) imgInfo(&img);
312
313 /*
314 * Allocate memory for one plane of input data
315 */
316 if(verbose>1) printf("Allocating memory for input data\n");
317 int pxlNr=binNr*dim2;
318 float *fdata, *fptr;
319 fdata=(float*)malloc(pxlNr*4);
320 if(fdata==NULL) {
321 fprintf(stderr, "Error: cannot allocate memory for binary data.\n");
322 imgEmpty(&img); return(3);
323 }
324
325 /*
326 * Open input binary file
327 */
328 if(verbose>1) printf("Opening input datafile %s\n", datfile);
329 if((fp=fopen(datfile, "rb")) == NULL) {
330 fprintf(stderr, "Error: cannot open file %s\n", datfile);
331 imgEmpty(&img); free(fdata); return(4);
332 }
333
334 /*
335 * Delete existing PET file
336 */
337 if(access(imgfile, 0)!=-1 && remove(imgfile)!=0) {
338 fprintf(stderr, "Error: cannot remove existing %s\n", imgfile);
339 imgEmpty(&img); free(fdata); return(11);
340 }
341
342 /*
343 * Read and write one PET frame at a time
344 */
345 n=0;
346 for(fi=0; fi<frameNr; fi++) {
347
348 if(verbose>0) printf("reading frame %d\n", fi+1);
349 /* Read and copy binary data one plane at a time into IMG struct */
350 for(pi=0; pi<planeNr; pi++) {
351 if(verbose>2) {fflush(stdout); printf(" reading plane %d\n", pi+1);}
352 /* Read float data */
353 fptr=fdata;
354 ret=fread((char*)fptr, 4, pxlNr, fp); if(ret<pxlNr) {
355 if(ret==0)
356 fprintf(stderr, "Error in reading data on pl%02d fr%02d.\n",
357 pi+1, fi+1);
358 else
359 fprintf(stderr, "Error: file does not contain all pixel values.\n");
360 free(fdata); fclose(fp); imgEmpty(&img);
361 return(5);
362 }
363 /* Change the byte order if necessary */
364 if(change_endian) {fptr=fdata; swawbip(fptr, 4*pxlNr);}
365 /* if option -z is given, call zero_hot_spots*/
366 if(fov_corr==1) zero_hot_spots(fdata, dim1);
367 /* Copy the data into IMG data structure */
368 fptr=fdata;
369 if(transpose==1) {
370 for(xi=(dim1-binNr)/2; xi<(dim1+binNr)/2; xi++)
371 for(yi=0; yi<dim2; yi++)
372 img.m[pi][yi][xi][0]=(*fptr++);
373 } else {
374 for(yi=0; yi<dim2; yi++)
375 for(xi=(dim1-binNr)/2; xi<(dim1+binNr)/2; xi++)
376 img.m[pi][yi][xi][0]=(*fptr++);
377 }
378 n++;
379 } // next plane
380
381 /* Set frame times to zero */
382 img.start[0]=img.end[0]=img.mid[0]=0.0;
383
384 /* Write this frame */
385 if(verbose>2) {fflush(stdout); printf(" writing frame\n");}
386 ret=imgWriteFrame(imgfile, fi+1, &img, 0);
387 if(ret) {
388 fprintf(stderr, "Error: %s\n", imgStatus(ret));
389 free(fdata); fclose(fp); imgEmpty(&img); return(13);
390 }
391
392 } // next frame
393 if(verbose>0) fprintf(stdout, "%s saved.\n", imgfile);
394 imgEmpty(&img);
395
396 /* Check that all data is read */
397 if(verbose>1) printf("verifying that all data was read\n");
398 fptr=fdata; count=fread((char*)fptr, 4, 1, fp);
399 if(!feof(fp) || count>0)
400 fprintf(stderr, "Warning: some data in %s were not read!\n", datfile);
401 /* Close file and free data buffer */
402 free(fdata); fclose(fp);
403
404 /* Check that all matrices were read */
405 if(n!=(frameNr*planeNr)) {
406 fprintf(stderr, "Error: %s did not contain %dx%d matrices!\n",
407 datfile, planeNr, frameNr);
408 return(8);
409 }
410
411 return(0);
412}
413#if(0)
414 /*
415 * Get header information from Interfile-type header file
416 */
417 if(iftfile[0]) {
418 /* Read IFT file */
419 iftInit(&ift);
420 ret=iftRead(&ift, iftfile, 0);
421 if(ret) {
422 fprintf(stderr, "Error (%d) in reading %s: %s\n", ret, iftfile, ift.status);
423 imgEmpty(&img); iftEmpty(&ift);
424 return(7);
425 }
426 /* Copy suitable information into IMG */
427 ret=imgApplyIFT(&img, &ift);
428 if(ret<1)
429 fprintf(stderr, "Warning: no information was retrieved from IF header.\n");
430 iftEmpty(&ift);
431 }
432#endif
433/*****************************************************************************/
434
435/*****************************************************************************/
437
443 float *fdata,
445 int dim
446) {
447 float *fptr;
448 float r, d;
449 int i;
450
451 r=(float)dim/2.0; if(r>25.0) r-=5.0;
452 fptr=fdata;
453 for(i=0; i<dim*dim; i++, fptr++ ) {
454 d=hypotf((float)(i/dim-dim/2), (float)(i-dim*(i/dim)-dim/2));
455/*
456 d=sqrt((i/dim-dim/2)*(i/dim-dim/2)+
457 (i-dim*(i/dim)-dim/2)*(i-dim*(i/dim)-dim/2));
458*/
459 if(d>r) *fptr=0.0;
460 }
461}
462/*****************************************************************************/
463
464/*****************************************************************************/
470 char *fname,
472 int *planeNr,
474 int *frameNr,
476 int *dim1,
478 int *dim2
479) {
480 FILE *fp;
481 int n;
482
483 if(fname==NULL || planeNr==NULL || frameNr==NULL || dim1==NULL || dim2==NULL)
484 return(1);
485 fp=fopen(fname, "r"); if(fp==NULL) return(2);
486 n=fscanf(fp, "%d %d %d %d", planeNr, frameNr, dim1, dim2);
487 fclose(fp); if(n!=4) return(3);
488 if(*planeNr<1 || *frameNr<1 || *dim1<1 || *dim2<1) return(4);
489 return(0);
490}
491/*****************************************************************************/
492
493/*****************************************************************************/
int atof_with_check(char *double_as_string, double *result_value)
Definition decpoint.c:107
void zero_hot_spots(float *fdata, int dim)
Definition flat2img.c:441
int readMatrixInformation(char *fname, int *planeNr, int *frameNr, int *dim1, int *dim2)
Definition flat2img.c:468
void iftEmpty(IFT *ift)
Definition ift.c:60
void iftInit(IFT *ift)
Definition ift.c:45
int iftRead(IFT *ift, char *filename, int is_key_required, int verbose)
Definition iftfile.c:24
void imgInfo(IMG *image)
Definition img.c:359
char * imgStatus(int status_index)
Definition img.c:330
int imgAllocate(IMG *image, int planes, int rows, int columns, int frames)
Definition img.c:194
void imgEmpty(IMG *image)
Definition img.c:121
void imgInit(IMG *image)
Definition img.c:60
int imgWriteFrame(const char *fname, int frame_to_write, IMG *img, int frame_index)
Definition imgfile.c:392
int imgSetScanner(IMG *img, int scanner_type)
Definition imgscanner.c:14
Header file for libtpcimgio.
#define IMG_TYPE_RAW
#define IMG_E7
#define SCANNER_ADVANCE
#define SCANNER_HRRT
#define IMG_NIFTI_1S
#define IMG_E7_2D
#define IMG_DC_CORRECTED
#define IMG_E63
#define IMG_DC_NONCORRECTED
#define SCANNER_HRPLUS
#define SCANNER_ECAT931
#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
void swawbip(void *buf, long long int size)
Definition swap.c:93
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
int studynr_from_fname(char *fname, char *studynr)
Definition studynr.c:119
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:383
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:158
char type
char patientName[32]
float **** m
char decayCorrection
char unit
time_t scanStart
int _fileFormat
int * planeNumber
float * start
float * end
float zoom
char radiopharmaceutical[32]
float isotopeHalflife
char studyNr[MAX_STUDYNR_LEN+1]
float * mid
char isWeight