TPCCLIB
Loading...
Searching...
No Matches
flat2nii.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 <math.h>
14#include <string.h>
15#include <time.h>
16/*****************************************************************************/
17#include "tpcextensions.h"
18//#include "tpcift.h"
19//#include "tpccsv.h"
20//#include "tpctac.h"
21#include "tpcdcm.h"
22#include "tpcecat.h"
23#include "tpcnifti.h"
24#include "tpcimage.h"
25/*****************************************************************************/
26
27/*****************************************************************************/
28static char *info[] = {
29 "Create a 4D PET image file in NIfTI 1S format, with contents from",
30 "the 32-bit float values in flat binary file.",
31 "Flat file must contain the pixel values in order t>z>y>x.",
32 " ",
33 "Usage: @P [Options] flatfile xdim ydim zdim tdim imagefile",
34 " ",
35 "Options:",
36 " -pxlsize=<x,y,z>",
37 " Pixel sizes in x, y, and z dimensions in mm; by default 1 mm each.",
38 " -stdoptions", // List standard options like --help, -v, etc
39 " ",
40 "Examples:",
41 " @P -pxlsize=2.5,2.5,3.0 data.bin 128 128 63 25 output",
42 " ",
43 "See also: img2flat, tac2nii, nii_ehdr, img2tif, simboxes, simcirc, pxl2mask",
44 " ",
45 "Keywords: image, NIfTI, simulation, software testing",
46 0};
47/*****************************************************************************/
48
49/*****************************************************************************/
50/* Turn on the globbing of the command line, since it is disabled by default in
51 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
52 In Unix&Linux wildcard command line processing is enabled by default. */
53/*
54#undef _CRT_glob
55#define _CRT_glob -1
56*/
57int _dowildcard = -1;
58/*****************************************************************************/
59
60/*****************************************************************************/
64/*****************************************************************************/
65int main(int argc, char **argv)
66{
67 int ai, help=0, version=0, verbose=1;
68 char flatfile[FILENAME_MAX], dbname[FILENAME_MAX];
69 int dimx=0, dimy=0, dimz=0, dimt=0;
70 double pxlsize[3]={1.0,1.0,1.0};
71 int ret=0;
72
73
74 /*
75 * Get arguments
76 */
77 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
78 flatfile[0]=dbname[0]=(char)0;
79
80 /* Options */
81 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') { /* options */
82 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
83 if(strncasecmp(cptr, "PXLSIZE=", 8)==0) {
84 if(atofList(cptr+8, ",", pxlsize, 3)<3)
85 {fprintf(stderr, "Error: invalid pixel sizes.\n"); return(1);}
86 if(!(pxlsize[0]>0.0) || !(pxlsize[1]>0.0) || !(pxlsize[2]>0.0))
87 {fprintf(stderr, "Error: invalid pixel sizes.\n"); return(1);}
88 continue;
89 }
90 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
91 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
92 return(1);
93 } else break; // tac name argument may start with '-'
94
95 TPCSTATUS status; statusInit(&status);
96 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
97 status.verbose=verbose-1;
98
99 /* Print help or version? */
100 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
101 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
102 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
103
104 /* Process other arguments, starting from the first non-option */
105 ret=0;
106 if(ai<argc) {strlcpy(flatfile, argv[ai], FILENAME_MAX); ai++;}
107 if(ai<argc) {if(atoiCheck(argv[ai++], &dimx)) ret++;}
108 if(ai<argc) {if(atoiCheck(argv[ai++], &dimy)) ret++;}
109 if(ai<argc) {if(atoiCheck(argv[ai++], &dimz)) ret++;}
110 if(ai<argc) {if(atoiCheck(argv[ai++], &dimt)) ret++;}
111 if(ret || dimx<1 || dimy<1 || dimz<1 || dimt<0) {
112 fprintf(stderr, "Error: invalid dimension.\n");
113 return(1);
114 }
115 if(ai<argc) {strlcpy(dbname, argv[ai], FILENAME_MAX); ai++;}
116 if(ai<argc) {fprintf(stderr, "Error: too many arguments.\n"); return(1);}
117
118 /* Is something missing or wrong? */
119 if(!dbname[0]) {
120 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
121 return(1);
122 }
123
124 /* In verbose mode print arguments and options */
125 if(verbose>1) {
126 printf("flatfile := %s\n", flatfile);
127 printf("dbname := %s\n", dbname);
128 printf("dimx := %d\n", dimx);
129 printf("dimy := %d\n", dimy);
130 printf("dimz := %d\n", dimz);
131 printf("dimt := %d\n", dimt);
132 printf("sizex := %g\n", pxlsize[0]);
133 printf("sizey := %g\n", pxlsize[1]);
134 printf("sizez := %g\n", pxlsize[2]);
135 fflush(stdout);
136 }
137
138 /* Make NIfTI filenames */
139 if(verbose>1) printf("Make NIfTI file names\n");
140 char hdrfile[FILENAME_MAX], imgfile[FILENAME_MAX], siffile[FILENAME_MAX];
141 if(niftiCreateFNames(dbname, hdrfile, imgfile, siffile, IMG_FORMAT_NIFTI_1S)) {
142 fprintf(stderr, " Error: invalid NIfTI name %s\n", dbname);
143 return(1);
144 }
145
146
147 /* Allocate memory for float data */
148 if(verbose>1) printf("Allocate memory for flat data\n");
149 size_t pxlNr=(size_t)dimz*dimy*dimx*dimt;
150 float *fdata;
151 fdata=(float*)calloc(pxlNr, sizeof(float));
152 if(fdata==NULL) {
153 fprintf(stderr, "Error: out of memory.\n");
154 return(2);
155 }
156
157 /*
158 * Read the binary file
159 */
160 {
161 FILE *fp;
162 if(verbose>1) printf("Opening input datafile %s\n", flatfile);
163 if((fp=fopen(flatfile, "rb")) == NULL) {
164 fprintf(stderr, "Error: cannot open file %s\n", flatfile);
165 free(fdata); return(3);
166 }
167 float *fptr=fdata;
168 size_t rnr=fread((char*)fptr, 4, pxlNr, fp);
169 if(rnr==0) {
170 fprintf(stderr, "Error: cannot read file %s\n", flatfile);
171 fclose(fp); free(fdata); return(3);
172 }
173 if(rnr<pxlNr) {
174 fprintf(stderr, "Error: binary file does not contain data for all pixels.\n");
175 fclose(fp); free(fdata); return(3);
176 }
177 /* Check that we are at the end of the binary file; feof() does not help here */
178 char buf[10];
179 rnr=fread(buf, 4, 1, fp);
180 if(rnr!=0) {
181 fprintf(stderr, "Error: mismatching matrix size and binary data.\n");
182 fclose(fp); free(fdata); return(3);
183 }
184 fclose(fp);
185 }
186
187 /* Find the range of pixel values */
188 float pxlmin, pxlmax; pxlmin=pxlmax=nanf("");
189 for(size_t i=0; i<pxlNr; i++) if(!isfinite(pxlmin) || fdata[i]<pxlmin) pxlmin=fdata[i];
190 for(size_t i=0; i<pxlNr; i++) if(!isfinite(pxlmax) || fdata[i]>pxlmax) pxlmax=fdata[i];
191 if(verbose>1) {
192 printf(" pxlmin := %g\n", pxlmin);
193 printf(" pxlmax := %g\n", pxlmax);
194 }
195
196
197 /*
198 * Set NIfTI header contents
199 */
200 if(verbose>1) printf("Fill NIfTI header\n");
201 NIFTI_DSR dsr;
202 dsr.n=1;
203 /* Set NIfTI byte order to current machines byte order */
205 /* Initiate header structures with zeroes */
206 memset(&dsr.h1, 0, sizeof(NIFTI_1_HEADER));
207 memset(&dsr.e, 0, sizeof(NIFTI_EXTENDER));
208 /* Set header */
210 strcpy(dsr.h1.data_type, "");
211 strlcpy(dsr.h1.db_name, dbname, 17);
212 dsr.h1.extents=16384; // not used in NIfTI, but required for Analyze compatibility
213 dsr.h1.regular='r'; // not used in NIfTI, but required for Analyze compatibility
214 dsr.h1.dim_info='\0'; // MRI slice ordering
215 /* Image dimension */
216 for(int i=0; i<8; i++) dsr.h1.dim[i]=1;
217 dsr.h1.dim[0]=4;
218 dsr.h1.dim[1]=dimx;
219 dsr.h1.dim[2]=dimy;
220 dsr.h1.dim[3]=dimz;
221 dsr.h1.dim[4]=dimt;
222 dsr.h1.intent_p1=0.0;
223 dsr.h1.intent_p2=0.0;
224 dsr.h1.intent_p3=0.0;
226 dsr.h1.datatype=NIFTI_DT_FLOAT; // data as floats, so no need to scale
227 dsr.h1.bitpix=32;
228 dsr.h1.slice_start=0;
229 for(int i=0; i<8; i++) dsr.h1.pixdim[i]=0.0;
230 // https://nifti.nimh.nih.gov/nifti-1/documentation/nifti1fields/nifti1fields_pages/qsform.html
231 dsr.h1.pixdim[0]=1.0; // Set to either 1.0 or -1.0
232 dsr.h1.pixdim[1]=pxlsize[0]; // pixel size in x dimension
233 dsr.h1.pixdim[2]=pxlsize[1]; // pixel size in y dimension
234 dsr.h1.pixdim[3]=pxlsize[2]; // pixel size in z dimension
235 dsr.h1.vox_offset=352; // Would be 0 for 1D format
236 dsr.h1.scl_slope=1.0; // no need to scale pixel values
237 dsr.h1.scl_inter=0.0; // no need to scale pixel values
238 dsr.h1.slice_end=0;
239 dsr.h1.slice_code=0;
241 dsr.h1.cal_max=pxlmax;
242 dsr.h1.cal_min=pxlmin;
243 dsr.h1.slice_duration=0.0;
244 dsr.h1.toffset=0.0;
245 dsr.h1.glmax=dsr.h1.cal_max; // unused in NIfTI
246 dsr.h1.glmin=0; // unused in NIfTI
247 strlcpy(dsr.h1.descrip, "flat2nii", 80);
248 strcpy(dsr.h1.aux_file, "");
249 dsr.h1.qform_code=0;
250 dsr.h1.sform_code=0;
251 dsr.h1.quatern_b=0;
252 dsr.h1.quatern_c=0;
253 dsr.h1.quatern_d=0;
254 dsr.h1.qoffset_x=0;
255 dsr.h1.qoffset_y=0;
256 dsr.h1.qoffset_z=0;
257 for(int i=0; i<4; i++) dsr.h1.srow_x[i]=0;
258 for(int i=0; i<4; i++) dsr.h1.srow_y[i]=0;
259 for(int i=0; i<4; i++) dsr.h1.srow_z[i]=0;
260 strcpy(dsr.h1.intent_name, "");
261 strcpy(dsr.h1.magic, "n+1"); // Would be "ni1" for 1D format
262 /* Extension is left as 0 0 0 0 */
263
264
265 /*
266 * Write NIfTI header
267 */
268 if(verbose>1) printf("Writing NIfTI header\n");
269 /* Delete previous NIfTI */
270 /* It does not need to be valid NIfTI format, just that the file names match */
271 if(fileExist(hdrfile)) remove(hdrfile);
272 if(fileExist(imgfile)) remove(imgfile);
273 //if(fileExist(siffile)) remove(siffile);
274 /* Write NIfTI header */
275 if(niftiWriteHeader(hdrfile, &dsr, verbose-1)) {
276 fprintf(stderr, "Error: cannot write header.\n");
277 free(fdata);
278 return(11);
279 }
280
281 /*
282 * Write NIfTI matrix data
283 */
284 if(verbose>1) printf("Writing NIfTI image data\n");
285 FILE *fp=fopen(imgfile, "r+b");
286 if(fp==NULL) {
287 fprintf(stderr, "Error: cannot open %s for write.\n", imgfile);
288 free(fdata);
289 if(fileExist(hdrfile)) remove(hdrfile);
290 if(fileExist(imgfile)) remove(imgfile);
291 return(12);
292 }
293 /* Move file pointer to the place of matrix data start */
294 if(fseeko(fp, (size_t)dsr.h1.vox_offset, SEEK_SET)!=0) {
295 fprintf(stderr, "Error: invalid file write position.\n");
296 fclose(fp); free(fdata);
297 if(fileExist(hdrfile)) remove(hdrfile);
298 if(fileExist(imgfile)) remove(imgfile);
299 return(13);
300 }
301 /* Write data */
302 if(fwrite(fdata, sizeof(float), pxlNr, fp) != pxlNr) {
303 fprintf(stderr, "Error: cannot write image matrix.\n");
304 fclose(fp); free(fdata);
305 if(fileExist(hdrfile)) remove(hdrfile);
306 if(fileExist(imgfile)) remove(imgfile);
307 return(14);
308 }
309 fclose(fp); free(fdata);
310 if(verbose>0) printf("written %s\n", imgfile);
311
312 return(0);
313}
314/*****************************************************************************/
315
316/*****************************************************************************/
318/*****************************************************************************/
int atofList(const char *s1, const char *s2, double *x, int maxn)
Definition decpoint.c:150
int endianLittle()
Definition endian.c:53
int fileExist(const char *filename)
Definition filexist.c:17
int niftiCreateFNames(const char *filename, char *hdrfile, char *imgfile, char *siffile, int fileformat)
Definition imagenii.c:17
int atoiCheck(const char *s, int *v)
Definition intutil.c:25
int niftiWriteHeader(const char *filename, NIFTI_DSR *dsr, int verbose)
Definition niftiio.c:445
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:47
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:169
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:339
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:114
void statusInit(TPCSTATUS *s)
Definition statusmsg.c:104
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
Definition statusmsg.c:142
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition stringext.c:632
float quatern_d
Definition tpcnifti.h:289
float quatern_c
Definition tpcnifti.h:287
short int qform_code
Definition tpcnifti.h:281
char db_name[18]
Definition tpcnifti.h:220
float qoffset_x
Definition tpcnifti.h:291
short int slice_start
Definition tpcnifti.h:247
short int slice_end
Definition tpcnifti.h:257
float slice_duration
Definition tpcnifti.h:267
short int datatype
Definition tpcnifti.h:243
float intent_p2
Definition tpcnifti.h:237
char aux_file[24]
Definition tpcnifti.h:278
float intent_p1
Definition tpcnifti.h:235
float srow_z[4]
Definition tpcnifti.h:301
float srow_x[4]
Definition tpcnifti.h:297
char intent_name[16]
Definition tpcnifti.h:303
float intent_p3
Definition tpcnifti.h:239
short int bitpix
Definition tpcnifti.h:245
float pixdim[8]
Definition tpcnifti.h:249
char data_type[10]
Definition tpcnifti.h:218
short int sform_code
Definition tpcnifti.h:283
float vox_offset
Definition tpcnifti.h:251
float srow_y[4]
Definition tpcnifti.h:299
float qoffset_y
Definition tpcnifti.h:293
char descrip[80]
Definition tpcnifti.h:276
char magic[4]
Definition tpcnifti.h:306
float scl_inter
Definition tpcnifti.h:255
float qoffset_z
Definition tpcnifti.h:295
short int dim[8]
Definition tpcnifti.h:233
short int intent_code
Definition tpcnifti.h:241
float quatern_b
Definition tpcnifti.h:285
float scl_slope
Definition tpcnifti.h:253
NIFTI_EXTENDER e
Definition tpcnifti.h:408
NIFTI_1_HEADER h1
Definition tpcnifti.h:404
int byte_order
Definition tpcnifti.h:412
int verbose
Verbose level, used by statusPrint() etc.
Header file for libtpcdcm.
Header file for libtpcecat.
Header file for library libtpcextensions.
@ TPCERROR_OK
No error.
Header file for libtpcimage.
@ IMG_FORMAT_NIFTI_1S
NIfTI-1 single-file format.
Definition tpcimage.h:43
Header file for libtpcnifti.
#define NIFTI_DT_FLOAT
Definition tpcnifti.h:100
#define NIFTI1_HEADER_SIZE
Definition tpcnifti.h:33
#define NIFTI_INTENT_NONE
Definition tpcnifti.h:129
#define NIFTI_UNITS_SEC
Definition tpcnifti.h:52
#define NIFTI_UNITS_MM
Definition tpcnifti.h:48