img_ana.c
Go to the documentation of this file.
1 /******************************************************************************
2 
3  Copyright (c) 2007-2009,2011 Turku PET Centre
4 
5  Library: img_ana.c
6  Description: I/O routines for IMG data from/to Analyze 7.5 format.
7 
8  This library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Lesser General Public
10  License as published by the Free Software Foundation; either
11  version 2.1 of the License, or (at your option) any later version.
12 
13  This library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  See the GNU Lesser General Public License for more details:
17  http://www.gnu.org/copyleft/lesser.html
18 
19  You should have received a copy of the GNU Lesser General Public License
20  along with this library/program; if not, write to the Free Software
21  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 
23  Turku PET Centre, Turku, Finland, http://www.turkupetcentre.fi/
24 
25  Modification history:
26  2007-01-31 Vesa Oikonen
27  Functions moved from imgfile.c.
28  Prompts and randoms are read from SIF data to IMG when reading Analyze.
29  2007-02-27 VO
30  Bug correction in imgWriteAnalyze(): fp was not closed in all errors.
31  2007-03-25 VO
32  Added functions imgReadAnalyzeHeader(), imgGetAnalyzeHeader(),
33  imgSetAnalyzeHeader(), imgReadAnalyzeFrame(), imgReadAnalyzeFirstFrame(),
34  and imgWriteAnalyzeFrame().
35  2007-17-07 Harri Merisaari
36  Modified for optional ANSi compatibility
37  2007-09-10 VO
38  Return value of localtime() is checked.
39  2008-07-07 VO
40  If information on decay correction is not found in Analyze header, then
41  it is assumed that image data is corrected for decay; previously assumed
42  that image was NOT corrected for decay.
43  2009-12-10 VO
44  strcpy() replaced with strncpy() in filling header fields.
45  2011-08-17 VO
46  imgSetAnalyzeHeader() writes exp_date in format YYYYMMDD instead of
47  YYYY-MM-DD because the header field length is only 10 bytes.
48 
49 
50 ******************************************************************************/
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <unistd.h>
54 #include <math.h>
55 #include <string.h>
56 #include <time.h>
57 /*****************************************************************************/
58 #include "petc99.h"
59 #include "swap.h"
60 #include "halflife.h"
61 /*****************************************************************************/
62 #include "include/img.h"
63 #include "include/analyze.h"
64 #include "include/imgmax.h"
65 #include "include/imgdecay.h"
66 #include "include/sif.h"
67 #include "include/imgfile.h"
68 /*****************************************************************************/
69 
70 /*****************************************************************************/
86 int imgReadAnalyze(const char *dbname, IMG *img) {
87  FILE *fp;
88  int ret, fi, pi, xi, yi;
89  float *fdata=NULL, *fptr;
90  ANALYZE_DSR dsr;
91  char datfile[FILENAME_MAX], hdrfile[FILENAME_MAX], siffile[FILENAME_MAX];
92  char buf[128], *cptr;
93  int dimNr, dimx, dimy, dimz=1, dimt=1, pxlNr=0;
94  SIF sif;
95  struct tm *st;
96 
97 
98  if(IMG_TEST) printf("imgReadAnalyze(%s, *img)\n", dbname);
99 
100  /* Check the arguments */
101  imgSetStatus(img, STATUS_OK);
102  if(img==NULL || img->status!=IMG_STATUS_INITIALIZED) {
103  imgSetStatus(img, STATUS_FAULT); return(2);}
104  if(dbname==NULL || !dbname[0]) {imgSetStatus(img, STATUS_FAULT); return(1);}
105 
106  /* Make the image and header filenames */
107  if(anaExists(dbname)==0) {
108  /* Check if filename was given accidentally with extension */
109  strcpy(datfile, dbname); cptr=strrchr(datfile, '.');
110  if(cptr!=NULL && (strcmp(cptr, ".img")==0 || strcmp(cptr, ".hdr")==0)) {
111  *cptr=(char)0; strcpy(hdrfile, datfile);
112  if(anaExists(datfile)==0) { /* still not found */
113  imgSetStatus(img, STATUS_NOHEADERFILE); return(3);}
114  strcat(datfile, ".img"); strcat(hdrfile, ".hdr");
115  } else {
116  imgSetStatus(img, STATUS_NOHEADERFILE); return(3);
117  }
118  } else {
119  /* Database name was given and img and hdr files were found */
120  strcpy(datfile, dbname); strcat(datfile, ".img");
121  strcpy(hdrfile, dbname); strcat(hdrfile, ".hdr");
122  }
123 
124  /* Read Analyze header file */
125  ret=anaReadHeader(hdrfile, &dsr);
126  if(ret) {
127  if(ret==1) imgSetStatus(img, STATUS_FAULT);
128  else if(ret==2) imgSetStatus(img, STATUS_NOHEADERFILE);
129  else imgSetStatus(img, STATUS_UNSUPPORTED);
130  return(3);
131  }
132  if(IMG_TEST) anaPrintHeader(&dsr, stdout);
133 
134  /* Open image datafile */
135  if(IMG_TEST) fprintf(stdout, "reading image data %s\n", datfile);
136  if((fp=fopen(datfile, "rb")) == NULL) {imgSetStatus(img, STATUS_NOIMGDATA); return(5);}
137 
138  /* Prepare IMG for Analyze image */
139  /* Get the image dimensions from header */
140  dimNr=dsr.dime.dim[0];
141  if(dimNr<2) {fclose(fp); imgSetStatus(img, STATUS_INVALIDHEADER); return(4);}
142  dimx=dsr.dime.dim[1]; dimy=dsr.dime.dim[2];
143  if(dimNr>2) {dimz=dsr.dime.dim[3]; if(dimNr>3) dimt=dsr.dime.dim[4];}
144  pxlNr=dimx*dimy*dimz;
145  if(pxlNr<1) {fclose(fp); imgSetStatus(img, STATUS_INVALIDHEADER); return(4);}
146  /* Allocate memory for IMG */
147  ret=imgAllocate(img, dimz, dimy, dimx, dimt);
148  if(ret) {fclose(fp); imgSetStatus(img, STATUS_NOMEMORY); return(11);}
149  /* Copy information from Analyze header */
150  img->type=IMG_TYPE_IMAGE;
151  strncpy(img->studyNr, dsr.hist.patient_id, MAX_STUDYNR_LEN);
152  strcpy(img->patientName, dsr.hist.patient_id);
153  img->sizex=dsr.dime.pixdim[1];
154  img->sizey=dsr.dime.pixdim[2];
155  img->sizez=dsr.dime.pixdim[3];
156  /*if(dsr.dime.funused2>1.E-5) img->zoom=dsr.dime.funused2;*/
157  if(dsr.dime.funused3>1.E-5) img->isotopeHalflife=dsr.dime.funused3;
158  for(pi=0; pi<dimz; pi++) img->planeNumber[pi]=pi+1;
159  if(dsr.little) img->_fileFormat=IMG_ANA_L; else img->_fileFormat=IMG_ANA;
160  /* Decay correction */
161  if(strstr(dsr.hist.descrip, "Decay corrected.")!=NULL)
162  img->decayCorrected=1;
163  else if(strstr(dsr.hist.descrip, "No decay correction.")!=NULL)
164  img->decayCorrected=0;
165  else
166  img->decayCorrected=1;
167 
168  /* Allocate memory for one image frame */
169  fdata=malloc(pxlNr*sizeof(float));
170  if(fdata==NULL) {fclose(fp); imgSetStatus(img, STATUS_NOMEMORY); return(12);}
171 
172  /* Read one image frame at a time */
173  for(fi=0; fi<dimt; fi++) {
174  fptr=fdata;
175  ret=anaReadImagedata(fp, &dsr, fi+1, fptr);
176  if(ret) {free(fdata); fclose(fp); imgSetStatus(img, STATUS_NOIMGDATA); return(7);}
177  /* Copy pixel values to IMG */
178  fptr=fdata;
179  if(anaFlipping()==0) { /* no flipping in z-direction */
180  for(pi=0; pi<img->dimz; pi++)
181  for(yi=dimy-1; yi>=0; yi--)
182  for(xi=dimx-1; xi>=0; xi--)
183  img->m[pi][yi][xi][fi]=*fptr++;
184  } else {
185  for(pi=dimz-1; pi>=0; pi--)
186  for(yi=dimy-1; yi>=0; yi--)
187  for(xi=dimx-1; xi>=0; xi--)
188  img->m[pi][yi][xi][fi]=*fptr++;
189  }
190  } /* next frame */
191  free(fdata);
192  fclose(fp);
193 
194  /* Try to read frame time information from SIF file */
195  /* Make filename from database or image data file */
196  strcpy(siffile, dbname); strcat(siffile, ".sif");
197  if(access(siffile, 0) == -1) {
198  strcpy(siffile, datfile); strcat(siffile, ".sif");
199  }
200  /* Check if SIF file is found */
201  if(IMG_TEST) printf("reading SIF file %s\n", siffile);
202  if(access(siffile, 0) == -1) {
203  if(IMG_TEST) printf(" No SIF file; therefore unknown frame times.\n");
204  return(0);
205  }
206  /* If found, then read it */
207  sifInit(&sif); ret=sifRead(siffile, &sif);
208  if(ret) {imgSetStatus(img, STATUS_NOSIFDATA); return(21);}
209  /* Copy scan start time */
210  if(sif.scantime>0) {
211  st=localtime(&sif.scantime);
212  if(st!=NULL) strftime(buf, 128, "%Y-%m-%d %H:%M:%S", st);
213  else strcpy(buf, "1900-01-01 00:00:00");
214  img->scanStart=sif.scantime;
215  }
216  /* Copy frame times */
217  if(sif.frameNr!=img->dimt) {
218  imgSetStatus(img, STATUS_WRONGSIFDATA); sifEmpty(&sif); return(22);}
219  for(fi=0; fi<sif.frameNr; fi++) {
220  img->start[fi]=sif.x1[fi]; img->end[fi]=sif.x2[fi];
221  img->mid[fi]=0.5*(img->start[fi]+img->end[fi]);
222  }
223  /* Copy prompts and randoms */
224  for(fi=0; fi<sif.frameNr; fi++) {
225  img->prompts[fi]=sif.prompts[fi];
226  img->randoms[fi]=sif.randoms[fi];
227  }
228 
229  /* Set isotopeHalflife, if isotope is found */
230  if(strlen(sif.isotope_name)>1) {
231  img->isotopeHalflife=60.0*hlFromIsotope(sif.isotope_name);
232  }
233  sifEmpty(&sif);
234 
235  return(0);
236 }
237 /*****************************************************************************/
238 
239 /*****************************************************************************/
256 int imgWriteAnalyze(const char *dbname, IMG *img) {
257  FILE *fp;
258  int ret, fi, pi, xi, yi, little;
259  float g;
260  ANALYZE_DSR dsr;
261  char datfile[FILENAME_MAX], hdrfile[FILENAME_MAX];
262  const char *cptr;
263  int pxlNr=0;
264  struct tm *st;
265  short int *sdata, *sptr, smin, smax;
266 
267 
268  if(IMG_TEST) printf("imgWriteAnalyze(%s, *img)\n", dbname);
269 
270  /* Check the arguments */
271  imgSetStatus(img, STATUS_OK);
272  if(img==NULL || img->status!=IMG_STATUS_OCCUPIED) {
273  imgSetStatus(img, STATUS_FAULT); return(2);}
274  if(dbname==NULL || !dbname[0]) {imgSetStatus(img, STATUS_FAULT); return(1);}
275 
276  /* Make the image and header filenames */
277  strcpy(datfile, dbname); strcat(datfile, ".img");
278  strcpy(hdrfile, dbname); strcat(hdrfile, ".hdr");
279 
280 
281  /*
282  * Fill Analyze header
283  */
284  if(img->_fileFormat==IMG_ANA_L) dsr.little=1; else dsr.little=0;
285  /* Header key */
286  memset(&dsr.hk, 0, sizeof(ANALYZE_HEADER_KEY));
287  memset(&dsr.dime, 0, sizeof(ANALYZE_HEADER_IMGDIM));
288  memset(&dsr.hist, 0, sizeof(ANALYZE_HEADER_HISTORY));
289  dsr.hk.sizeof_hdr=348;
290  strcpy(dsr.hk.data_type, "");
291  cptr=strrchr(dbname, '/'); if(cptr==NULL) cptr=strrchr(dbname, '\\');
292  if(cptr!=NULL) cptr++; if(cptr==NULL) cptr=dbname;
293  strncpy(dsr.hk.db_name, cptr, 17);
294  dsr.hk.extents=16384;
295  dsr.hk.regular='r';
296  /* Image dimension */
297  dsr.dime.dim[0]=4;
298  dsr.dime.dim[1]=img->dimx;
299  dsr.dime.dim[2]=img->dimy;
300  dsr.dime.dim[3]=img->dimz;
301  dsr.dime.dim[4]=img->dimt;
303  dsr.dime.bitpix=16;
304  dsr.dime.pixdim[0]=0.0;
305  dsr.dime.pixdim[1]=img->sizex;
306  dsr.dime.pixdim[2]=img->sizey;
307  dsr.dime.pixdim[3]=img->sizez;
308  dsr.dime.pixdim[4]=0.0;
309  dsr.dime.funused1=0.0; /* Scale factor is set later */
310  /* dsr.dime.funused2=img->zoom; */ /* Reconstruction zoom */
311  dsr.dime.funused3=img->isotopeHalflife;
312  /* Data history */
313  if(img->decayCorrected==1) strcpy(dsr.hist.descrip, "Decay corrected.");
314  else strcpy(dsr.hist.descrip, "No decay correction.");
315  strncpy(dsr.hist.scannum, img->studyNr, 10);
316  st=localtime(&img->scanStart);
317  if(st!=NULL) {
318  strftime(dsr.hist.exp_date, 10, "%Y-%m-%d", st);
319  strftime(dsr.hist.exp_time, 10, "%H:%M:%S", st);
320  } else {
321  strncpy(dsr.hist.exp_date, "1900-01-01", 10);
322  strncpy(dsr.hist.exp_time, "00:00:00", 10);
323  }
324 
325  /*
326  * Scale data to short int range
327  * Determine and set scale factor and cal_min & cal_max
328  */
329  if(IMG_TEST) printf("scaling data to short ints\n");
330  ret=imgMinMax(img, &dsr.dime.cal_min, &dsr.dime.cal_max);
331  if(ret) {imgSetStatus(img, STATUS_FAULT); return(3);}
332  if(fabs(dsr.dime.cal_min)>fabs(dsr.dime.cal_max)) g=fabs(dsr.dime.cal_min);
333  else g=fabs(dsr.dime.cal_max);
334  if(g<1E-20) g=1.0; else g=32767./g; dsr.dime.funused1=1.0/g;
335  if(IMG_TEST) printf("min=%g max=%g scale_factor=%g\n",
336  dsr.dime.cal_min, dsr.dime.cal_max, dsr.dime.funused1);
337 
338  /* Allocate memory for short int array */
339  pxlNr=(img->dimx)*(img->dimy)*(img->dimz);
340  sdata=malloc(pxlNr*sizeof(short int));
341  if(sdata==NULL) {
343  return 12;
344  }
345 
346  /* Open image data file for write */
347  if((fp=fopen(datfile, "wb")) == NULL) {
349  free(sdata);
350  return 14;
351  }
352 
353  /* Copy and write image matrix data to short int array */
354  /* Data is written one frame at a time */
355  smin=smax=temp_roundf(g*img->m[0][0][0][0]);
356  for(fi=0; fi<img->dimt; fi++) {
357  sptr=sdata;
358  if(anaFlipping()==0) {
359  for(pi=0; pi<img->dimz; pi++)
360  for(yi=img->dimy-1; yi>=0; yi--)
361  for(xi=img->dimx-1; xi>=0; xi--) {
362  *sptr=temp_roundf(g*img->m[pi][yi][xi][fi]);
363  if(*sptr>smax) smax=*sptr; else if(*sptr<smin) smin=*sptr;
364  sptr++;
365  }
366  } else {
367  for(pi=img->dimz-1; pi>=0; pi--)
368  for(yi=img->dimy-1; yi>=0; yi--)
369  for(xi=img->dimx-1; xi>=0; xi--) {
370  *sptr=temp_roundf(g*img->m[pi][yi][xi][fi]);
371  if(*sptr>smax) smax=*sptr; else if(*sptr<smin) smin=*sptr;
372  sptr++;
373  }
374  }
375  /* Change byte order if necessary */
376  little=little_endian();
377  if(little!=dsr.little)
378  swabip(sdata, pxlNr*sizeof(short int));
379  /* Write image data */
380  if(fwrite(sdata, 2, pxlNr, fp) != pxlNr) {
382  free(sdata); fclose(fp);
383  return 15;
384  }
385  }
386  /* Done writing */
387  fclose(fp);
388  free(sdata);
389 
390  if(IMG_TEST) printf("smin=%d smax=%d\n", smin, smax);
391 
392  /* Set header glmin & glmax */
393  dsr.dime.glmin=smin; dsr.dime.glmax=smax;
394 
395  /* Write Analyze header */
396  ret=anaWriteHeader(hdrfile, &dsr);
397  if(ret) {
399  return 21;
400  }
401  imgSetStatus(img, STATUS_OK);
402  return 0;
403 }
404 /*****************************************************************************/
405 
406 /*****************************************************************************/
417 int imgReadAnalyzeHeader(const char *dbname, IMG *img) {
418  char hdrfile[FILENAME_MAX], siffile[FILENAME_MAX];
419  ANALYZE_DSR ana_header;
420  SIF sif;
421  double f;
422  int ret;
423 
424  if(IMG_TEST) printf("\nimgReadAnalyzeHeader(%s, *img)\n", dbname);
425 
426  /* Check the input */
427  if(img==NULL) return STATUS_FAULT;
428  if(img->status!=IMG_STATUS_INITIALIZED) return STATUS_FAULT;
430  if(dbname==NULL) return STATUS_FAULT;
431 
432  /* Determine the names of hdr and sif files */
433  ret=anaDatabaseExists(dbname, hdrfile, NULL, siffile);
434  if(ret==0) return STATUS_NOFILE;
435 
436  /* Read Analyze header file */
437  ret=anaReadHeader(hdrfile, &ana_header);
438  if(ret!=0) {
439  if(IMG_TEST>1) printf("anaReadHeader() return value := %d\n", ret);
440  if(ret==1) return STATUS_FAULT;
441  else if(ret==2) return STATUS_NOHEADERFILE;
442  else return STATUS_UNSUPPORTED;
443  return(STATUS_FAULT);
444  }
445  /* and set IMG contents */
446  ret=imgGetAnalyzeHeader(img, &ana_header);
447  if(ret!=0) {
448  imgSetStatus(img, ret);
449  return(ret);
450  }
451 
452  /* If SIF does not exist, then that's it */
453  if(!siffile[0]) {
454  imgSetStatus(img, STATUS_OK);
455  return STATUS_OK;
456  }
457 
458  /* SIF is available, so read that too */
459  sifInit(&sif); ret=0;
460  if(sifRead(siffile, &sif)!=0) return STATUS_OK;
461  /* Copy scan time */
462  img->scanStart=sif.scantime;
463  /* Study number, if not yet defined */
464  if(!img->studyNr[0] && strlen(sif.studynr)>1 )
465  strncpy(img->studyNr, sif.studynr, MAX_STUDYNR_LEN);
466  /* Isotope half-life, if not yet defined */
467  f=hlFromIsotope(sif.isotope_name);
468  if(img->isotopeHalflife<=0.0 && f>0.0) img->isotopeHalflife=60.0*f;
469  sifEmpty(&sif);
470 
471  return STATUS_OK;
472 }
473 /*****************************************************************************/
474 
475 /*****************************************************************************/
485  int dimNr, dimx, dimy, dimz=1, dimt=1, pxlNr=0;
486 
487  if(IMG_TEST) printf("\nimgGetAnalyzeHeader(*img, *dsr)\n");
488 
489  /* Check the input */
490 
491  if(img==NULL) return STATUS_FAULT;
493  return STATUS_FAULT;
495  if(h==NULL) return STATUS_FAULT;
496 
498 
499  /* Get the image dimensions from header */
500  dimNr=h->dime.dim[0];
501  if(dimNr<2) return STATUS_INVALIDHEADER;
502  dimx=h->dime.dim[1]; dimy=h->dime.dim[2];
503  if(dimNr>2) {dimz=h->dime.dim[3]; if(dimNr>3) dimt=h->dime.dim[4];}
504  pxlNr=dimx*dimy*dimz;
505  if(pxlNr<1) return STATUS_INVALIDHEADER;
506  img->dimx=dimx; img->dimy=dimy; img->dimz=dimz; img->dimt=dimt;
507 
508  /* Copy information from Analyze header */
509  img->type=IMG_TYPE_IMAGE;
510  strncpy(img->studyNr, h->hist.patient_id, MAX_STUDYNR_LEN);
511  strcpy(img->patientName, h->hist.patient_id);
512  img->sizex=h->dime.pixdim[1];
513  img->sizey=h->dime.pixdim[2];
514  img->sizez=h->dime.pixdim[3];
515  /*if(h->dime.funused2>1.E-5) img->zoom=h->dime.funused2;*/
516  if(h->dime.funused3>1.E-5) img->isotopeHalflife=h->dime.funused3;
517  if(h->little) img->_fileFormat=IMG_ANA_L; else img->_fileFormat=IMG_ANA;
518 
519  /* Decay correction */
520  if(strstr(h->hist.descrip, "Decay corrected.")!=NULL)
521  img->decayCorrected=1;
522  else if(strstr(h->hist.descrip, "No decay correction.")!=NULL)
523  img->decayCorrected=0;
524  else
525  img->decayCorrected=1;
526 
527  imgSetStatus(img, STATUS_OK);
528  return STATUS_OK;
529 }
530 /*****************************************************************************/
531 
532 /*****************************************************************************/
545 int imgSetAnalyzeHeader(IMG *img, const char *dbname, ANALYZE_DSR *dsr, float fmin, float fmax) {
546  struct tm *st;
547  char *cptr;
548  float g;
549 
550  if(IMG_TEST) printf("\nimgSetAnalyzeHeader(*img, *dsr)\n");
551 
552  /* Check the input */
553  if(img==NULL) return STATUS_FAULT;
555  return STATUS_FAULT;
557  if(dsr==NULL) return STATUS_FAULT;
558 
559  /* Byte order */
560  if(img->_fileFormat==IMG_ANA_L) dsr->little=1; else dsr->little=0;
561  /* Header key */
562  memset(&dsr->hk, 0, sizeof(ANALYZE_HEADER_KEY));
563  memset(&dsr->dime, 0, sizeof(ANALYZE_HEADER_IMGDIM));
564  memset(&dsr->hist, 0, sizeof(ANALYZE_HEADER_HISTORY));
565  dsr->hk.sizeof_hdr=348;
566  strcpy(dsr->hk.data_type, "");
567  cptr=strrchr(dbname, '/'); if(cptr==NULL) cptr=strrchr(dbname, '\\');
568  if(cptr!=NULL) cptr++; if(cptr==NULL) cptr=(char*)dbname;
569  strncpy(dsr->hk.db_name, cptr, 17);
570  dsr->hk.extents=16384;
571  dsr->hk.regular='r';
572  /* Image dimension */
573  dsr->dime.dim[0]=4;
574  dsr->dime.dim[1]=img->dimx;
575  dsr->dime.dim[2]=img->dimy;
576  dsr->dime.dim[3]=img->dimz;
577  dsr->dime.dim[4]=img->dimt;
579  dsr->dime.bitpix=16;
580  dsr->dime.pixdim[0]=0.0;
581  dsr->dime.pixdim[1]=img->sizex;
582  dsr->dime.pixdim[2]=img->sizey;
583  dsr->dime.pixdim[3]=img->sizez;
584  dsr->dime.pixdim[4]=0.0;
585  dsr->dime.funused1=0.0; /* Scale factor is set later */
586  /* dsr.dime.funused2=img->zoom; */ /* Reconstruction zoom */
587  dsr->dime.funused3=img->isotopeHalflife;
588  /* Data history */
589  if(img->decayCorrected==1) strcpy(dsr->hist.descrip, "Decay corrected.");
590  else strcpy(dsr->hist.descrip, "No decay correction.");
591  strncpy(dsr->hist.scannum, img->studyNr, 10);
592  st=localtime(&img->scanStart);
593  if(st!=NULL) {
594  strftime(dsr->hist.exp_date, 10, "%Y%m%d", st);
595  strftime(dsr->hist.exp_time, 10, "%H:%M:%S", st);
596  } else {
597  strcpy(dsr->hist.exp_date, "19000101");
598  strcpy(dsr->hist.exp_time, "00:00:00");
599  }
600  /* Determine and set scale factor and cal_min & cal_max */
601  if(fmin<fmax) {
602  dsr->dime.cal_min=fmin; dsr->dime.cal_max=fmax;
603  } else { /* not given in function call, try to find those here */
604  if(img->status==IMG_STATUS_OCCUPIED &&
605  imgMinMax(img, &dsr->dime.cal_min, &dsr->dime.cal_max)==0) {}
606  else return STATUS_FAULT;
607  }
608  if(fabs(dsr->dime.cal_min) > fabs(dsr->dime.cal_max)) g = fabs(dsr->dime.cal_min);
609  else g = fabs(dsr->dime.cal_max);
610  /* if(fabs(dsr->dime.cal_min)>fabs(dsr->dime.cal_max)) g=fabs(dsr->dime.cal_min); */
611  /* else g=fabs(dsr->dime.cal_max); */
612  if(g<1E-20) g=1.0; else g=32767./g; dsr->dime.funused1=1.0/g;
613  /* Set header glmin & glmax */
614  dsr->dime.glmin=temp_roundf(fmin*g); dsr->dime.glmax=temp_roundf(fmax*g);
615  /* printf("glmin=%d\n", dsr->dime.glmin); */
616  /* printf("glmax=%d\n", dsr->dime.glmax); */
617 
618  imgSetStatus(img, STATUS_OK);
619  return STATUS_OK;
620 }
621 /*****************************************************************************/
622 
623 /*****************************************************************************/
632 int imgReadAnalyzeFirstFrame(const char *fname, IMG *img) {
633  int ret=0;
634 
635  if(IMG_TEST) printf("\nimgReadAnalyzeFirstFrame(%s, *img)\n", fname);
636  /* Check the input */
637  if(img==NULL) return STATUS_FAULT;
638  if(img->status!=IMG_STATUS_INITIALIZED) return STATUS_FAULT;
640  if(fname==NULL) return STATUS_FAULT;
641 
642  /* Read header information from file */
643  ret=imgReadAnalyzeHeader(fname, img); if(ret) return(ret);
644  if(IMG_TEST>3) imgInfo(img);
645 
646  /* Allocate memory for one frame */
647  img->dimt=1;
648  ret=imgAllocate(img, img->dimz, img->dimy, img->dimx, img->dimt);
649  if(ret) return STATUS_NOMEMORY;
650 
651  /* Read the first frame */
652  ret=imgReadAnalyzeFrame(fname, 1, img, 0); if(ret) return(ret);
653 
654  /* All went well */
655  imgSetStatus(img, STATUS_OK);
656  return STATUS_OK;
657 }
658 /*****************************************************************************/
659 
660 /*****************************************************************************/
677 int imgReadAnalyzeFrame(const char *fname, int frame_to_read, IMG *img, int frame_index) {
678  FILE *fp;
679  int ret, pi, xi, yi;
680  float *fdata=NULL, *fptr;
681  ANALYZE_DSR dsr;
682  char datfile[FILENAME_MAX], hdrfile[FILENAME_MAX], siffile[FILENAME_MAX];
683  SIF sif;
684 
685 
686  if(IMG_TEST) printf("\nimgReadAnalyzeFrame(%s, %d, *img, %d)\n",
687  fname, frame_to_read, frame_index);
688 
689  /* Check the input */
690  if(img==NULL) return STATUS_FAULT;
691  if(img->status!=IMG_STATUS_OCCUPIED) return STATUS_FAULT;
692  if(fname==NULL) return STATUS_FAULT;
693  if(frame_index<0 || frame_index>img->dimt-1) return STATUS_FAULT;
694  if(frame_to_read<1) return STATUS_FAULT;
696 
697  /* Determine the names of hdr, data and sif files */
698  ret=anaDatabaseExists(fname, hdrfile, datfile, siffile);
699  if(ret==0) return STATUS_NOFILE;
700 
701  /* Read Analyze header file */
702  ret=anaReadHeader(hdrfile, &dsr);
703  if(ret!=0) {
704  if(ret==1) return STATUS_FAULT;
705  else if(ret==2) return STATUS_NOHEADERFILE;
706  else return STATUS_UNSUPPORTED;
707  return(STATUS_FAULT);
708  }
709 
710  /* Open image datafile */
711  if(IMG_TEST>2) fprintf(stdout, "reading image data %s\n", datfile);
712  if((fp=fopen(datfile, "rb")) == NULL) return STATUS_NOIMGDATA;
713 
714  /* Allocate memory for one image frame */
715  fdata=malloc(img->dimx*img->dimy*img->dimz*sizeof(float));
716  if(fdata==NULL) {fclose(fp); return STATUS_NOMEMORY;}
717 
718  /* Read the required image frame */
719  fptr=fdata;
720  ret=anaReadImagedata(fp, &dsr, frame_to_read, fptr);
721  fclose(fp);
722  if(ret==3) {free(fdata); return STATUS_NOMATRIX;} /* no more frames */
723  if(ret!=0) {free(fdata); return STATUS_UNSUPPORTED;}
724 
725  /* Copy pixel values to IMG */
726  fptr=fdata;
727  if(anaFlipping()==0) { /* no flipping in z-direction */
728  for(pi=0; pi<img->dimz; pi++)
729  for(yi=img->dimy-1; yi>=0; yi--)
730  for(xi=img->dimx-1; xi>=0; xi--)
731  img->m[pi][yi][xi][frame_index]=*fptr++;
732  } else {
733  for(pi=img->dimz-1; pi>=0; pi--)
734  for(yi=img->dimy-1; yi>=0; yi--)
735  for(xi=img->dimx-1; xi>=0; xi--)
736  img->m[pi][yi][xi][frame_index]=*fptr++;
737  }
738  free(fdata);
739 
740  imgSetStatus(img, STATUS_OK); /* If the rest is failed, no problem */
741 
742  /*
743  * Try to read frame time information from SIF file
744  */
745  sifInit(&sif);
746  if(sifRead(siffile, &sif)!=0) return STATUS_OK;
747  /* Frame information */
748  if(sif.frameNr>=frame_to_read) {
749  img->start[frame_index]=sif.x1[frame_to_read-1];
750  img->end[frame_index]=sif.x2[frame_to_read-1];
751  img->mid[frame_index]=0.5*(img->start[frame_index]+img->end[frame_index]);
752  img->prompts[frame_index]=sif.prompts[frame_to_read-1];
753  img->randoms[frame_index]=sif.randoms[frame_to_read-1];
754  }
755  sifEmpty(&sif);
756 
757  return STATUS_OK;
758 }
759 /*****************************************************************************/
760 
761 /*****************************************************************************/
784 int imgWriteAnalyzeFrame(const char *dbname, int frame_to_write, IMG *img, int frame_index, float fmin, float fmax) {
785  IMG test_img;
786  int ret=0, pxlNr, zi, xi, yi, little;
787  FILE *fp;
788  short int *sdata=NULL, *sptr;
789  char datfile[FILENAME_MAX], hdrfile[FILENAME_MAX], siffile[FILENAME_MAX];
790  ANALYZE_DSR dsr;
791  float scale_factor=1.0;
792 
793 
794  if(IMG_TEST) printf("\nimgWriteAnalyzeFrame(%s, %d, *img, %d, %g, %g)\n",
795  dbname, frame_to_write, frame_index, fmin, fmax);
796 
797  /*
798  * Check the input
799  */
800  if(dbname==NULL) return STATUS_FAULT;
801  if(img==NULL) return STATUS_FAULT;
802  if(img->status!=IMG_STATUS_OCCUPIED) return STATUS_FAULT;
803  if(frame_to_write<0) return STATUS_FAULT;
804  if(frame_index<0 || frame_index>=img->dimt) return STATUS_FAULT;
805  if(img->_fileFormat!=IMG_ANA_L && img->_fileFormat!=IMG_ANA) return STATUS_FAULT;
806 
807  /*
808  * If database does not exist, then create it with new header,
809  * and if it does exist, then read and check header information.
810  * Create or edit header to contain correct frame nr.
811  * Determine the global scaling factor.
812  */
813  imgInit(&test_img);
814  if(anaDatabaseExists(dbname, hdrfile, datfile, siffile)==0) { /* not existing */
815 
816  /* Create database filenames */
817  sprintf(hdrfile, "%s.hdr", dbname);
818  sprintf(datfile, "%s.img", dbname);
819  sprintf(siffile, "%s.sif", dbname);
820 
821  /* Set main header */
822  imgSetAnalyzeHeader(img, dbname, &dsr, fmin, fmax);
823  if(frame_to_write==0) frame_to_write=1;
824  dsr.dime.dim[4]=frame_to_write;
825  scale_factor=dsr.dime.funused1;
826  if(fabs(scale_factor)>1.0E-20) scale_factor=1.0/scale_factor;
827 
828  /* Write Analyze header */
829  ret=anaWriteHeader(hdrfile, &dsr); if(ret && IMG_TEST) printf("anaWriteHeader() := %d\n", ret);
830  if(ret) return STATUS_CANTWRITEHEADERFILE;
831 
832  /* Remove datafile if necessary */
833  if(access(datfile, 0) != -1) remove(datfile);
834 
835  } else { /* database does exist */
836 
837  /* Read header information for checking */
838  ret=imgReadAnalyzeHeader(dbname, &test_img); if(ret!=0) return ret;
839  /* Check that file format is the same */
840  if(img->_fileFormat!=test_img._fileFormat || img->type!=test_img.type)
841  return STATUS_WRONGFILETYPE;
842  /* Check that matrix sizes are the same */
843  if(img->dimz!=test_img.dimz || img->dimx!=test_img.dimx ||
844  img->dimy!=test_img.dimy)
845  return STATUS_VARMATSIZE;
846  imgEmpty(&test_img);
847 
848  /* Read the header, set new frame number, and write it back */
849  /* Get also the scale factor */
850  if((ret=anaReadHeader(hdrfile, &dsr))!=0) return STATUS_NOMAINHEADER;
851  scale_factor=1.0/dsr.dime.funused1;
852  if(frame_to_write==0) frame_to_write=dsr.dime.dim[4]+1;
853  if(dsr.dime.dim[4]<frame_to_write) {
854  if(dsr.dime.dim[4]+1<frame_to_write) return STATUS_MISSINGMATRIX;
855  dsr.dime.dim[4]=frame_to_write;
856  }
857  if((ret=anaWriteHeader(hdrfile, &dsr))!=0) return STATUS_NOWRITEPERM;
858  }
859  if(IMG_TEST>2) {
860  printf("frame_to_write := %d\n", frame_to_write);
861  printf("hdrfile := %s\n", hdrfile);
862  printf("datfile := %s\n", datfile);
863  printf("siffile := %s\n", siffile);
864  }
865 
866  /* Allocate memory for matrix short int data (one plane) */
867  pxlNr=img->dimx*img->dimy;
868  sdata=(short int*)malloc(pxlNr*sizeof(short int));
869  if(sdata==NULL) return STATUS_NOMEMORY;
870 
871  /* Open datafile, not removing possible old contents */
872  if(frame_to_write==1) fp=fopen(datfile, "wb"); else fp=fopen(datfile, "r+b");
873  if(fp==NULL) {free(sdata); return STATUS_CANTWRITEIMGFILE;}
874  /* Move file pointer to the place of current frame */
875  if(fseek(fp, (frame_to_write-1)*pxlNr*img->dimz*sizeof(short int), SEEK_SET)!=0) {
876  free(sdata); fclose(fp); return STATUS_MISSINGMATRIX;}
877  little=little_endian();
878  /* Copy, scale and write data plane-by-plane */
879  if(anaFlipping()==0) {
880  for(zi=0; zi<img->dimz; zi++) {
881  sptr=sdata; /*printf("plane := %d\n scale_factor := %g\n", zi+1, scale_factor);*/
882  for(yi=img->dimy-1; yi>=0; yi--) for(xi=img->dimx-1; xi>=0; xi--) {
883  *sptr=temp_roundf(scale_factor*img->m[zi][yi][xi][frame_index]); sptr++;
884  }
885  /* Change byte order if necessary */
886  sptr=sdata; if(little!=dsr.little) swabip(sptr, pxlNr*sizeof(short int));
887  /* Write image data */
888  sptr=sdata;
889  if(fwrite(sptr, sizeof(short int), pxlNr, fp) != pxlNr) {
890  free(sdata); fclose(fp); return STATUS_CANTWRITEIMGFILE;
891  }
892  }
893  } else {
894  for(zi=img->dimz-1; zi>=0; zi--) {
895  sptr=sdata;
896  for(yi=img->dimy-1; yi>=0; yi--) for(xi=img->dimx-1; xi>=0; xi--) {
897  *sptr=temp_roundf(scale_factor*img->m[zi][yi][xi][frame_index]); sptr++;
898  }
899  /* Change byte order if necessary */
900  sptr=sdata; if(little!=dsr.little) swabip(sptr, pxlNr*sizeof(short int));
901  /* Write image data */
902  sptr=sdata;
903  if(fwrite(sptr, sizeof(short int), pxlNr, fp) != pxlNr) {
904  free(sdata); fclose(fp); return STATUS_CANTWRITEIMGFILE;
905  }
906  }
907  }
908  free(sdata);
909  fclose(fp);
910 
911  return STATUS_OK;
912 }
913 /*****************************************************************************/
914 
915 /*****************************************************************************/
int anaExists(const char *dbname)
Definition: analyze.c:75
time_t scantime
Definition: sif.h:38
int imgAllocate(IMG *image, int planes, int rows, int columns, int frames)
Definition: img.c:285
int anaWriteHeader(char *filename, ANALYZE_DSR *h)
Definition: analyze.c:209
void imgEmpty(IMG *image)
Definition: img.c:216
unsigned short int dimz
Definition: img.h:265
void sifInit(SIF *data)
Definition: sif.c:61
Definition: img.h:156
char patient_id[10]
Definition: analyze.h:85
char db_name[18]
Definition: analyze.h:46
ANALYZE_HEADER_HISTORY hist
Definition: analyze.h:102
float sizey
Definition: img.h:210
short int datatype
Definition: analyze.h:62
float * end
Definition: img.h:292
int anaFlipping()
Definition: analyze.c:545
unsigned short int dimx
Definition: img.h:261
int anaReadHeader(char *filename, ANALYZE_DSR *h)
Definition: analyze.c:102
int imgReadAnalyzeFrame(const char *fname, int frame_to_read, IMG *img, int frame_index)
Definition: img_ana.c:677
char patientName[32]
Definition: img.h:176
int imgWriteAnalyze(const char *dbname, IMG *img)
Definition: img_ana.c:256
float * mid
Definition: img.h:294
int frameNr
Definition: sif.h:40
char status
Definition: img.h:164
float **** m
Definition: img.h:274
double * prompts
Definition: sif.h:54
#define IMG_STATUS_OCCUPIED
Definition: img.h:73
float * randoms
Definition: img.h:308
short int dim[8]
Definition: analyze.h:54
int imgSetAnalyzeHeader(IMG *img, const char *dbname, ANALYZE_DSR *dsr, float fmin, float fmax)
Definition: img_ana.c:545
#define IMG_ANA_L
Definition: img.h:90
int anaPrintHeader(ANALYZE_DSR *h, FILE *fp)
Definition: analyze.c:307
float sizez
Definition: img.h:212
Definition: img.h:118
char data_type[10]
Definition: analyze.h:45
int little
Definition: analyze.h:104
double * randoms
Definition: sif.h:56
int sifRead(char *filename, SIF *data)
Definition: sifio.c:68
int imgReadAnalyze(const char *dbname, IMG *img)
Definition: img_ana.c:86
short int bitpix
Definition: analyze.h:63
#define IMG_STATUS_INITIALIZED
Definition: img.h:72
Definition: sif.h:36
double * x2
Definition: sif.h:52
char studynr[11]
Definition: sif.h:46
#define IMG_ANA
Definition: img.h:89
float isotopeHalflife
Definition: img.h:182
int anaDatabaseExists(const char *dbname, char *hdrfile, char *imgfile, char *siffile)
Definition: analyze.c:619
void imgInit(IMG *image)
Definition: img.c:163
int imgReadAnalyzeFirstFrame(const char *fname, IMG *img)
Definition: img_ana.c:632
int anaReadImagedata(FILE *fp, ANALYZE_DSR *h, int frame, float *data)
Definition: analyze.c:381
#define IMG_TYPE_IMAGE
Definition: img.h:80
#define ANALYZE_DT_SIGNED_SHORT
Definition: analyze.h:33
int _fileFormat
Definition: img.h:229
float sizex
Definition: img.h:208
char studyNr[MAX_STUDYNR_LEN+1]
Definition: img.h:174
int imgReadAnalyzeHeader(const char *dbname, IMG *img)
Definition: img_ana.c:417
char decayCorrected
Definition: img.h:184
double * x1
Definition: sif.h:50
int IMG_TEST
Definition: img.h:128
int imgWriteAnalyzeFrame(const char *dbname, int frame_to_write, IMG *img, int frame_index, float fmin, float fmax)
Definition: img_ana.c:784
time_t scanStart
Definition: img.h:186
char isotope_name[8]
Definition: sif.h:48
ANALYZE_HEADER_IMGDIM dime
Definition: analyze.h:101
int * planeNumber
Definition: img.h:284
float * start
Definition: img.h:290
unsigned short int dimy
Definition: img.h:263
unsigned short int dimt
Definition: img.h:259
void imgInfo(IMG *image)
Definition: img.c:414
ANALYZE_HEADER_KEY hk
Definition: analyze.h:100
float * prompts
Definition: img.h:306
void sifEmpty(SIF *data)
Definition: sif.c:74
int imgGetAnalyzeHeader(IMG *img, ANALYZE_DSR *h)
Definition: img_ana.c:484
char type
Definition: img.h:198
void imgSetStatus(IMG *img, int status_index)
Definition: img.c:399
int imgMinMax(IMG *img, float *minvalue, float *maxvalue)
Definition: imgmax.c:115