TPCCLIB
Loading...
Searching...
No Matches
img_nii.c File Reference

NIfTI-1 PET image I/O routines for IMG data. More...

#include "libtpcimgio.h"

Go to the source code of this file.

Functions

int imgReadNifti (const char *filename, IMG *img, int verbose)
int imgReadNiftiFirstFrame (const char *filename, IMG *img, int verbose)
int imgReadNiftiHeader (const char *filename, IMG *img, int verbose)
int imgGetNiftiHeader (IMG *img, NIFTI_DSR *dsr, int verbose)
int imgReadNiftiFrame (const char *filename, int frame_to_read, IMG *img, int frame_index, int verbose)
int imgSetNiftiHeader (IMG *img, const char *dbname, NIFTI_DSR *dsr, float fmin, float fmax, int verbose)
int imgWriteNiftiFrame (const char *dbname, int frame_to_write, IMG *img, int frame_index, float fmin, float fmax, int verbose)
int imgWriteNifti (const char *dbname, IMG *img, int save_sif, int verbose)

Detailed Description

NIfTI-1 PET image I/O routines for IMG data.

Author
Vesa Oikonen

Function are not intended to support all NIfTI files or file properties, but only those that have been found necessary in Turku PET Centre.

Definition in file img_nii.c.

Function Documentation

◆ imgGetNiftiHeader()

int imgGetNiftiHeader ( IMG * img,
NIFTI_DSR * dsr,
int verbose )

Copy Nifti header information into IMG.

Returns
Returns IMG status, which is STATUS_OK (0) when call was successful, and >0 in case of an error.
See also
imgSetNiftiHeader, imgReadNiftiHeader
Parameters
imgPointer to IMG struct
dsrPointer to Nifti header contents
verboseVerbose level; if zero, then nothing is printed to stderr or stdout

Definition at line 218 of file img_nii.c.

225 {
226 if(verbose>0) {printf("imgGetNiftiHeader()\n"); fflush(stdout);}
227
228 /* Check the input */
229 if(img==NULL) return STATUS_FAULT;
231 return STATUS_FAULT;
232 imgSetStatus(img, STATUS_FAULT);
233 if(dsr==NULL) return STATUS_FAULT;
234
235 imgSetStatus(img, STATUS_INVALIDHEADER);
236
237 /* Get the image dimensions from header */
238 int dimNr=dsr->h.dim[0];
239 if(dimNr<2 || dimNr>4) {
240 if(verbose>0)
241 fprintf(stderr, "Error: Nifti image dimension %d is not supported\n", dimNr);
242 return STATUS_UNSUPPORTED;
243 }
244 int dimx, dimy, dimz=1, dimt=1;
245 dimx=dsr->h.dim[1]; dimy=dsr->h.dim[2];
246 if(dimNr>2) {dimz=dsr->h.dim[3]; if(dimNr>3) dimt=dsr->h.dim[4];}
247 long long pxlNr=dimx*dimy*dimz;
248 if(pxlNr<1) {
249 if(verbose>0) fprintf(stderr, "Error: invalid Nifti image dimensions.\n");
250 return STATUS_INVALIDHEADER;
251 }
252 img->dimx=dimx; img->dimy=dimy; img->dimz=dimz; img->dimt=dimt;
253
254 /* Copy information from header */
255 img->type=IMG_TYPE_IMAGE;
256 strcpy(img->studyNr, "");
257 strcpy(img->patientName, "");
258 /* NIfTI file format */
259 if(strcmp(dsr->h.magic, "ni1")==0) img->_fileFormat=IMG_NIFTI_1D;
260 else if(strcmp(dsr->h.magic, "n+1")==0) img->_fileFormat=IMG_NIFTI_1S;
261 else {
262 if(verbose>0) fprintf(stderr, "Error: invalid Nifti magic number.\n");
263 return STATUS_INVALIDHEADER;
264 }
265 /* NIfTI datatype is not needed, because currently saved as floats anyway */
266 //img->_dataType=dsr->h.datatype;
267 /* Pixel x,y,z sizes, converting units if necessary */
268 float f=1.0;
269 if(dsr->h.xyzt_units & NIFTI_UNITS_METER) f=1000.;
270 else if(dsr->h.xyzt_units & NIFTI_UNITS_MICRON) f=0.001;
271 else if(dsr->h.xyzt_units & NIFTI_UNITS_MM) f=1.0;
272 if(verbose>2) printf("pixel size conversion factor := %g\n", f);
273 for(int i=1; i<=3; i++) {
274 if(i==1) img->sizex=f*dsr->h.pixdim[i];
275 else if(i==2) img->sizey=f*dsr->h.pixdim[i];
276 else if(i==3) img->sizez=f*dsr->h.pixdim[i];
277 }
278 /* Orientation, quaternion, and transformation parameters */
279 img->xform[0]=dsr->h.qform_code;
280 img->xform[1]=dsr->h.sform_code;
281 img->quatern[0]=dsr->h.quatern_b;
282 img->quatern[1]=dsr->h.quatern_c;
283 img->quatern[2]=dsr->h.quatern_d;
284 img->quatern[3]=dsr->h.qoffset_x;
285 img->quatern[4]=dsr->h.qoffset_y;
286 img->quatern[5]=dsr->h.qoffset_z;
287 for(int i=0; i<4; i++) img->quatern[6+i]=dsr->h.srow_x[i];
288 for(int i=0; i<4; i++) img->quatern[10+i]=dsr->h.srow_y[i];
289 for(int i=0; i<4; i++) img->quatern[14+i]=dsr->h.srow_z[i];
290
291 /* Assumptions */
293
294 imgSetStatus(img, STATUS_OK);
295 return STATUS_OK;
296}
void imgSetStatus(IMG *img, int status_index)
Definition img.c:345
#define IMG_STATUS_OCCUPIED
#define IMG_NIFTI_1S
#define IMG_DC_CORRECTED
#define NIFTI_UNITS_METER
#define IMG_STATUS_INITIALIZED
#define NIFTI_UNITS_MICRON
#define IMG_NIFTI_1D
#define NIFTI_UNITS_MM
#define IMG_TYPE_IMAGE
float sizex
unsigned short int dimx
char type
char patientName[32]
char decayCorrection
short int xform[2]
char status
int _fileFormat
unsigned short int dimt
float sizey
unsigned short int dimz
unsigned short int dimy
float quatern[18]
char studyNr[MAX_STUDYNR_LEN+1]
float sizez
short int qform_code
short int sform_code
short int dim[8]
NIFTI_1_HEADER h

Referenced by imgFormatDetermine(), imgReadNiftiHeader(), and imgWriteNiftiFrame().

◆ imgReadNifti()

int imgReadNifti ( const char * filename,
IMG * img,
int verbose )

Read Nifti-1 image.

Nifti database name must be given with path. Either one file with extension .nii, or image and header files with extensions .img and .hdr must exist. Also SIF file with .sif extension is used, if it exists.

Returns
0 if ok, and otherwise IMG status code (<>0); sets IMG->statmsg in case of an error.
See also
imgInit, imgReadNiftiFirstFrame, imgReadNiftiHeader, imgWriteNifti
Parameters
filenameNifti database name with path, with or without extension
imgPointer to initialized IMG structure
verboseVerbose level; if zero, then nothing is printed to stderr or stdout

Definition at line 23 of file img_nii.c.

30 {
31 if(verbose>0) {printf("imgReadNifti(%s, ...)\n", filename); fflush(stdout);}
32
33 /* Check the arguments */
34 if(img==NULL || img->status!=IMG_STATUS_INITIALIZED) {
35 if(img!=NULL) imgSetStatus(img, STATUS_FAULT);
36 if(verbose>0) fprintf(stderr, "Error: invalid IMG argument\n");
37 return(STATUS_FAULT);
38 }
39 if(filename==NULL || !filename[0]) {
40 imgSetStatus(img, STATUS_FAULT);
41 if(verbose>0) fprintf(stderr, "Error: invalid filename\n");
42 return(STATUS_FAULT);
43 }
44 imgSetStatus(img, STATUS_OK);
45
46 /* Read header information from file */
47 int ret=imgReadNiftiHeader(filename, img, verbose-1); if(ret) {return(ret);}
48 if(verbose>10) imgInfo(img);
49
50 /* Allocate memory for all frames */
51 ret=imgAllocate(img, img->dimz, img->dimy, img->dimx, img->dimt);
52 if(ret) {
53 imgSetStatus(img, STATUS_OK);
54 return STATUS_NOMEMORY;
55 }
56
57 /* Read one frame at a time */
58 for(int fi=0; fi<img->dimt; fi++) {
59 ret=imgReadNiftiFrame(filename, 1+fi, img, fi, verbose-1);
60 if(ret) return(ret);
61 }
62
63 /* All went well */
64 imgSetStatus(img, STATUS_OK);
65 return(STATUS_OK);
66}
void imgInfo(IMG *image)
Definition img.c:359
int imgAllocate(IMG *image, int planes, int rows, int columns, int frames)
Definition img.c:194
int imgReadNiftiHeader(const char *filename, IMG *img, int verbose)
Definition img_nii.c:134
int imgReadNiftiFrame(const char *filename, int frame_to_read, IMG *img, int frame_index, int verbose)
Definition img_nii.c:311

Referenced by imgRead().

◆ imgReadNiftiFirstFrame()

int imgReadNiftiFirstFrame ( const char * filename,
IMG * img,
int verbose )

Read the first frame of Nifti-1 image into IMG data structure.

Nifti database name must be given with path. Either one file with extension .nii, or image and header files with extensions .img and .hdr must exist. Also SIF file with .sif extension is used, if it exists.

Returns
0 if ok, and otherwise IMG status code (<>0); sets IMG->statmsg in case of an error.
Parameters
filenameNifti database name with path, with or without extension
imgPointer to initialized IMG structure
verboseVerbose level; if zero, then nothing is printed to stderr or stdout

Definition at line 78 of file img_nii.c.

85 {
86 if(verbose>0) {printf("imgReadNiftiFirstFrame(%s, ...)\n", filename); fflush(stdout);}
87
88 /* Check the arguments */
89 if(img==NULL || img->status!=IMG_STATUS_INITIALIZED) {
90 if(img!=NULL) imgSetStatus(img, STATUS_FAULT);
91 if(verbose>0) fprintf(stderr, "Error: invalid IMG argument\n");
92 return(STATUS_FAULT);
93 }
94 if(filename==NULL || !filename[0]) {
95 imgSetStatus(img, STATUS_FAULT);
96 if(verbose>0) fprintf(stderr, "Error: invalid filename\n");
97 return(STATUS_FAULT);
98 }
99 imgSetStatus(img, STATUS_OK);
100
101 /* Read header information from file */
102 int ret=imgReadNiftiHeader(filename, img, verbose-1); if(ret) {return(ret);}
103 if(verbose>10) imgInfo(img);
104
105 /* Allocate memory for one frame */
106 img->dimt=1;
107 ret=imgAllocate(img, img->dimz, img->dimy, img->dimx, img->dimt);
108 if(ret) {
109 imgSetStatus(img, STATUS_OK);
110 return STATUS_NOMEMORY;
111 }
112
113 /* Read the first frame */
114 ret=imgReadNiftiFrame(filename, 1, img, 0, verbose-1); if(ret) return(ret);
115
116 /* All went well */
117 imgSetStatus(img, STATUS_OK);
118 return(STATUS_OK);
119}

Referenced by imgNiftiToEcat().

◆ imgReadNiftiFrame()

int imgReadNiftiFrame ( const char * filename,
int frame_to_read,
IMG * img,
int frame_index,
int verbose )

Read a specified frame from a Nifti database files into preallocated IMG data structure.

IMG header is assumed to be filled correctly before calling this function, except for information concerning separate planes and this frame, which is filled here.

Returns
0 if ok, and otherwise IMG status code (<>0); sets IMG->statmsg in case of an error. If frame does not exist, then and only then STATUS_NOMATRIX is returned.
See also
imgReadNifti, imgNaNs
Parameters
filenamePointer to string that contains the name of NIfTI database with path, with or without filename extension. Either one file with extension .nii, or image and header files with extensions .img and .hdr must exist. Also SIF file with .sif extension is used, if it exists; however, information concerning separate frames or planes is not filled.
frame_to_readFrame which will be read from database [1..frameNr]
imgPointer to the IMG data. Place for the frame must be preallocated
frame_indexIMG frame index [0..dimt-1] where data will be placed
verboseVerbose level; if zero, then nothing is printed to stderr or stdout

Definition at line 311 of file img_nii.c.

327 {
328 char basefile[FILENAME_MAX], tmp[256];
329 char datfile[FILENAME_MAX], hdrfile[FILENAME_MAX], siffile[FILENAME_MAX];
330 NIFTI_DSR dsr;
331 int ret;
332 SIF sif;
333 FILE *fp;
334 float *fdata=NULL, *fptr;
335
336
337 if(verbose>0) {
338 printf("\nimgReadNiftiFrame(%s, %d, *img, %d, %d)\n",
339 filename, frame_to_read, frame_index, verbose);
340 fflush(stdout);
341 }
342
343 /* Check the input */
344 if(img==NULL || img->status!=IMG_STATUS_OCCUPIED) {
345 if(img!=NULL) imgSetStatus(img, STATUS_FAULT);
346 if(verbose>0) fprintf(stderr, "Error: invalid IMG argument\n");
347 return(STATUS_FAULT);
348 }
349 if(filename==NULL || !filename[0]) {
350 imgSetStatus(img, STATUS_FAULT);
351 if(verbose>0) fprintf(stderr, "Error: invalid filename\n");
352 return(STATUS_FAULT);
353 }
354 if(frame_index<0 || frame_index>img->dimt-1 || frame_to_read<1) {
355 imgSetStatus(img, STATUS_FAULT);
356 if(verbose>0) fprintf(stderr, "Error: invalid frame settings\n");
357 return STATUS_FAULT;
358 }
359
360 /* Extract the base file name without extensions */
361 strcpy(basefile, filename); niftiRemoveFNameExtension(basefile);
362 if(strlen(basefile)<1) {
363 imgSetStatus(img, STATUS_FAULT);
364 if(verbose>0) fprintf(stderr, "Error: invalid filename\n");
365 return(STATUS_FAULT);
366 }
367
368 /* Make the image and header filenames, and read Nifti header */
369 ret=niftiExists(basefile, hdrfile, datfile, siffile, &dsr, verbose-2, tmp);
370 if(ret==0) {
371 imgSetStatus(img, STATUS_NOFILE);
372 if(verbose>0) fprintf(stderr, "Error: %s\n", tmp);
373 return(STATUS_NOFILE);
374 }
375 if(ret==1 && verbose>1) {
376 printf("no SIF found for %s\n", basefile); fflush(stdout);}
377
378 /* Open image datafile */
379 if(verbose>2) {fprintf(stdout, "reading image data %s\n", datfile); fflush(stdout);}
380 if((fp=fopen(datfile, "rb")) == NULL) {
381 imgSetStatus(img, STATUS_NOIMGDATAFILE);
382 return STATUS_NOIMGDATAFILE;
383 }
384
385 /* Allocate memory for one image frame */
386 imgSetStatus(img, STATUS_NOMEMORY);
387 fdata=calloc((size_t)img->dimx*img->dimy*img->dimz, sizeof(float));
388 if(fdata==NULL) {fclose(fp); return STATUS_NOMEMORY;}
389
390 /* Read the required image frame */
391 fptr=fdata;
392 ret=niftiReadImagedata(fp, &dsr, frame_to_read, fptr, verbose-1, tmp);
393 if(verbose>1) printf("niftiReadImagedata() -> %s\n", tmp);
394 fclose(fp);
395 if(ret==-1) { /* no more frames */
396 free(fdata); imgSetStatus(img, STATUS_NOMATRIX);
397 return STATUS_NOMATRIX;
398 }
399 if(ret!=0) {
400 free(fdata); imgSetStatus(img, STATUS_UNSUPPORTED);
401 return STATUS_UNSUPPORTED;
402 }
403
404 if(0) { // Call imgNaNs(IMG, 1) instead
405 /* Check for invalid pixel values and set to zero.
406 SPM can write lots of NaNs on image borders.
407 Remove this later, if/when all image processing functions support NaN and Inf. */
408 long long int goodNr=0;
409 fptr=fdata;
410 for(int zi=0; zi<img->dimz; zi++)
411 for(int yi=0; yi<img->dimy; yi++)
412 for(int xi=0; xi<img->dimx; xi++) {
413 if(isfinite(*fptr)) goodNr++; else *fptr=0.0;
414 fptr++;
415 }
416 if(goodNr==0) {
417 free(fdata);
418 imgSetStatus(img, STATUS_NOIMGDATA);
419 return STATUS_NOIMGDATA;
420 }
421 }
422
423 /* Copy pixel values to IMG */
424 fptr=fdata;
425 for(int zi=0; zi<img->dimz; zi++)
426 for(int yi=0; yi<img->dimy; yi++)
427 for(int xi=0; xi<img->dimx; xi++)
428 img->m[zi][yi][xi][frame_index]=*fptr++;
429 free(fdata);
430
431 /* Set decay correction factor to zero */
432 img->decayCorrFactor[frame_index]=0.0;
433
434 /* Set plane numbers */
435 for(int fi=0; fi<img->dimz; fi++) img->planeNumber[fi]=fi+1;
436
437 /*
438 * Try to read frame time information from SIF file
439 */
440 imgSetStatus(img, STATUS_OK); /* If the rest is failed, no problem */
441 sifInit(&sif);
442 if(sifRead(siffile, &sif)!=0) {
443 if(verbose>1) {fprintf(stdout, " cannot read SIF (%s)\n", siffile); fflush(stdout);}
444 return STATUS_OK;
445 }
446 /* Frame information */
447 if(verbose>3) {fprintf(stdout, " setting frame times\n"); fflush(stdout);}
448 if(sif.frameNr>=frame_to_read) {
449 img->start[frame_index]=sif.x1[frame_to_read-1];
450 img->end[frame_index]=sif.x2[frame_to_read-1];
451 img->mid[frame_index]=0.5*(img->start[frame_index]+img->end[frame_index]);
452 img->prompts[frame_index]=sif.prompts[frame_to_read-1];
453 img->randoms[frame_index]=sif.randoms[frame_to_read-1];
454 }
455 sifEmpty(&sif);
456
457 imgSetStatus(img, STATUS_OK);
458 return STATUS_OK;
459}
void niftiRemoveFNameExtension(char *fname)
Definition nifti.c:23
void sifInit(SIF *data)
Definition sif.c:17
int niftiReadImagedata(FILE *fp, NIFTI_DSR *h, int frame, float *data, int verbose, char *status)
Definition nifti.c:619
int niftiExists(const char *dbname, char *hdrfile, char *imgile, char *siffile, NIFTI_DSR *header, int verbose, char *status)
Definition nifti.c:160
void sifEmpty(SIF *data)
Definition sif.c:33
int sifRead(char *filename, SIF *data)
Definition sifio.c:21
float **** m
float * prompts
int * planeNumber
float * start
float * end
float * decayCorrFactor
float * randoms
float * mid
double * x1
double * prompts
int frameNr
double * x2
double * randoms

Referenced by imgNiftiToEcat(), imgReadFrame(), imgReadNifti(), and imgReadNiftiFirstFrame().

◆ imgReadNiftiHeader()

int imgReadNiftiHeader ( const char * filename,
IMG * img,
int verbose )

Fill IMG struct header information from Nifti database files.

Nifti database name must be given with path. Either one file with extension .nii, or image and header files with extensions .img and .hdr must exist. Also SIF file with .sif extension is used, if it exists; however, information concerning separate frames or planes is not filled.

Returns
0 if ok, and otherwise IMG status code (<>0); sets IMG->statmsg in case of an error.
See also
imgGetNiftiHeader
Parameters
filenameNifti database name with path, with or without extension
imgPointer to initialized IMG structure
verboseVerbose level; if zero, then nothing is printed to stderr or stdout

Definition at line 134 of file img_nii.c.

141 {
142 char basefile[FILENAME_MAX], tmp[256];
143 char datfile[FILENAME_MAX], hdrfile[FILENAME_MAX], siffile[FILENAME_MAX];
144 NIFTI_DSR dsr;
145 int ret;
146 SIF sif;
147 double f;
148
149 if(verbose>0) {printf("imgReadNiftiHeader(%s, ...)\n", filename); fflush(stdout);}
150
151 /* Check the arguments */
152 if(img==NULL || img->status!=IMG_STATUS_INITIALIZED) {
153 if(img!=NULL) imgSetStatus(img, STATUS_FAULT);
154 if(verbose>0) fprintf(stderr, "Error: invalid IMG argument\n");
155 return(STATUS_FAULT);
156 }
157 if(filename==NULL || !filename[0]) {
158 imgSetStatus(img, STATUS_FAULT);
159 if(verbose>0) fprintf(stderr, "Error: invalid filename\n");
160 return(STATUS_FAULT);
161 }
162 imgSetStatus(img, STATUS_OK);
163
164 /* Extract the base file name without extensions */
165 strcpy(basefile, filename); niftiRemoveFNameExtension(basefile);
166 if(strlen(basefile)<1) {
167 imgSetStatus(img, STATUS_FAULT);
168 if(verbose>0) fprintf(stderr, "Error: invalid filename\n");
169 return(STATUS_FAULT);
170 }
171
172 /* Make the image and header filenames, and read Nifti header */
173 ret=niftiExists(basefile, hdrfile, datfile, siffile, &dsr, verbose-2, tmp);
174 if(ret==0) {
175 imgSetStatus(img, STATUS_NOFILE);
176 if(verbose>0) fprintf(stderr, "Error: %s\n", tmp);
177 return(STATUS_NOFILE);
178 }
179 if(ret==1 && verbose>1) printf("no SIF found for %s\n", basefile);
180
181 /* and set IMG contents */
182 ret=imgGetNiftiHeader(img, &dsr, verbose-2);
183 if(ret!=0) {
184 imgSetStatus(img, ret);
185 return(ret);
186 }
187
188 /* If SIF does not exist, then that's it */
189 if(!siffile[0]) {
190 imgSetStatus(img, STATUS_OK);
191 return STATUS_OK;
192 }
193
194 /* SIF is available, so read that too */
195 if(verbose>1) {printf("reading SIF %s\n", siffile); fflush(stdout);}
196 sifInit(&sif); ret=0;
197 if(sifRead(siffile, &sif)!=0) return STATUS_OK;
198 /* Copy scan time */
199 img->scanStart=sif.scantime;
200 /* Study number, if not yet defined */
201 if(!img->studyNr[0] && strlen(sif.studynr)>1 )
203 /* Isotope half-life, if not yet defined */
205 if(img->isotopeHalflife<=0.0 && f>0.0) img->isotopeHalflife=60.0*f;
206 sifEmpty(&sif);
207
208 return(STATUS_OK);
209}
double hlFromIsotope(char *isocode)
Definition halflife.c:55
int imgGetNiftiHeader(IMG *img, NIFTI_DSR *dsr, int verbose)
Definition img_nii.c:218
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition strext.c:245
#define MAX_STUDYNR_LEN
Definition libtpcmisc.h:163
time_t scanStart
float isotopeHalflife
char studynr[MAX_STUDYNR_LEN+1]
time_t scantime
char isotope_name[8]

Referenced by imgReadHeader(), imgReadNifti(), and imgReadNiftiFirstFrame().

◆ imgSetNiftiHeader()

int imgSetNiftiHeader ( IMG * img,
const char * dbname,
NIFTI_DSR * dsr,
float fmin,
float fmax,
int verbose )

Copy header information in IMG structure into NIfTI header structure.

Min, max, and scale factor are set here and they apply to all frames.

Returns
errstatus, which is STATUS_OK (0) when call was successful, and >0 in case of an error.
See also
imgGetNiftiHeader, imgReadNiftiHeader
Parameters
imgpointer to IMG structure from which header information is read
dbnameNIfTI database name
dsrpointer to NIfTI header struct to be filled
fminminimum pixel value in all frames that will be written
fmaxmaximum pixel value in all frames that will be written
verboseVerbose level; if zero, then nothing is printed to stderr or stdout

Definition at line 471 of file img_nii.c.

484 {
485 if(verbose>0) {
486 printf("\nimgSetNiftiHeader(*img, %s, *dsr, %g, %g, ...)\n", dbname, fmin, fmax);
487 fflush(stdout);
488 }
489 /* Check the input */
490 if(dbname==NULL || !dbname[0]) {
491 if(verbose>0) fprintf(stderr, "Error: invalid filename\n");
492 return(STATUS_FAULT);
493 }
494 if(img==NULL || (img->status!=IMG_STATUS_INITIALIZED && img->status!=IMG_STATUS_OCCUPIED)) {
495 if(verbose>0) fprintf(stderr, "Error: invalid IMG argument\n");
496 return(STATUS_FAULT);
497 }
498 if(dsr==NULL) {
499 if(verbose>0) fprintf(stderr, "Error: invalid header struct\n");
500 return STATUS_FAULT;
501 }
502
503 /* Set NIfTI byte order to current machines byte order */
505
506 /* Initiate header struct with zeroes */
507 memset(&dsr->h, 0, sizeof(NIFTI_1_HEADER));
508 memset(&dsr->e, 0, sizeof(NIFTI_EXTENDER));
509
510 /* Set header */
512 strcpy(dsr->h.data_type, "");
513 char *cptr=strrchr(dbname, '/'); if(cptr==NULL) cptr=strrchr(dbname, '\\');
514 if(cptr!=NULL) cptr++;
515 if(cptr==NULL) cptr=(char*)dbname;
516 strncpy(dsr->h.db_name, cptr, 17);
517 dsr->h.extents=16384; // not used in NIfTI, but required for Analyze compatibility
518 dsr->h.regular='r'; // not used in NIfTI, but required for Analyze compatibility
519 dsr->h.dim_info='\0'; // MRI slice ordering
520
521 /* Image dimension */
522 for(int i=0; i<8; i++) dsr->h.dim[i]=1;
523 dsr->h.dim[0]=4;
524 dsr->h.dim[1]=img->dimx;
525 dsr->h.dim[2]=img->dimy;
526 dsr->h.dim[3]=img->dimz;
527 dsr->h.dim[4]=img->dimt;
528 dsr->h.intent_p1=0.0;
529 dsr->h.intent_p2=0.0;
530 dsr->h.intent_p3=0.0;
532 dsr->h.datatype=NIFTI_DT_FLOAT; // data as floats, so no need to scale
533 dsr->h.bitpix=32;
534 dsr->h.slice_start=0;
535 for(int i=0; i<8; i++) dsr->h.pixdim[i]=0.0;
536 // https://nifti.nimh.nih.gov/nifti-1/documentation/nifti1fields/nifti1fields_pages/qsform.html
537 dsr->h.pixdim[0]=1.0; // Set to either 1.0 or -1.0
538 dsr->h.pixdim[1]=img->sizex;
539 dsr->h.pixdim[2]=img->sizey;
540 dsr->h.pixdim[3]=img->sizez;
541 if(img->_fileFormat==IMG_NIFTI_1D)
542 dsr->h.vox_offset=0;
543 else
544 dsr->h.vox_offset=352;
545 dsr->h.scl_slope=1.0; // data as floats, so no need to scale
546 dsr->h.scl_inter=0.0; // data as floats, so no need to scale
547 dsr->h.slice_end=0;
548 dsr->h.slice_code=0;
550 dsr->h.cal_max=fmax;
551 dsr->h.cal_min=0.0; // scale display colours to have black at zero
552 dsr->h.slice_duration=0.0;
553 dsr->h.toffset=0.0;
554 dsr->h.glmax=fmax; // unused in NIfTI
555 dsr->h.glmin=fmin; // unused in NIfTI
556
557 strlcpy(dsr->h.descrip, img->studyNr, 80);
558 strcpy(dsr->h.aux_file, "");
559
560 dsr->h.qform_code=img->xform[0];
561 dsr->h.sform_code=img->xform[1];
562 dsr->h.quatern_b=img->quatern[0];
563 dsr->h.quatern_c=img->quatern[1];
564 dsr->h.quatern_d=img->quatern[2];
565 dsr->h.qoffset_x=img->quatern[3];
566 dsr->h.qoffset_y=img->quatern[4];
567 dsr->h.qoffset_z=img->quatern[5];
568 for(int i=0; i<4; i++) dsr->h.srow_x[i]=img->quatern[6+i];
569 for(int i=0; i<4; i++) dsr->h.srow_y[i]=img->quatern[10+i];
570 for(int i=0; i<4; i++) dsr->h.srow_z[i]=img->quatern[14+i];
571 strcpy(dsr->h.intent_name, "");
572
573 if(img->_fileFormat==IMG_NIFTI_1D) strcpy(dsr->h.magic, "ni1");
574 else strcpy(dsr->h.magic, "n+1");
575
576 /* Extension is left as 0 0 0 0 */
577
578 return STATUS_OK;
579}
#define NIFTI_DT_FLOAT
#define NIFTI_HEADER_SIZE
#define NIFTI_INTENT_NONE
#define NIFTI_UNITS_SEC
int little_endian()
Definition swap.c:14
short int slice_start
short int slice_end
short int datatype
char aux_file[24]
char intent_name[16]
short int bitpix
char data_type[10]
short int intent_code
NIFTI_EXTENDER e

Referenced by imgWriteNiftiFrame().

◆ imgWriteNifti()

int imgWriteNifti ( const char * dbname,
IMG * img,
int save_sif,
int verbose )

Write NIfTI-1 image.

Nifti database name can be given with path, however, path is not created in here. IMG field _fileFormat determines whether NIfTI is written in single file format (*.nii) or dual file format (*.hdr and *.img). Optionally SIF file with .sif extension is saved to store frame times.

Returns
0 if ok, and otherwise IMG status code (<>0); sets IMG->statmsg in case of an error.
See also
imgInit, imgReadNiftiFirstFrame, imgReadNiftiHeader, imgReadNifti
Parameters
dbnameNifti database name with path, with or without extension
imgPointer to IMG structure containing the image data to be written
save_sifSave (1) or do not save (0) SIF
verboseVerbose level; if zero, then nothing is printed to stderr or stdout

Definition at line 811 of file img_nii.c.

820 {
821 int ret;
822 char imgfile[FILENAME_MAX], hdrfile[FILENAME_MAX], siffile[FILENAME_MAX];
823 float fmin, fmax;
824 SIF sif;
825
826 if(verbose>0) {
827 printf("imgWriteNifti(%s, *img, %d, ...)\n", dbname, save_sif);
828 fflush(stdout);
829 }
830
831 /*
832 * Check the input
833 */
834 if(dbname==NULL || !dbname[0]) {
835 imgSetStatus(img, STATUS_FAULT);
836 if(verbose>0) fprintf(stderr, "Error: invalid filename\n");
837 return(STATUS_FAULT);
838 }
839 if(img==NULL || img->status!=IMG_STATUS_OCCUPIED) {
840 if(img!=NULL) imgSetStatus(img, STATUS_FAULT);
841 if(verbose>0) fprintf(stderr, "Error: invalid IMG argument\n");
842 return(STATUS_FAULT);
843 }
845 imgSetStatus(img, STATUS_FAULT);
846 if(verbose>0) fprintf(stderr, "Error: invalid file format setting\n");
847 return STATUS_FAULT;
848 }
849
850 /* Create the NIfTI filename(s) */
851 ret=niftiCreateFNames(dbname, hdrfile, imgfile, siffile, img->_fileFormat);
852 if(ret!=0) {
853 if(verbose>0) fprintf(stderr, " Error: invalid NIfTI name %s\n", dbname);
854 imgSetStatus(img, STATUS_FAULT);
855 return STATUS_FAULT;
856 }
857 /* Delete previous NIfTI */
858 ret=niftiRemove(dbname, 0, verbose-1);
859 if(ret!=0) {
860 if(verbose>0) fprintf(stderr, " Error: cannot delete previous NIfTI.\n");
861 imgSetStatus(img, STATUS_CANNOTERASE);
862 return STATUS_CANNOTERASE;
863 }
864
865 /*
866 * Get the global min and max pixel values;
867 * those are currently only saved in header, but may be later
868 * needed for scaling pixels to short ints
869 */
870 if(verbose>1) {fprintf(stdout, " searching min and max\n"); fflush(stdout);}
871 ret=imgMinMax(img, &fmin, &fmax);
872 if(ret) {
873 if(verbose>0) fprintf(stderr, " Error: %s\n", imgStatus(ret));
874 imgSetStatus(img, STATUS_NOIMGDATA);
875 return STATUS_NOIMGDATA;
876 }
877 if(verbose>1) {
878 printf(" global_min := %g\n global_max := %g\n", fmin, fmax);
879 fflush(stdout);
880 }
881 /*
882 * Write the image frames
883 */
884 for(int fi=0, ret=0; fi<img->dimt; fi++) {
885 ret=imgWriteNiftiFrame(dbname, fi+1, img, fi, fmin, fmax, verbose-2);
886 if(ret!=STATUS_OK) break;
887 if(verbose>4) {printf(" frame written.\n"); fflush(stdout);}
888 } // next frame
889 //printf("ret := %d\n", ret);
890 if(ret!=STATUS_OK) {
891 niftiRemove(dbname, img->_fileFormat, verbose-3);
892 if(verbose>0) fprintf(stderr, "Error: %s.\n", imgStatus(ret));
893 return ret;
894 }
895
896 /* If SIF is not needed, then that's it */
897 if(save_sif==0) {
898 imgSetStatus(img, STATUS_OK);
899 return 0;
900 }
901
902 /* Copy contents from IMG to SIF and save SIF */
903 sifInit(&sif);
904 /* Try to read existing SIF */
905 ret=sifRead(siffile, &sif);
906 if(ret==0) { // SIF could be read
907 if(sif.frameNr==img->dimt) {
908 /* If size matches, then update the contents, but keep counts, in case
909 previous SIF comes with actual count info from scanner */
910 ret=img2sif(img, &sif, 1, 1, 0, verbose-3);
911 } else {
912 /* otherwise create SIF contents */
913 ret=img2sif(img, &sif, 1, 1, 2, verbose-3);
914 }
915 } else {
916 /* otherwise create SIF contents */
917 ret=img2sif(img, &sif, 1, 1, 2, verbose-3);
918 }
919 if(ret!=0) {
920 if(verbose>0) fprintf(stderr, " Error: cannot create SIF contents.\n");
921 imgSetStatus(img, STATUS_CANNOTWRITE);
922 sifEmpty(&sif);
923 return STATUS_CANNOTWRITE;
924 }
925 /* Write SIF */
926 ret=sifWrite(&sif, siffile);
927 if(ret!=0) {
928 if(verbose>0) fprintf(stderr, " Error: cannot write %s\n", siffile);
929 imgSetStatus(img, STATUS_CANNOTWRITE);
930 sifEmpty(&sif);
931 return STATUS_CANNOTWRITE;
932 }
933 sifEmpty(&sif);
934
935 imgSetStatus(img, STATUS_OK);
936 return 0;
937}
char * imgStatus(int status_index)
Definition img.c:330
int imgWriteNiftiFrame(const char *dbname, int frame_to_write, IMG *img, int frame_index, float fmin, float fmax, int verbose)
Definition img_nii.c:594
int img2sif(IMG *img, SIF *sif, int copy_header, int copy_frames, int copy_counts, int verbose)
Definition img_sif.c:71
int imgMinMax(IMG *img, float *minvalue, float *maxvalue)
Definition imgminmax.c:154
int sifWrite(SIF *data, char *filename)
Definition sifio.c:145
int niftiCreateFNames(const char *filename, char *hdrfile, char *imgfile, char *siffile, int fileformat)
Definition nifti.c:44
int niftiRemove(const char *dbname, int fileformat, int verbose)
Definition nifti.c:100

Referenced by imgWrite().

◆ imgWriteNiftiFrame()

int imgWriteNiftiFrame ( const char * dbname,
int frame_to_write,
IMG * img,
int frame_index,
float fmin,
float fmax,
int verbose )

Write one PET frame from IMG data struct into NIfTI file.

This function can be called repeatedly to write all frames one at a time to conserve memory. This function does not write SIF. Single or dual file format is determined based on _fileFormat field in IMG struct. Byte order is the not changed.

Returns
Returns errstatus, which is STATUS_OK (0) when call was successful, and >0 in case of an error.
See also
imgReadNiftiFrame
Parameters
dbnameName of NIfTI file where IMG contents will be written. If file does not exist, it is created. Make sure to delete existing file, unless you want to add data.
frame_to_writePET frame number (1..frameNr) which will be written: If set to 0, frame data will be written to an existing or new PET file as a new additional frame, never overwriting existing data. If >0, then frame data is written as specified frame number, overwriting any data existing with the same frame number
imgpointer to the IMG data struct.
frame_indexIMG frame index (0..dimt-1) which will be written.
fminminimum pixel value in all frames that will be written; used only when writing the first frame.
fmaxmaximum pixel value in all frames that will be written; used only when writing the first frame.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout

Definition at line 594 of file img_nii.c.

617 {
618 IMG test_img;
619 NIFTI_DSR dsr;
620 int ret=0, fileis=0;
621 char imgfile[FILENAME_MAX], hdrfile[FILENAME_MAX], siffile[FILENAME_MAX];
622 char tmp[256];
623 FILE *fp;
624 float *fdata=NULL, *fptr;
625
626
627 if(verbose>0) {
628 printf("\nimgWriteNiftiFrame(%s, %d, *img, %d, %g, %g, ...)\n",
629 dbname, frame_to_write, frame_index, fmin, fmax);
630 fflush(stdout);
631 }
632 /*
633 * Check the input
634 */
635 if(dbname==NULL || !dbname[0]) {
636 imgSetStatus(img, STATUS_FAULT);
637 if(verbose>0) fprintf(stderr, "Error: invalid filename\n");
638 return(STATUS_FAULT);
639 }
640 if(img==NULL || img->status!=IMG_STATUS_OCCUPIED) {
641 if(img!=NULL) imgSetStatus(img, STATUS_FAULT);
642 if(verbose>0) fprintf(stderr, "Error: invalid IMG argument\n");
643 return(STATUS_FAULT);
644 }
645 if(frame_index<0 || frame_index>img->dimt-1 || frame_to_write<0) {
646 imgSetStatus(img, STATUS_FAULT);
647 if(verbose>0) fprintf(stderr, "Error: invalid frame settings\n");
648 return STATUS_FAULT;
649 }
651 imgSetStatus(img, STATUS_FAULT);
652 if(verbose>0) fprintf(stderr, "Error: invalid file format setting\n");
653 return STATUS_FAULT;
654 }
655
656 /*
657 * If NIfTI does not exist, then create it with new header,
658 * and if it does exist, then read and check header information.
659 * Create or edit header to contain correct frame nr.
660 * Determine the global scaling factors.
661 */
662 imgInit(&test_img);
663 fileis=niftiExists(dbname, hdrfile, imgfile, siffile, &dsr, verbose-2, NULL);
664 if(fileis==0) { // not existing
665 if(verbose>1) {
666 printf(" writing 1st frame to a new file\n"); fflush(stdout);}
667
668 /* Create database filenames */
669 niftiCreateFNames(dbname, hdrfile, imgfile, siffile, img->_fileFormat);
670
671 /* Set main header */
672 ret=imgSetNiftiHeader(img, dbname, &dsr, fmin, fmax, verbose-1);
673 if(ret!=0) {
674 if(verbose>0) fprintf(stderr, "Error: cannot read NIfTI header\n");
675 return STATUS_INVALIDHEADER;
676 }
677 if(frame_to_write==0) frame_to_write=1;
678 dsr.h.dim[4]=1;
679
680 /* Write NIfTI header */
681 ret=niftiWriteHeader(hdrfile, &dsr, verbose-1, tmp);
682 if(ret!=0) {
683 if(verbose>0) fprintf(stderr, "Error in niftiWriteHeader(): %s\n", tmp);
684 return STATUS_CANTWRITEHEADERFILE;
685 }
686
687 /* Remove dual format datafile if necessary */
688 if(img->_fileFormat==IMG_NIFTI_1D)
689 if(access(imgfile, 0) != -1) {
690 if(verbose>0) printf(" removing %s\n", imgfile);
691 remove(imgfile);
692 }
693
694 } else { /* NIfTI exists */
695 if(verbose>1) printf(" adding frame to an existing file\n");
696
697 /* Read header information for checking */
698 ret=imgGetNiftiHeader(&test_img, &dsr, verbose-1);
699 if(ret!=0) {
700 if(verbose>0) fprintf(stderr, "Error: cannot read NIfTI header\n");
701 imgEmpty(&test_img); return ret;
702 }
703 /* Check that file format is the same */
704 if(img->_fileFormat!=test_img._fileFormat) {
705 if(verbose>0) {
706 fprintf(stderr, "Error: different file format\n");
707 printf(" new._fileFormat:=%d\n", img->_fileFormat);
708 printf(" prev._fileFormat:=%d\n", test_img._fileFormat);
709 }
710 imgEmpty(&test_img); return STATUS_WRONGFILETYPE;
711 }
712 /* Check also data type, if available */
713 if(img->_dataType>0 && test_img._dataType>0 &&
714 img->_dataType!=test_img._dataType)
715 {
716 if(verbose>0) {
717 fprintf(stderr, "Error: different datatype\n");
718 printf(" new._dataType:=%d\n", img->_dataType);
719 printf(" prev._dataType:=%d\n", test_img._dataType);
720 }
721 imgEmpty(&test_img); return STATUS_WRONGFILETYPE;
722 }
723 /* Check that matrix sizes are the same */
724 if(img->dimz!=test_img.dimz || img->dimx!=test_img.dimx ||
725 img->dimy!=test_img.dimy) {
726 if(verbose>0) fprintf(stderr, "Error: different matrix size\n");
727 imgEmpty(&test_img); return STATUS_VARMATSIZE;}
728 imgEmpty(&test_img);
729
730 /* Set new frame number in NIfTI header */
731 if(frame_to_write==0) frame_to_write=dsr.h.dim[4]+1;
732 if(dsr.h.dim[4]<frame_to_write) {
733 if(dsr.h.dim[4]+1<frame_to_write) {
734 if(verbose>0) fprintf(stderr, "Error: missing matrix\n");
735 return STATUS_MISSINGMATRIX;
736 }
737 dsr.h.dim[4]=frame_to_write;
738 }
739 /* and save the updated header */
740 if((ret=niftiWriteHeader(hdrfile, &dsr, verbose-1, tmp))!=0) {
741 if(verbose>0) fprintf(stderr, "Error: %s.\n", tmp);
742 return STATUS_NOWRITEPERM;
743 }
744 }
745 if(verbose>2) {
746 printf("frame_to_write := %d\n", frame_to_write);
747 printf("vox_offset := %d\n", (int)dsr.h.vox_offset);
748 printf("hdrfile := %s\n", hdrfile);
749 printf("imgfile := %s\n", imgfile);
750 printf("siffile := %s\n", siffile);
751 printf("magic := %s\n", dsr.h.magic);
752 }
753
754 /* Open voxel data file, not removing possible old contents like header */
755 if(img->_fileFormat==IMG_NIFTI_1D && frame_to_write==1)
756 fp=fopen(imgfile, "wb");
757 else
758 fp=fopen(imgfile, "r+b");
759 if(fp==NULL) {
760 if(verbose>0) fprintf(stderr, "Error: cannot open %s for write.\n",imgfile);
761 return STATUS_CANTWRITEIMGFILE;
762 }
763
764 /* Move file pointer to the place of current frame */
765 long long voxNr=img->dimz*img->dimy*img->dimx;
766 if(fseeko(fp, (int)dsr.h.vox_offset+(frame_to_write-1)*voxNr*sizeof(float),
767 SEEK_SET)!=0)
768 {
769 if(verbose>0) fprintf(stderr, "Error: invalid file write position.\n");
770 fclose(fp); return STATUS_MISSINGMATRIX;
771 }
772
773 /* Allocate memory for matrix float data (one plane) */
774 fdata=(float*)calloc(voxNr, sizeof(float));
775 if(fdata==NULL) {
776 if(verbose>0) fprintf(stderr, "Error: out of memory.\n");
777 fclose(fp); return STATUS_NOMEMORY;
778 }
779
780 /* Write voxel values as floats */
781 fptr=fdata;
782 for(int zi=0; zi<img->dimz; zi++)
783 for(int yi=0; yi<img->dimy; yi++)
784 for(int xi=0; xi<img->dimx; xi++, fptr++)
785 *fptr=img->m[zi][yi][xi][frame_index];
786 fptr=fdata;
787 if(fwrite(fptr, sizeof(float), voxNr, fp) != (unsigned int)voxNr) {
788 if(verbose>0) fprintf(stderr, "Error: disk full or no write permission.\n");
789 free(fdata); fclose(fp); return STATUS_CANTWRITEIMGFILE;
790 }
791 free(fdata);
792 fclose(fp);
793
794 return STATUS_OK;
795}
void imgEmpty(IMG *image)
Definition img.c:121
void imgInit(IMG *image)
Definition img.c:60
int imgSetNiftiHeader(IMG *img, const char *dbname, NIFTI_DSR *dsr, float fmin, float fmax, int verbose)
Definition img_nii.c:471
int niftiWriteHeader(char *filename, NIFTI_DSR *dsr, int verbose, char *status)
Definition nifti.c:844
int _dataType

Referenced by imgWriteFrame(), and imgWriteNifti().