TPCCLIB
Loading...
Searching...
No Matches
imagenii.c
Go to the documentation of this file.
1
6/*****************************************************************************/
7#include "tpcclibConfig.h"
8/*****************************************************************************/
9#include "tpcimage.h"
10/*****************************************************************************/
11
12/*****************************************************************************/
20 const char *filename,
24 char *hdrfile,
28 char *imgfile,
31 char *siffile,
34 int fileformat
35) {
36 if(hdrfile!=NULL) strcpy(hdrfile, "");
37 if(imgfile!=NULL) strcpy(imgfile, "");
38 if(siffile!=NULL) strcpy(siffile, "");
39 if(filename==NULL) return(TPCERROR_INVALID_FILENAME);
40
41 char basename[FILENAME_MAX];
42 strlcpy(basename, filename, FILENAME_MAX); niftiBasename(basename);
43 /* Check that there is something left after path */
44 char basenamewopath[FILENAME_MAX];
45 strcpy(basenamewopath, basename); filenameRmPath(basenamewopath);
46 if(strlen(basenamewopath)<1) return(TPCERROR_INVALID_FILENAME);
47
48 /* Create database filenames */
49 if(fileformat==IMG_FORMAT_NIFTI_1D || fileformat==IMG_FORMAT_NIFTI_2D) {
50 if(hdrfile!=NULL) snprintf(hdrfile, FILENAME_MAX, "%s.hdr", basename);
51 if(imgfile!=NULL) snprintf(imgfile, FILENAME_MAX, "%s.img", basename);
52 } else if(fileformat==IMG_FORMAT_NIFTI_1S || fileformat==IMG_FORMAT_NIFTI_2S) {
53 if(hdrfile!=NULL) snprintf(hdrfile, FILENAME_MAX, "%s.nii", basename);
54 if(imgfile!=NULL) snprintf(imgfile, FILENAME_MAX, "%s.nii", basename);
55 } else {
57 }
58 if(siffile!=NULL) snprintf(siffile, FILENAME_MAX, "%s.sif", basename);
59
60 return(TPCERROR_OK);
61}
62/*****************************************************************************/
63
64/*****************************************************************************/
74 IMG *img,
76 const char *fname,
78 TPCSTATUS *status
79) {
80 int verbose=0; if(status!=NULL) verbose=status->verbose;
81 if(verbose>0) {printf("%s(..., %s, ...)\n", __func__, fname); fflush(stdout);}
82
83 if(img==NULL || strnlen(fname, 2)<1) {
84 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_FAIL);
85 return(TPCERROR_FAIL);
86 }
87 /* Delete any old contents in data structure */
88 imgFree(img);
89
90 /* Get NIfTI filenames, check existence, and read header */
91 if(verbose>1) printf("checking that %s exists and is NIfTI\n", fname);
92 char hdrfile[FILENAME_MAX], imgfile[FILENAME_MAX], siffile[FILENAME_MAX];
93 NIFTI_DSR dsr;
94 if(!niftiExists(fname, hdrfile, imgfile, siffile, &dsr, status)) {
95 if(status!=NULL) return(status->error);
96 else return(TPCERROR_FAIL);
97 }
98 if(verbose>1) printf("NIfTI header read from %s\n", hdrfile);
99
100 /* Get data type and check that it is currently supported */
101 if(verbose>2) printf(" verifying datatype\n");
102 int datatype=0;
103 if(dsr.n==1) datatype=dsr.h1.datatype; else datatype=dsr.h2.datatype;
104 switch(datatype) {
108 case NIFTI_DT_FLOAT:
109 case NIFTI_DT_DOUBLE:
115 break;
116 case NIFTI_DT_UNKNOWN:
117 case NIFTI_DT_BINARY:
118 case NIFTI_DT_COMPLEX:
119 case NIFTI_DT_RGB:
120 case NIFTI_DT_ALL:
124 case NIFTI_DT_RGBA:
125 default:
126 if(verbose>0) printf("Error: currently unsupported NIfTI datatype %d\n", datatype);
127 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_UNSUPPORTED);
128 return(TPCERROR_UNSUPPORTED);
129 }
130 int bitpix=0;
131 if(dsr.n==1) bitpix=dsr.h1.bitpix; else bitpix=dsr.h2.bitpix;
132 if(verbose>2) printf(" bits per pixel := %d\n", bitpix);
133 if(bitpix==0) { // Carimas Nifti Writer does not set bitpix
134 if(datatype==NIFTI_DT_UNSIGNED_SHORT) bitpix=16;
135 }
136 if(bitpix<8 || (bitpix%8)!=0) { // We don't support bit data
137 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_UNSUPPORTED);
138 return(TPCERROR_UNSUPPORTED);
139 }
140 if(bitpix>64) { // We don't currently support 128 bit data or larger
141 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_UNSUPPORTED);
142 return(TPCERROR_UNSUPPORTED);
143 }
144 int bytepix=bitpix/8; if(verbose>2) printf(" bytes per pixel := %d\n", bytepix);
145
146
147 /* Allocate memory for 4D image */
148 {
149 int ret=imgGetNiftiHeader(img, &dsr, verbose-1); // Get the image dimensions
150 if(ret!=TPCERROR_OK) {
151 statusSet(status, __func__, __FILE__, __LINE__, ret);
152 return(ret);
153 }
154 if(verbose>1) printf("allocating memory for 4D image\n");
155 ret=imgAllocate(img, img->dimz, img->dimy, img->dimx, img->dimt, status);
156 if(ret) return(ret);
157 }
158
159 /* Copy header contents into IMG structure */
160 {
161 int ret=imgGetNiftiHeader(img, &dsr, verbose-1);
162 if(ret!=TPCERROR_OK) {
163 statusSet(status, __func__, __FILE__, __LINE__, ret);
164 return(ret);
165 }
166 if(verbose>2) printf("format: %s\n", imgFormatDescr(img->format));
167 }
168
169 /* Open file */
170 if(verbose>1) printf("reading pixel data in %s\n", imgfile);
171 FILE *fp=fopen(imgfile, "rb");
172 if(fp==NULL) {
173 imgFree(img);
174 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_OPEN);
175 return(TPCERROR_CANNOT_OPEN);
176 }
177
178
179 /* Set initial read position.
180 Get the image data start location from header, in case of single file format */
181 long long start_pos=0;
182 {
183 long long int s=0;
184 if(dsr.n==1) s=(int)dsr.h1.vox_offset; else s=(int)dsr.h2.vox_offset;
185 if(s<0) start_pos=-s; else start_pos=s;
186 /* Check that start location is not earlier than it can by definition; it can be later, though */
189 start_pos=s;
190 }
191 if(verbose>2) printf(" image_start_pos := %llu\n", start_pos);
192 /* Seek the data position, jumping over possible header */
193 if(start_pos>0) {
194 fseeko(fp, start_pos, SEEK_SET);
195 if(ftello(fp)!=start_pos) {
196 fclose(fp); imgFree(img);
197 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_FORMAT);
199 }
200 }
201
202 /* Allocate memory for one frame of the binary data */
203 long long pxlNr=img->dimx*img->dimy*img->dimz;
204 if(verbose>2) printf(" pixels/frame := %llu\n", pxlNr);
205 long long rawSize=pxlNr*(bitpix/8);
206 if(verbose>1) printf(" raw bytes per frame := %lld\n", rawSize);
207 if(verbose>1) printf(" allocating memory for raw binary data\n");
208 unsigned char *buf=(unsigned char*)malloc(rawSize);
209 if(buf==NULL) {
210 fclose(fp); imgFree(img);
211 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OUT_OF_MEMORY);
213 }
214
215 /* Read the data, frame-by-frame */
216 if(verbose>1) printf(" reading binary data\n");
217 int little=endianLittle(); // Are we on little endian platform?
218 int byteconv=0;
219 if(little!=dsr.byte_order) {
220 byteconv=1;
221 if(verbose>1) printf(" byte conversion needed\n");
222 }
223 /* Get scaling factors */
224 float scl_slope, scl_inter;
225 if(dsr.n==1) {scl_slope=dsr.h1.scl_slope; scl_inter=dsr.h1.scl_inter;}
226 else {scl_slope=dsr.h2.scl_slope; scl_inter=dsr.h2.scl_inter;}
227 if(scl_slope==0.0) scl_slope=1.0;
228
229 for(int ti=0; ti<img->dimt; ti++) {
230 if(verbose>3) printf(" frame %d\n", 1+ti);
231 if(fread(buf, rawSize, 1, fp) < 1) {
232 fclose(fp); imgFree(img); free(buf);
233 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_READ);
234 return(TPCERROR_CANNOT_READ);
235 }
236 /* Convert byte order if necessary */
237 if(byteconv) switch(bitpix) {
238 case 8: /* no conversion needed */ break;
239 case 16: swap16ip(buf, pxlNr); break;
240 case 32: swap32ip(buf, pxlNr); break;
241 case 64: swap64ip(buf, pxlNr); break;
242 default: /* others not supported */ break;
243 }
244 /* Copy data to float pixel values */
245 int ret=0;
246 unsigned char *bptr=buf;
247 switch(datatype) {
250 if(bitpix!=8) {ret=1; break;}
251 for(int zi=0; zi<img->dimz; zi++)
252 for(int yi=0; yi<img->dimy; yi++)
253 for(int xi=0; xi<img->dimx; xi++) {
254 img->m[zi][yi][xi][ti]=scl_inter+scl_slope*(float)(*bptr);
255 bptr++;
256 }
257 break;
259 if(bitpix!=16) {ret=1; break;}
260 for(int zi=0; zi<img->dimz; zi++)
261 for(int yi=0; yi<img->dimy; yi++)
262 for(int xi=0; xi<img->dimx; xi++) {
263 uint16_t a;
264 memcpy(&a, bptr, 2);
265 img->m[zi][yi][xi][ti]=scl_inter+scl_slope*(float)a;
266 bptr+=bytepix;
267 }
268 break;
270 if(bitpix!=16) {ret=1; break;}
271 for(int zi=0; zi<img->dimz; zi++)
272 for(int yi=0; yi<img->dimy; yi++)
273 for(int xi=0; xi<img->dimx; xi++) {
274 int16_t a;
275 memcpy(&a, bptr, 2);
276 img->m[zi][yi][xi][ti]=scl_inter+scl_slope*(float)a;
277 bptr+=bytepix;
278 }
279 break;
281 if(bitpix!=32) {ret=1; break;}
282 for(int zi=0; zi<img->dimz; zi++)
283 for(int yi=0; yi<img->dimy; yi++)
284 for(int xi=0; xi<img->dimx; xi++) {
285 int32_t a;
286 memcpy(&a, bptr, 4);
287 img->m[zi][yi][xi][ti]=scl_inter+scl_slope*(float)a;
288 bptr+=bytepix;
289 }
290 break;
292 if(bitpix!=32) {ret=1; break;}
293 for(int zi=0; zi<img->dimz; zi++)
294 for(int yi=0; yi<img->dimy; yi++)
295 for(int xi=0; xi<img->dimx; xi++) {
296 uint32_t a;
297 memcpy(&a, bptr, 4);
298 img->m[zi][yi][xi][ti]=scl_inter+scl_slope*(float)a;
299 bptr+=bytepix;
300 }
301 break;
303 if(bitpix!=64) {ret=1; break;}
304 for(int zi=0; zi<img->dimz; zi++)
305 for(int yi=0; yi<img->dimy; yi++)
306 for(int xi=0; xi<img->dimx; xi++) {
307 int64_t a;
308 memcpy(&a, bptr, 8);
309 img->m[zi][yi][xi][ti]=scl_inter+scl_slope*(float)a;
310 bptr+=bytepix;
311 }
312 break;
314 if(bitpix!=64) {ret=1; break;}
315 for(int zi=0; zi<img->dimz; zi++)
316 for(int yi=0; yi<img->dimy; yi++)
317 for(int xi=0; xi<img->dimx; xi++) {
318 uint64_t a;
319 memcpy(&a, bptr, 8);
320 img->m[zi][yi][xi][ti]=scl_inter+scl_slope*(float)a;
321 bptr+=bytepix;
322 }
323 break;
324 case NIFTI_DT_FLOAT:
325 if(bitpix!=32) {ret=1; break;}
326 for(int zi=0; zi<img->dimz; zi++)
327 for(int yi=0; yi<img->dimy; yi++)
328 for(int xi=0; xi<img->dimx; xi++) {
329 float a;
330 memcpy(&a, bptr, 4);
331 img->m[zi][yi][xi][ti]=scl_inter+scl_slope*a;
332 bptr+=bytepix;
333 }
334 break;
335 case NIFTI_DT_DOUBLE:
336 if(bitpix!=64) {ret=1; break;}
337 for(int zi=0; zi<img->dimz; zi++)
338 for(int yi=0; yi<img->dimy; yi++)
339 for(int xi=0; xi<img->dimx; xi++) {
340 double a;
341 memcpy(&a, bptr, 8);
342 img->m[zi][yi][xi][ti]=scl_inter+scl_slope*(float)a;
343 bptr+=bytepix;
344 }
345 break;
346 default:
347 ret=2;
348 }
349 if(ret) {
350 fclose(fp); imgFree(img); free(buf);
351 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_UNSUPPORTED);
352 return(TPCERROR_UNSUPPORTED);
353 }
354 } // next frame
355 fclose(fp); free(buf);
356
357
358 /* Read SIF, if available */
359 if(siffile[0]) {
360 if(verbose>0) {printf("reading SIF %s\n", siffile); fflush(stdout);}
361 TAC sif; tacInit(&sif);
362 int ret=tacRead(&sif, siffile, status);
363 if(ret!=TPCERROR_OK) {imgFree(img); return(ret);}
364 ret=imgFromSIF(img, &sif, 1, 1, 0, verbose-1);
365 tacFree(&sif);
366 if(ret!=TPCERROR_OK) {
367 imgFree(img);
368 statusSet(status, __func__, __FILE__, __LINE__, ret);
369 return(ret);
370 }
371 }
372
373 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
374 return(TPCERROR_OK);
375}
376/*****************************************************************************/
377
378/*****************************************************************************/
392 IMG *img,
394 const char *fname,
396 TPCSTATUS *status
397) {
398 int verbose=0; if(status!=NULL) verbose=status->verbose;
399 if(verbose>0) {printf("%s(..., %s, ...)\n", __func__, fname); fflush(stdout);}
400
401 if(img==NULL || strnlen(fname, 2)<1) {
402 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_FAIL);
403 return(TPCERROR_FAIL);
404 }
405 if(!imgHasData(img)) {
406 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_DATA);
407 return(TPCERROR_NO_DATA);
408 }
409
410 /* Determine the output format */
411 if(verbose>1) {printf("determine output format\n"); fflush(stdout);}
412 if(img->oformat==IMG_FORMAT_UNKNOWN) {
413 char *cptr=filenameGetExtension(fname);
414 if(cptr!=NULL && strcasecmp(cptr, ".nii")==0) img->oformat=IMG_FORMAT_NIFTI_1S;
415 else img->oformat=img->format;
416 }
420
421 /* Get database name, in case file name was given with extension */
422 if(verbose>1) {printf("get dbname\n"); fflush(stdout);}
423 char basename[FILENAME_MAX];
424 strlcpy(basename, fname, FILENAME_MAX); niftiBasename(basename);
425 /* Check that there is something left after path */
426 char basenamewopath[FILENAME_MAX];
427 strcpy(basenamewopath, basename); filenameRmPath(basenamewopath);
428 if(strlen(basenamewopath)<1) {
429 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_FILENAME);
431 }
432 /* Create output file names (now to catch some errors) */
433 if(verbose>1) {printf("determine output file names\n"); fflush(stdout);}
434 char hdrfile[FILENAME_MAX], imgfile[FILENAME_MAX], siffile[FILENAME_MAX];
435 hdrfile[0]=imgfile[0]=siffile[0]=(char)0;
436 if(niftiCreateFNames(basename, hdrfile, imgfile, siffile, img->oformat)!=TPCERROR_OK) {
437 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_FILENAME);
439 }
440 /* If we have path, then create it */
441 char filepath[FILENAME_MAX];
442 strcpy(filepath, basename); filenameRmFile(filepath);
443 if(pathCreate(filepath)) {
444 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_FILENAME);
446 }
447
448
449 /* Fill the header structure */
450 NIFTI_DSR dsr;
451 int ret=imgSetNiftiHeader(img, &dsr, verbose-1);
452 if(ret!=TPCERROR_OK) {
453 statusSet(status, __func__, __FILE__, __LINE__, ret);
454 return(ret);
455 }
456
457 /* Delete previous NIfTI */
458 if(verbose>1) {printf("removing any previous files\n"); fflush(stdout);}
459 if(fileExist(hdrfile)) remove(hdrfile);
460 if(fileExist(imgfile)) remove(imgfile);
461 //if(fileExist(siffile)) remove(siffile); // NO, not this!
462
463 /* Write the header */
464 if(verbose>1) {printf("writing the header\n"); fflush(stdout);}
466 ret=niftiWriteHeader(hdrfile, &dsr, verbose-1);
467 } else if(img->oformat==IMG_FORMAT_NIFTI_1S || img->oformat==IMG_FORMAT_NIFTI_2S) {
468 ret=niftiWriteHeader(imgfile, &dsr, verbose-1);
469 }
470 if(ret!=TPCERROR_OK) {
471 statusSet(status, __func__, __FILE__, __LINE__, ret);
472 return(ret);
473 }
474 /* Write the pixel data */
475 if(verbose>1) {printf("opening file for pixel data\n"); fflush(stdout);}
476 FILE *fp;
478 fp=fopen(imgfile, "wb");
479 } else { // if(img->oformat==IMG_FORMAT_NIFTI_1S || if(img->oformat==IMG_FORMAT_NIFTI_2S
480 fp=fopen(imgfile, "r+b");
481 }
482 if(fp==NULL) {
483 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_OPEN);
484 return(TPCERROR_CANNOT_OPEN);
485 }
486 /* Move pointer to the start of pixel data */
487 long int pos;
488 if(dsr.n==1) pos=(int)dsr.h1.vox_offset; else pos=(int)dsr.h2.vox_offset;
489 if(fseek(fp, pos, SEEK_SET)!=0) {
490 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_WRITE);
491 fclose(fp); return(TPCERROR_CANNOT_WRITE);
492 }
493 /* Allocate memory for pixel matrix */
494 unsigned long long voxNr=img->dimt*img->dimz*img->dimy*img->dimx;
495 float *fdata;
496 fdata=(float*)calloc(voxNr, sizeof(float));
497 if(fdata==NULL) {
498 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OUT_OF_MEMORY);
499 fclose(fp); return(TPCERROR_OUT_OF_MEMORY);
500 }
501 /* Write voxel values as floats */
502 float *fptr=fdata;
503 for(unsigned int fi=0; fi<img->dimt; fi++)
504 for(unsigned int zi=0; zi<img->dimz; zi++)
505 for(unsigned int yi=0; yi<img->dimy; yi++)
506 for(unsigned int xi=0; xi<img->dimx; xi++, fptr++)
507 *fptr=img->m[zi][yi][xi][fi];
508 if(verbose>1) {printf("writing pixel data\n"); fflush(stdout);}
509 fptr=fdata;
510 if(fwrite(fptr, sizeof(float), voxNr, fp) != voxNr) {
511 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_WRITE);
512 free(fdata); fclose(fp); return(TPCERROR_CANNOT_WRITE);
513 }
514
515 free(fdata);
516 fclose(fp);
517
518 /* Frame times into SIF */
519 if(!imgHasTimes(img)) { // no frame times to save
520 if(verbose>1) printf(" no frame times to save into SIF\n");
521 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
522 return(TPCERROR_OK);
523 }
524 {
525 if(verbose>1) {printf("making SIF\n"); fflush(stdout);}
526 TAC sif; tacInit(&sif);
527 /* Try to read existing SIF */
528 if(fileExist(siffile) && tacRead(&sif, siffile, status)==TPCERROR_OK && sif.sampleNr==img->dimt)
529 {
530 /* If SIF was found and frameNr matches with image, then update the SIF contents,
531 but keep counts, in case previous SIF comes with actual count info from scanner */
532 ret=imgToSIF(img, &sif, 1, 1, 0, verbose-3);
533 } else {
534 /* otherwise create SIF contents */
535 ret=imgToSIF(img, &sif, 1, 1, 2, verbose-3);
536 }
537 if(ret!=TPCERROR_OK) {
538 if(verbose>0) fprintf(stderr, " Error: cannot create SIF contents.\n");
539 tacFree(&sif);
540 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_X);
541 return(TPCERROR_INVALID_X);
542 }
543 if(verbose>1) {printf("writing SIF\n"); fflush(stdout);}
544 fp=fopen(siffile, "w");
545 if(fp==NULL) {
546 tacFree(&sif);
547 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_OPEN);
548 return(TPCERROR_CANNOT_OPEN);
549 }
550 ret=tacWrite(&sif, fp, TAC_FORMAT_SIF, 0, status);
551 fclose(fp); tacFree(&sif);
552 if(ret!=TPCERROR_OK) {
553 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_WRITE);
554 return(TPCERROR_CANNOT_WRITE);
555 }
556 }
557
558
559 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
560 return(TPCERROR_OK);
561}
562/*****************************************************************************/
563
564/*****************************************************************************/
578 IMG *img,
580 NIFTI_DSR *dsr,
582 int verbose
583) {
584 if(verbose>0) {printf("%s()\n", __func__); fflush(stdout);}
585
586 if(img==NULL || imgHasData(img)==0 || dsr==NULL) return(TPCERROR_FAIL);
587
588 /* Check file format */
589 switch(img->oformat) {
591 dsr->n=1;
592 break;
594 dsr->n=1;
595 break;
597 dsr->n=2;
598 break;
600 dsr->n=2;
601 break;
602 default:
604 }
605
606 /* Find pixel value range */
607 float pmin, pmax;
608 int ret=imgMinMax(img, &pmin, &pmax);
609 if(ret!=TPCERROR_OK) return(ret);
610 if(verbose>1) {printf(" min=%g\n max=%g\n", pmin, pmax); fflush(stdout);}
611
612 /* Set NIfTI byte order to current machines byte order */
614
615 /* Initiate header structures with zeroes */
616 memset(&dsr->h1, 0, sizeof(NIFTI_1_HEADER));
617 memset(&dsr->h2, 0, sizeof(NIFTI_2_HEADER));
618 memset(&dsr->e, 0, sizeof(NIFTI_EXTENDER));
619
620
621 /* Set header */
622 if(dsr->n==1) { // NIfTI-1
623
624 dsr->h1.sizeof_hdr=NIFTI1_HEADER_SIZE; // 348
625 strcpy(dsr->h1.data_type, ""); // not used in NIfTI
626 strcpy(dsr->h1.db_name, ""); // not used in NIfTI
627 dsr->h1.extents=16384; // not used in NIfTI, but required for Analyze compatibility
628 dsr->h1.regular='r'; // not used in NIfTI, but required for Analyze compatibility
629 dsr->h1.dim_info='\0'; // MRI slice ordering
630 if(img->oformat==IMG_FORMAT_NIFTI_1S) {
632 strcpy(dsr->h1.magic, "n+1");
633 } else {
634 dsr->h1.vox_offset=0;
635 strcpy(dsr->h1.magic, "ni1");
636 }
637 strcpy(dsr->h1.aux_file, "");
638
639 /* Image dimension */
640 for(int i=0; i<8; i++) dsr->h1.dim[i]=1;
641 dsr->h1.dim[0]=4;
642 dsr->h1.dim[1]=img->dimx;
643 dsr->h1.dim[2]=img->dimy;
644 dsr->h1.dim[3]=img->dimz;
645 dsr->h1.dim[4]=img->dimt;
646
647 /* Intent */
649 dsr->h1.intent_p1=0.0;
650 dsr->h1.intent_p2=0.0;
651 dsr->h1.intent_p3=0.0;
652 strcpy(dsr->h1.intent_name, "");
653
654 /* Save data as floats, so that there is no need to scale */
656 dsr->h1.bitpix=32; // bits per pixel
657 dsr->h1.scl_slope=1.0; // data as floats, so no need to scale
658 dsr->h1.scl_inter=0.0; // data as floats, so no need to scale
659 dsr->h1.glmax=pmax; // unused in NIfTI
660 dsr->h1.glmin=pmin; // unused in NIfTI
661 dsr->h1.cal_max=pmax;
662 dsr->h1.cal_min=0.0; // scale display colours to have black at zero
663
664 /* Pixel size */
665 dsr->h1.slice_start=0;
666 for(int i=0; i<8; i++) dsr->h1.pixdim[i]=0.0;
667 // https://nifti.nimh.nih.gov/nifti-1/documentation/nifti1fields/nifti1fields_pages/qsform.html
668 dsr->h1.pixdim[0]=1.0; // Set to either 1.0 or -1.0; default should be 1.0.
669 dsr->h1.pixdim[1]=img->sizex;
670 dsr->h1.pixdim[2]=img->sizey;
671 dsr->h1.pixdim[3]=img->sizez;
672 dsr->h1.slice_end=0;
673 dsr->h1.slice_code=0;
674 dsr->h1.xyzt_units=NIFTI_UNITS_MM; // Voxel size in mm in IMG structure
675 dsr->h1.slice_duration=0.0;
676 dsr->h1.toffset=0.0;
677
678 /* Coordinate system */
679 dsr->h1.qform_code=img->xform[0];
680 dsr->h1.sform_code=img->xform[1];
681 dsr->h1.quatern_b=img->quatern[0];
682 dsr->h1.quatern_c=img->quatern[1];
683 dsr->h1.quatern_d=img->quatern[2];
684 dsr->h1.qoffset_x=img->quatern[3];
685 dsr->h1.qoffset_y=img->quatern[4];
686 dsr->h1.qoffset_z=img->quatern[5];
687
688 /* Save pixel units into description (not standard NIfTI) */
689 if(img->cunit==UNIT_UNKNOWN) strcpy(dsr->h1.descrip, "");
690 else strlcpy(dsr->h1.descrip, unitName(img->cunit), 80);
691
692 for(int i=0; i<4; i++) dsr->h1.srow_x[i]=img->srow[i];
693 for(int i=0; i<4; i++) dsr->h1.srow_y[i]=img->srow[4+i];
694 for(int i=0; i<4; i++) dsr->h1.srow_z[i]=img->srow[8+i];
695
696 /* Extension is left as 0 0 0 0 */
697
698 } else { // NIfTI-2
699
700 /* Header size. Used for identifying the format and endianness of data */
701 dsr->h2.sizeof_hdr=NIFTI2_HEADER_SIZE; // 540
702
703 /* Magic string. Used for identifying the format and verifying validity */
704 if(img->oformat==IMG_FORMAT_NIFTI_2S) strcpy(dsr->h2.magic, "n+2");
705 else strcpy(dsr->h2.magic, "ni2");
706 dsr->h2.magic[3]='\0';
707 dsr->h2.magic[4]='\r';
708 dsr->h2.magic[5]='\n';
709 dsr->h2.magic[6]=(char)32;
710 dsr->h2.magic[7]='\n';
711
712 /* Save data as 32-bit floats, so that there is no need to scale */
714 dsr->h2.bitpix=32; // bits per pixel
715
716 /* Image dimensions */
717 for(int i=0; i<8; i++) dsr->h2.dim[i]=1;
718 dsr->h2.dim[0]=4;
719 dsr->h2.dim[1]=img->dimx;
720 dsr->h2.dim[2]=img->dimy;
721 dsr->h2.dim[3]=img->dimz;
722 dsr->h2.dim[4]=img->dimt;
723
724 /* Intent */
726 dsr->h2.intent_p1=0.0;
727 dsr->h2.intent_p2=0.0;
728 dsr->h2.intent_p3=0.0;
729 strcpy(dsr->h2.intent_name, "");
730
731 /* Grid spacings */
732 dsr->h2.pixdim[0]=1.0; // Set to either 1.0 or -1.0; default should be 1.0.
733 dsr->h2.pixdim[1]=img->sizex;
734 dsr->h2.pixdim[2]=img->sizey;
735 dsr->h2.pixdim[3]=img->sizez;
736 for(int i=4; i<8; i++) dsr->h2.pixdim[i]=0.0;
737
738 /* Offset into pixel data; zero for dual file */
739 if(img->oformat==IMG_FORMAT_NIFTI_2S) {
741 } else {
742 dsr->h2.vox_offset=0;
743 }
744
745 /* Scaling */
746 dsr->h2.scl_slope=1.0; // data as floats, so no need to scale
747 dsr->h2.scl_inter=0.0; // data as floats, so no need to scale
748 dsr->h2.cal_max=pmax;
749 dsr->h2.cal_min=0.0; // scale display colours to have black at zero
750
751 dsr->h2.slice_duration=0.0;
752 dsr->h2.toffset=0.0;
753 dsr->h2.slice_start=0;
754 dsr->h2.slice_end=img->dimz-1;
755
756 /* Save pixel units into description (not standard NIfTI) */
757 if(img->cunit==UNIT_UNKNOWN) strcpy(dsr->h2.descrip, "");
758 else strlcpy(dsr->h2.descrip, unitName(img->cunit), 80);
759
760 strcpy(dsr->h2.aux_file, "");
761
762 /* Coordinate system */
763 dsr->h2.qform_code=img->xform[0];
764 dsr->h2.sform_code=img->xform[1];
765 dsr->h2.quatern_b=img->quatern[0];
766 dsr->h2.quatern_c=img->quatern[1];
767 dsr->h2.quatern_d=img->quatern[2];
768 dsr->h2.qoffset_x=img->quatern[3];
769 dsr->h2.qoffset_y=img->quatern[4];
770 dsr->h2.qoffset_z=img->quatern[5];
771 for(int i=0; i<4; i++) dsr->h2.srow_x[i]=img->srow[i];
772 for(int i=0; i<4; i++) dsr->h2.srow_y[i]=img->srow[4+i];
773 for(int i=0; i<4; i++) dsr->h2.srow_z[i]=img->srow[8+i];
774
775 dsr->h2.slice_code=0;
777 dsr->h2.dim_info='\0'; // MRI slice ordering
778
779 /* Extension is left as 0 0 0 0 */
780
781 }
782
783 return(TPCERROR_OK);
784}
785/*****************************************************************************/
786
787/*****************************************************************************/
796 IMG *img,
798 NIFTI_DSR *dsr,
800 int verbose
801) {
802 if(verbose>0) {printf("%s()\n", __func__); fflush(stdout);}
803
804 /* Check the input */
805 if(dsr==NULL || img==NULL) return(TPCERROR_FAIL);
806 if(dsr->n!=1 && dsr->n!=2) return(TPCERROR_FAIL);
807
808 /* NIfTI file format */
809 if(dsr->n==1) {
810 if(strcmp(dsr->h1.magic, "ni1")==0) img->format=IMG_FORMAT_NIFTI_1D;
811 else if(strcmp(dsr->h1.magic, "n+1")==0) img->format=IMG_FORMAT_NIFTI_1S;
812 else return(TPCERROR_INVALID_FORMAT);
813 } else if (dsr->n==2) {
814 if(strcmp(dsr->h2.magic, "ni2")==0) img->format=IMG_FORMAT_NIFTI_2D;
815 else if(strcmp(dsr->h2.magic, "n+2")==0) img->format=IMG_FORMAT_NIFTI_2S;
816 else return(TPCERROR_INVALID_FORMAT);
817 } else {
818 return(TPCERROR_FAIL);
819 }
820
821 /* Get the image dimensions */
822 int dimNr;
823 if(dsr->n==1) dimNr=dsr->h1.dim[0]; else dimNr=dsr->h2.dim[0];
824 if(dimNr<2 || dimNr>8) return(TPCERROR_INVALID_HEADER);
825 if(dimNr>4) {
826 if(verbose>0) fprintf(stderr, "Error: NIfTI image dimension %d is not supported\n", dimNr);
827 return(TPCERROR_UNSUPPORTED);
828 }
829
830 long long dimx, dimy, dimz=1, dimt=1;
831 if(dsr->n==1) {
832 dimx=dsr->h1.dim[1];
833 dimy=dsr->h1.dim[2];
834 if(dimNr>2) {dimz=dsr->h1.dim[3]; if(dimNr>3) dimt=dsr->h1.dim[4];}
835 } else {
836 dimx=dsr->h2.dim[1];
837 dimy=dsr->h2.dim[2];
838 if(dimNr>2) {dimz=dsr->h2.dim[3]; if(dimNr>3) dimt=dsr->h2.dim[4];}
839 }
840 long long pxlNr=dimx*dimy*dimz;
841 if(pxlNr<1 || dimt<0) {
842 if(verbose>0) fprintf(stderr, "Error: invalid NIfTI image dimensions.\n");
844 }
845 if(dimt==0) dimt=1;
846 img->dimx=dimx; img->dimy=dimy; img->dimz=dimz; img->dimt=dimt;
847
848 /* Pixel x,y,z sizes, converting units if necessary */
849 int xyzt_units=0;
850 if(dsr->n==1) xyzt_units=dsr->h1.xyzt_units; else xyzt_units=dsr->h2.xyzt_units;
851 float f=1.0;
852 if(xyzt_units & NIFTI_UNITS_METER) f=1000.;
853 else if(xyzt_units & NIFTI_UNITS_MICRON) f=0.001;
854 else if(xyzt_units & NIFTI_UNITS_MM) f=1.0;
855 if(verbose>2) printf("pixel size conversion factor := %g\n", f);
856 if(dsr->n==1) {
857 img->sizex=dsr->h1.pixdim[1]; img->sizey=dsr->h1.pixdim[2]; img->sizez=dsr->h1.pixdim[3];
858 } else {
859 img->sizex=dsr->h2.pixdim[1]; img->sizey=dsr->h2.pixdim[2]; img->sizez=dsr->h2.pixdim[3];
860 }
861 img->sizex*=f; img->sizey*=f; img->sizez*=f;
862
863 /* Orientation, quaternion, and transformation parameters */
864 if(dsr->n==1) {
865 img->xform[0]=dsr->h1.qform_code;
866 img->xform[1]=dsr->h1.sform_code;
867 img->quatern[0]=dsr->h1.quatern_b;
868 img->quatern[1]=dsr->h1.quatern_c;
869 img->quatern[2]=dsr->h1.quatern_d;
870 img->quatern[3]=dsr->h1.qoffset_x;
871 img->quatern[4]=dsr->h1.qoffset_y;
872 img->quatern[5]=dsr->h1.qoffset_z;
873 for(int i=0; i<4; i++) img->srow[i]=dsr->h1.srow_x[i];
874 for(int i=0; i<4; i++) img->srow[4+i]=dsr->h1.srow_y[i];
875 for(int i=0; i<4; i++) img->srow[8+i]=dsr->h1.srow_z[i];
876 } else {
877 img->xform[0]=dsr->h2.qform_code;
878 img->xform[1]=dsr->h2.sform_code;
879 img->quatern[0]=dsr->h2.quatern_b;
880 img->quatern[1]=dsr->h2.quatern_c;
881 img->quatern[2]=dsr->h2.quatern_d;
882 img->quatern[3]=dsr->h2.qoffset_x;
883 img->quatern[4]=dsr->h2.qoffset_y;
884 img->quatern[5]=dsr->h2.qoffset_z;
885 for(int i=0; i<4; i++) img->srow[i]=dsr->h2.srow_x[i];
886 for(int i=0; i<4; i++) img->srow[4+i]=dsr->h2.srow_y[i];
887 for(int i=0; i<4; i++) img->srow[8+i]=dsr->h2.srow_z[i];
888 }
889
890 /* Assumptions etc */
892 strcpy(img->studyNr, "");
894 img->cunit=UNIT_UNKNOWN;
895
896 /* Check if unit can be found in description field */
897 char *cptr;
898 if(dsr->n==1) cptr=dsr->h1.descrip; else cptr=dsr->h2.descrip;
899 img->cunit=unitIdentify(cptr);
900
901 return(TPCERROR_OK);
902}
903/*****************************************************************************/
904
905/*****************************************************************************/
void swap32ip(void *buf, unsigned long long size)
Definition endian.c:210
void swap64ip(void *buf, unsigned long long size)
Definition endian.c:184
int endianLittle()
Definition endian.c:53
void swap16ip(void *buf, unsigned long long size)
Definition endian.c:234
void filenameRmFile(char *s)
Definition filename.c:44
char * filenameGetExtension(const char *s)
Get the last extension of a file name.
Definition filename.c:178
void filenameRmPath(char *s)
Definition filename.c:20
int fileExist(const char *filename)
Definition filexist.c:17
int imgHasData(IMG *img)
Definition image.c:218
void imgFree(IMG *img)
Definition image.c:107
int imgHasTimes(IMG *img)
Definition image.c:235
int imgMinMax(IMG *img, float *minvalue, float *maxvalue)
Definition image.c:396
int imgAllocate(IMG *img, const unsigned int dimz, const unsigned int dimy, const unsigned int dimx, const unsigned int dimt, TPCSTATUS *status)
Definition image.c:126
char * imgFormatDescr(imgformat c)
Definition imageio.c:36
int imgSetNiftiHeader(IMG *img, NIFTI_DSR *dsr, int verbose)
Definition imagenii.c:576
int niftiCreateFNames(const char *filename, char *hdrfile, char *imgfile, char *siffile, int fileformat)
Definition imagenii.c:17
int imgWriteNifti(IMG *img, const char *fname, TPCSTATUS *status)
Definition imagenii.c:390
int imgReadNifti(IMG *img, const char *fname, TPCSTATUS *status)
Definition imagenii.c:72
int imgGetNiftiHeader(IMG *img, NIFTI_DSR *dsr, int verbose)
Definition imagenii.c:794
int imgToSIF(IMG *img, TAC *sif, int copy_header, int copy_frames, int copy_counts, int verbose)
Definition imagesif.c:18
int imgFromSIF(IMG *img, TAC *sif, int copy_header, int copy_frames, int copy_counts, int verbose)
Definition imagesif.c:126
int niftiExists(const char *filename, char *hdrfile, char *imgfile, char *siffile, NIFTI_DSR *header, TPCSTATUS *status)
Definition niftiio.c:17
int niftiWriteHeader(const char *filename, NIFTI_DSR *dsr, int verbose)
Definition niftiio.c:445
void niftiBasename(char *filename)
Definition niftiname.c:14
int pathCreate(const char *pathname)
Definition pathexist.c:81
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
Definition statusmsg.c:142
size_t strnlen(const char *s, size_t n)
Definition stringext.c:566
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition stringext.c:632
Definition tpcimage.h:82
float sizex
Definition tpcimage.h:119
unsigned short int dimx
Definition tpcimage.h:112
unit cunit
Definition tpcimage.h:203
float **** m
Definition tpcimage.h:161
imgformat format
Definition tpcimage.h:103
short int xform[2]
Definition tpcimage.h:133
float quatern[6]
Definition tpcimage.h:135
float srow[12]
Definition tpcimage.h:137
unsigned short int dimt
Definition tpcimage.h:110
float sizey
Definition tpcimage.h:121
imgcontent content
Definition tpcimage.h:97
unsigned short int dimz
Definition tpcimage.h:116
unsigned short int dimy
Definition tpcimage.h:114
decaycorrection decayCorrection
Definition tpcimage.h:91
char studyNr[MAX_STUDYNR_LEN+1]
Definition tpcimage.h:85
imgformat oformat
Definition tpcimage.h:105
float sizez
Definition tpcimage.h:123
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
double srow_x[4]
Definition tpcnifti.h:372
int64_t vox_offset
Definition tpcnifti.h:333
char aux_file[24]
Definition tpcnifti.h:353
int16_t datatype
Definition tpcnifti.h:317
char magic[8]
Definition tpcnifti.h:315
double slice_duration
Definition tpcnifti.h:343
int64_t dim[8]
Definition tpcnifti.h:323
double cal_min
Definition tpcnifti.h:341
double pixdim[8]
Definition tpcnifti.h:331
double intent_p2
Definition tpcnifti.h:327
int64_t slice_start
Definition tpcnifti.h:347
double qoffset_y
Definition tpcnifti.h:368
double intent_p3
Definition tpcnifti.h:329
int64_t slice_end
Definition tpcnifti.h:349
double srow_y[4]
Definition tpcnifti.h:374
double scl_inter
Definition tpcnifti.h:337
double scl_slope
Definition tpcnifti.h:335
double intent_p1
Definition tpcnifti.h:325
double quatern_d
Definition tpcnifti.h:364
double qoffset_z
Definition tpcnifti.h:370
double qoffset_x
Definition tpcnifti.h:366
double toffset
Definition tpcnifti.h:345
char descrip[80]
Definition tpcnifti.h:351
double quatern_c
Definition tpcnifti.h:362
int16_t bitpix
Definition tpcnifti.h:319
double cal_max
Definition tpcnifti.h:339
double srow_z[4]
Definition tpcnifti.h:376
double quatern_b
Definition tpcnifti.h:360
char intent_name[16]
Definition tpcnifti.h:384
NIFTI_2_HEADER h2
Definition tpcnifti.h:406
NIFTI_EXTENDER e
Definition tpcnifti.h:408
NIFTI_1_HEADER h1
Definition tpcnifti.h:404
int byte_order
Definition tpcnifti.h:412
Definition tpctac.h:87
int sampleNr
Definition tpctac.h:89
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
void tacFree(TAC *tac)
Definition tac.c:106
void tacInit(TAC *tac)
Definition tac.c:24
int tacRead(TAC *d, const char *fname, TPCSTATUS *status)
Definition tacio.c:413
int tacWrite(TAC *tac, FILE *fp, tacformat format, int extra, TPCSTATUS *status)
Definition tacio.c:332
@ UNIT_UNKNOWN
Unknown unit.
@ TPCERROR_FAIL
General error.
@ TPCERROR_INVALID_FORMAT
Invalid file format.
@ TPCERROR_INVALID_HEADER
Invalid header contents.
@ TPCERROR_CANNOT_OPEN
Cannot open file.
@ TPCERROR_OUT_OF_MEMORY
Cannot allocate memory.
@ TPCERROR_INVALID_X
Invalid sample time.
@ TPCERROR_UNSUPPORTED
Unsupported file type.
@ TPCERROR_OK
No error.
@ TPCERROR_INVALID_FILENAME
Invalid file name.
@ TPCERROR_NO_DATA
File contains no data.
@ TPCERROR_CANNOT_READ
Cannot read file.
@ TPCERROR_CANNOT_WRITE
Cannot write file.
int unitIdentify(const char *s)
Definition units.c:162
char * unitName(int unit_code)
Definition units.c:143
Header file for libtpcimage.
@ IMG_FORMAT_NIFTI_1D
NIfTI-1 dual-file format.
Definition tpcimage.h:42
@ IMG_FORMAT_NIFTI_2S
NIfTI-2 single-file format.
Definition tpcimage.h:45
@ IMG_FORMAT_UNKNOWN
Unknown format.
Definition tpcimage.h:33
@ IMG_FORMAT_NIFTI_1S
NIfTI-1 single-file format.
Definition tpcimage.h:43
@ IMG_FORMAT_NIFTI_2D
NIfTI-2 dual-file format.
Definition tpcimage.h:44
@ IMG_CONTENT_IMAGE
Image data.
Definition tpcimage.h:72
@ DECAY_CORRECTED
Data is corrected for physical decay.
Definition tpcisotope.h:81
#define NIFTI_DT_LONG_DOUBLE
Definition tpcnifti.h:120
#define NIFTI_DT_RGB
Definition tpcnifti.h:106
#define NIFTI_DT_BINARY
Definition tpcnifti.h:92
#define NIFTI_DT_FLOAT
Definition tpcnifti.h:100
#define NIFTI_DT_UNSIGNED_SHORT
Definition tpcnifti.h:112
#define NIFTI_UNITS_METER
Definition tpcnifti.h:46
#define NIFTI_DT_SIGNED_SHORT
Definition tpcnifti.h:96
#define NIFTI_DT_UNSIGNED_INT
Definition tpcnifti.h:114
#define NIFTI_DT_UNSIGNED_LONG_LONG
Definition tpcnifti.h:118
#define NIFTI_DT_SIGNED_INT
Definition tpcnifti.h:98
#define NIFTI_DT_ALL
Definition tpcnifti.h:108
#define NIFTI_DT_UNSIGNED_CHAR
Definition tpcnifti.h:94
#define NIFTI1_HEADER_EXTENDER_SIZE
Definition tpcnifti.h:35
#define NIFTI_UNITS_MICRON
Definition tpcnifti.h:50
#define NIFTI1_HEADER_SIZE
Definition tpcnifti.h:33
#define NIFTI_DT_COMPLEX
Definition tpcnifti.h:102
#define NIFTI2_HEADER_EXTENDER_SIZE
Definition tpcnifti.h:39
#define NIFTI2_HEADER_SIZE
Definition tpcnifti.h:37
#define NIFTI_DT_DOUBLE_PAIR
Definition tpcnifti.h:122
#define NIFTI_INTENT_NONE
Definition tpcnifti.h:129
#define NIFTI_DT_RGBA
Definition tpcnifti.h:126
#define NIFTI_DT_UNKNOWN
Definition tpcnifti.h:90
#define NIFTI_UNITS_SEC
Definition tpcnifti.h:52
#define NIFTI_UNITS_MM
Definition tpcnifti.h:48
#define NIFTI_DT_SIGNED_CHAR
Definition tpcnifti.h:110
#define NIFTI_DT_LONG_LONG
Definition tpcnifti.h:116
#define NIFTI_DT_DOUBLE
Definition tpcnifti.h:104
#define NIFTI_DT_LONG_DOUBLE_PAIR
Definition tpcnifti.h:124
@ TAC_FORMAT_SIF
Scan information file.
Definition tpctac.h:43