/*! * Fill IMG struct header information from Analyze 7.5 database files. * SIF file is read if available. Information concerning separate frames * or planes is not filled though. * * @param dbname name of Analyze database, may contain filename extension * @param img pointer to the initiated IMG data * @return errstatus, which is STATUS_OK (0) when call was successful, * and >0 in case of an error. */ int imgReadAnalyzeHeader(const char *dbname, IMG *img) { char hdrfile[FILENAME_MAX], siffile[FILENAME_MAX]; ANALYZE_DSR ana_header; SIF sif; double f; int ret; if(IMG_TEST) printf("\nimgReadAnalyzeHeader(%s, *img)\n", dbname); /* Check the input */ if(img==NULL) return STATUS_FAULT; if(img->status!=IMG_STATUS_INITIALIZED) return STATUS_FAULT; imgSetStatus(img, STATUS_FAULT); if(dbname==NULL) return STATUS_FAULT; /* Determine the names of hdr and sif files */ ret=anaDatabaseExists(dbname, hdrfile, NULL, siffile); if(ret==0) return STATUS_NOFILE; /* Read Analyze header file */ ret=anaReadHeader(hdrfile, &ana_header); if(ret!=0) { if(IMG_TEST>1) printf("anaReadHeader() return value := %d\n", ret); if(ret==1) return STATUS_FAULT; else if(ret==2) return STATUS_NOHEADERFILE; else return STATUS_UNSUPPORTED; return(STATUS_FAULT); } /* and set IMG contents */ ret=imgGetAnalyzeHeader(img, &ana_header); if(ret!=0) { imgSetStatus(img, ret); return(ret); } /* If SIF does not exist, then that's it */ if(!siffile[0]) { imgSetStatus(img, STATUS_OK); return STATUS_OK; } /* SIF is available, so read that too */ sifInit(&sif); ret=0; if(sifRead(siffile, &sif)!=0) return STATUS_OK; /* Copy scan time */ img->scanStart=sif.scantime; /* Study number, if not yet defined */ if(!img->studyNr[0] && strlen(sif.studynr)>1 ) strncpy(img->studyNr, sif.studynr, MAX_STUDYNR_LEN); /* Isotope half-life, if not yet defined */ f=hlFromIsotope(sif.isotope_name); if(img->isotopeHalflife<=0.0 && f>0.0) img->isotopeHalflife=60.0*f; sifEmpty(&sif); return STATUS_OK; }
/*! * Write one PET frame from IMG data struct into Analyze 7.5 database file. * This function can be called repeatedly to write all frames one at a time * to conserve memory. This function does not write SIF. * * @param dbname name of 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 * @param frame_to_write PET 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 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 * @param img pointer to the IMG data struct * @param frame_index IMG frame index (0..dimt-1) which will be written * @param fmin minimum pixel value in all frames that will be written; * used only when writing the first frame * @param fmax maximum pixel value in all frames that will be written; * used only when writing the first frame * @return errstatus, which is STATUS_OK (0) when call was successful, * and >0 in case of an error. */ int imgWriteAnalyzeFrame( const char *dbname, int frame_to_write, IMG *img, int frame_index, float fmin, float fmax ) { IMG test_img; int ret=0, pxlNr, zi, xi, yi, little; FILE *fp; short int *sdata=NULL, *sptr; char datfile[FILENAME_MAX], hdrfile[FILENAME_MAX], siffile[FILENAME_MAX]; ANALYZE_DSR dsr; float scale_factor=1.0; if(IMG_TEST) printf("\nimgWriteAnalyzeFrame(%s, %d, *img, %d, %g, %g)\n", dbname, frame_to_write, frame_index, fmin, fmax); /* * Check the input */ if(dbname==NULL) return STATUS_FAULT; if(img==NULL) return STATUS_FAULT; if(img->status!=IMG_STATUS_OCCUPIED) return STATUS_FAULT; if(frame_to_write<0) return STATUS_FAULT; if(frame_index<0 || frame_index>=img->dimt) return STATUS_FAULT; if(img->_fileFormat!=IMG_ANA_L && img->_fileFormat!=IMG_ANA) return STATUS_FAULT; /* * If database does not exist, then create it with new header, * and if it does exist, then read and check header information. * Create or edit header to contain correct frame nr. * Determine the global scaling factor. */ imgInit(&test_img); if(anaDatabaseExists(dbname, hdrfile, datfile, siffile)==0) { // not existing /* Create database filenames */ sprintf(hdrfile, "%s.hdr", dbname); sprintf(datfile, "%s.img", dbname); sprintf(siffile, "%s.sif", dbname); /* Set main header */ imgSetAnalyzeHeader(img, dbname, &dsr, fmin, fmax); if(frame_to_write==0) frame_to_write=1; dsr.dime.dim[4]=frame_to_write; scale_factor=dsr.dime.funused1; if(fabs(scale_factor)>1.0E-20) scale_factor=1.0/scale_factor; /* Write Analyze header */ ret=anaWriteHeader(hdrfile, &dsr); if(ret && IMG_TEST) printf("anaWriteHeader() := %d\n", ret); if(ret) return STATUS_CANTWRITEHEADERFILE; /* Remove datafile if necessary */ if(access(datfile, 0) != -1) remove(datfile); } else { /* database does exist */ /* Read header information for checking */ ret=imgReadAnalyzeHeader(dbname, &test_img); if(ret!=0) {imgEmpty(&test_img); return ret;} /* Check that file format is the same */ if(img->_fileFormat!=test_img._fileFormat || img->type!=test_img.type) { imgEmpty(&test_img); return STATUS_WRONGFILETYPE;} /* Check that matrix sizes are the same */ if(img->dimz!=test_img.dimz || img->dimx!=test_img.dimx || img->dimy!=test_img.dimy) { imgEmpty(&test_img); return STATUS_VARMATSIZE;} imgEmpty(&test_img); /* Read the header, set new frame number, and write it back */ /* Get also the scale factor */ if((ret=anaReadHeader(hdrfile, &dsr))!=0) return STATUS_NOMAINHEADER; scale_factor=1.0/dsr.dime.funused1; if(frame_to_write==0) frame_to_write=dsr.dime.dim[4]+1; if(dsr.dime.dim[4]<frame_to_write) { if(dsr.dime.dim[4]+1<frame_to_write) return STATUS_MISSINGMATRIX; dsr.dime.dim[4]=frame_to_write; } if((ret=anaWriteHeader(hdrfile, &dsr))!=0) return STATUS_NOWRITEPERM; } if(IMG_TEST>2) { printf("frame_to_write := %d\n", frame_to_write); printf("hdrfile := %s\n", hdrfile); printf("datfile := %s\n", datfile); printf("siffile := %s\n", siffile); } /* Allocate memory for matrix short int data (one plane) */ pxlNr=img->dimx*img->dimy; sdata=(short int*)malloc(pxlNr*sizeof(short int)); if(sdata==NULL) return STATUS_NOMEMORY; /* Open datafile, not removing possible old contents */ if(frame_to_write==1) fp=fopen(datfile, "wb"); else fp=fopen(datfile, "r+b"); if(fp==NULL) {free(sdata); return STATUS_CANTWRITEIMGFILE;} /* Move file pointer to the place of current frame */ if(fseek(fp, (frame_to_write-1)*pxlNr*img->dimz*sizeof(short int), SEEK_SET)!=0) { free(sdata); fclose(fp); return STATUS_MISSINGMATRIX;} little=little_endian(); /* Copy, scale and write data plane-by-plane */ if(anaFlipping()==0) { for(zi=0; zi<img->dimz; zi++) { sptr=sdata; /*printf("plane := %d\n scale_factor := %g\n", zi+1, scale_factor);*/ for(yi=img->dimy-1; yi>=0; yi--) for(xi=img->dimx-1; xi>=0; xi--) { *sptr=temp_roundf(scale_factor*img->m[zi][yi][xi][frame_index]); sptr++; } /* Change byte order if necessary */ sptr=sdata; if(little!=dsr.little) swabip(sptr, pxlNr*sizeof(short int)); /* Write image data */ sptr=sdata; if(fwrite(sptr, sizeof(short int), pxlNr, fp) != pxlNr) { free(sdata); fclose(fp); return STATUS_CANTWRITEIMGFILE; } } } else { for(zi=img->dimz-1; zi>=0; zi--) { sptr=sdata; for(yi=img->dimy-1; yi>=0; yi--) for(xi=img->dimx-1; xi>=0; xi--) { *sptr=temp_roundf(scale_factor*img->m[zi][yi][xi][frame_index]); sptr++; } /* Change byte order if necessary */ sptr=sdata; if(little!=dsr.little) swabip(sptr, pxlNr*sizeof(short int)); /* Write image data */ sptr=sdata; if(fwrite(sptr, sizeof(short int), pxlNr, fp) != pxlNr) { free(sdata); fclose(fp); return STATUS_CANTWRITEIMGFILE; } } } free(sdata); fclose(fp); return STATUS_OK; }
/*! * Read a specified frame from an Analyze 7.5 database into preallocated IMG * data structure. Analyze database consists of two or three files in the same * directory: fname.hdr, fname.img, and optionally fname.sif. * 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. * If frame does not exist, then and only then STATUS_NOMATRIX is returned. * * @param fname name of Analyze database from which IMG contents will be read * @param frame_to_read frame which will be read [1..frameNr] * @param img pointer to the IMG data. Place for the frame must be preallocated * @param frame_index IMG frame index [0..dimt-1] where data will be placed * @return errstatus, which is STATUS_OK (0) when call was successful, * and >0 in case of an error. */ int imgReadAnalyzeFrame( const char *fname, int frame_to_read, IMG *img, int frame_index ) { FILE *fp; int ret, pi, xi, yi; float *fdata=NULL, *fptr; ANALYZE_DSR dsr; char datfile[FILENAME_MAX], hdrfile[FILENAME_MAX], siffile[FILENAME_MAX]; SIF sif; if(IMG_TEST) printf("\nimgReadAnalyzeFrame(%s, %d, *img, %d)\n", fname, frame_to_read, frame_index); /* Check the input */ if(img==NULL) return STATUS_FAULT; if(img->status!=IMG_STATUS_OCCUPIED) return STATUS_FAULT; if(fname==NULL) return STATUS_FAULT; if(frame_index<0 || frame_index>img->dimt-1) return STATUS_FAULT; if(frame_to_read<1) return STATUS_FAULT; imgSetStatus(img, STATUS_FAULT); /* Determine the names of hdr, data and sif files */ ret=anaDatabaseExists(fname, hdrfile, datfile, siffile); if(ret==0) return STATUS_NOFILE; /* Read Analyze header file */ ret=anaReadHeader(hdrfile, &dsr); if(ret!=0) { if(ret==1) return STATUS_FAULT; else if(ret==2) return STATUS_NOHEADERFILE; else return STATUS_UNSUPPORTED; return(STATUS_FAULT); } /* Open image datafile */ if(IMG_TEST>2) fprintf(stdout, "reading image data %s\n", datfile); if((fp=fopen(datfile, "rb")) == NULL) return STATUS_NOIMGDATA; /* Allocate memory for one image frame */ fdata=malloc(img->dimx*img->dimy*img->dimz*sizeof(float)); if(fdata==NULL) {fclose(fp); return STATUS_NOMEMORY;} /* Read the required image frame */ fptr=fdata; ret=anaReadImagedata(fp, &dsr, frame_to_read, fptr); fclose(fp); if(ret==3) {free(fdata); return STATUS_NOMATRIX;} /* no more frames */ if(ret!=0) {free(fdata); return STATUS_UNSUPPORTED;} /* Copy pixel values to IMG */ fptr=fdata; if(anaFlipping()==0) { /* no flipping in z-direction */ for(pi=0; pi<img->dimz; pi++) for(yi=img->dimy-1; yi>=0; yi--) for(xi=img->dimx-1; xi>=0; xi--) img->m[pi][yi][xi][frame_index]=*fptr++; } else { for(pi=img->dimz-1; pi>=0; pi--) for(yi=img->dimy-1; yi>=0; yi--) for(xi=img->dimx-1; xi>=0; xi--) img->m[pi][yi][xi][frame_index]=*fptr++; } free(fdata); /* Set decay correction factor to zero */ img->decayCorrFactor[frame_index]=0.0; imgSetStatus(img, STATUS_OK); /* If the rest is failed, no problem */ /* * Try to read frame time information from SIF file */ sifInit(&sif); if(sifRead(siffile, &sif)!=0) return STATUS_OK; /* Frame information */ if(sif.frameNr>=frame_to_read) { img->start[frame_index]=sif.x1[frame_to_read-1]; img->end[frame_index]=sif.x2[frame_to_read-1]; img->mid[frame_index]=0.5*(img->start[frame_index]+img->end[frame_index]); img->prompts[frame_index]=sif.prompts[frame_to_read-1]; img->randoms[frame_index]=sif.randoms[frame_to_read-1]; } sifEmpty(&sif); return STATUS_OK; }
/*! * Read Analyze 7.5 image. * Analyze database name must be given with path. Image and header files * with .img and .hdr extensions must exist. Also SIF file with .sif * extension is used, if it exists. * anaFlipping() determines whether image is flipped in z-direction; * image is always flipped in x,y-directions. * * @param dbname Analyze database name with path, with or without extension * @param img Pointer to initialized IMG structure * @return 0 if ok, and otherwise IMG status code; sets IMG->statmsg * in case of error. */ int imgReadAnalyze(const char *dbname, IMG *img) { FILE *fp; int ret, fi, pi, xi, yi; float *fdata=NULL, *fptr; ANALYZE_DSR dsr; char datfile[FILENAME_MAX], hdrfile[FILENAME_MAX], siffile[FILENAME_MAX]; int dimNr, dimx, dimy, dimz=1, dimt=1, pxlNr=0; SIF sif; if(IMG_TEST) printf("imgReadAnalyze(%s, *img)\n", dbname); /* Check the arguments */ imgSetStatus(img, STATUS_OK); if(img==NULL || img->status!=IMG_STATUS_INITIALIZED) { imgSetStatus(img, STATUS_FAULT); return(2);} if(dbname==NULL || !dbname[0]) {imgSetStatus(img, STATUS_FAULT); return(1);} /* Make the image and header filenames */ ret=anaExistsNew(dbname, hdrfile, datfile, siffile); if(ret==0) {imgSetStatus(img, STATUS_NOHEADERFILE); return(3);} if(ret==1 && IMG_TEST>0) printf("no SIF found for %s\n", dbname); /* Read Analyze header file */ ret=anaReadHeader(hdrfile, &dsr); if(ret) { if(ret==1) imgSetStatus(img, STATUS_FAULT); else if(ret==2) imgSetStatus(img, STATUS_NOHEADERFILE); else imgSetStatus(img, STATUS_UNSUPPORTED); return(3); } if(IMG_TEST) anaPrintHeader(&dsr, stdout); /* Open image datafile */ if(IMG_TEST) fprintf(stdout, "reading image data %s\n", datfile); if((fp=fopen(datfile, "rb")) == NULL) { imgSetStatus(img, STATUS_NOIMGDATA); return(5);} /* Prepare IMG for Analyze image */ /* Get the image dimensions from header */ dimNr=dsr.dime.dim[0]; if(dimNr<2) {fclose(fp); imgSetStatus(img, STATUS_INVALIDHEADER); return(4);} dimx=dsr.dime.dim[1]; dimy=dsr.dime.dim[2]; if(dimNr>2) {dimz=dsr.dime.dim[3]; if(dimNr>3) dimt=dsr.dime.dim[4];} pxlNr=dimx*dimy*dimz; if(pxlNr<1) {fclose(fp); imgSetStatus(img, STATUS_INVALIDHEADER); return(4);} /* Allocate memory for IMG */ ret=imgAllocate(img, dimz, dimy, dimx, dimt); if(ret) {fclose(fp); imgSetStatus(img, STATUS_NOMEMORY); return(11);} /* Copy information from Analyze header */ img->type=IMG_TYPE_IMAGE; strncpy(img->studyNr, dsr.hist.patient_id, MAX_STUDYNR_LEN); if(strcmp(img->studyNr, ".")==0) strcpy(img->studyNr, ""); strcpy(img->patientName, dsr.hist.patient_id); img->sizex=dsr.dime.pixdim[1]; img->sizey=dsr.dime.pixdim[2]; img->sizez=dsr.dime.pixdim[3]; /*if(dsr.dime.funused2>1.E-5) img->zoom=dsr.dime.funused2;*/ if(dsr.dime.funused3>1.E-5) img->isotopeHalflife=dsr.dime.funused3; for(pi=0; pi<dimz; pi++) img->planeNumber[pi]=pi+1; if(dsr.little) img->_fileFormat=IMG_ANA_L; else img->_fileFormat=IMG_ANA; /* Decay correction */ if(strstr(dsr.hist.descrip, "Decay corrected.")!=NULL) img->decayCorrection=IMG_DC_CORRECTED; else if(strstr(dsr.hist.descrip, "No decay correction.")!=NULL) img->decayCorrection=IMG_DC_NONCORRECTED; else img->decayCorrection=IMG_DC_CORRECTED; // just assumed so /* Allocate memory for one image frame */ fdata=malloc(pxlNr*sizeof(float)); if(fdata==NULL) {fclose(fp); imgSetStatus(img, STATUS_NOMEMORY); return(12);} /* Read one image frame at a time */ for(fi=0; fi<dimt; fi++) { fptr=fdata; ret=anaReadImagedata(fp, &dsr, fi+1, fptr); if(ret) { free(fdata); fclose(fp); imgSetStatus(img, STATUS_NOIMGDATA); return(7);} /* Copy pixel values to IMG */ fptr=fdata; if(anaFlipping()==0) { /* no flipping in z-direction */ for(pi=0; pi<img->dimz; pi++) for(yi=dimy-1; yi>=0; yi--) for(xi=dimx-1; xi>=0; xi--) img->m[pi][yi][xi][fi]=*fptr++; } else { for(pi=dimz-1; pi>=0; pi--) for(yi=dimy-1; yi>=0; yi--) for(xi=dimx-1; xi>=0; xi--) img->m[pi][yi][xi][fi]=*fptr++; } } /* next frame */ free(fdata); fclose(fp); /* Try to read frame time information from SIF file */ /* Check if SIF file is found */ if(siffile[0]) { if(IMG_TEST) printf("reading SIF file %s\n", siffile); if(access(siffile, 0) == -1) { if(IMG_TEST) printf(" No SIF file; therefore unknown frame times.\n"); return(0); } } /* If found, then read it */ sifInit(&sif); ret=sifRead(siffile, &sif); if(ret) {imgSetStatus(img, STATUS_NOSIFDATA); return(21);} /* Copy SIF contents */ ret=sif2img(&sif, img, 1, 1, 1, IMG_TEST-2); sifEmpty(&sif); if(ret!=0) {imgSetStatus(img, STATUS_WRONGSIFDATA); return(22);} return(0); }
/** Check if specified filename is a Analyze file. \return Returns 0 if it is not, 1 if it is, and both image and header is found, and 2, if sif file is found too. */ int anaExistsNew( /** Filename, either header file, image file, or base name without extensions. * this string is never modified. */ const char *filename, /** If filename refers to a Analyze file, then header filename will be written in this char pointer (space needs to allocated by caller); NULL if not needed. */ char *hdrfile, /** If filename refers to a Analyze file, then image filename will be written in this char pointer (space needs to allocated by caller); NULL if not needed. */ char *imgfile, /** If filename refers to a Analyze file, and if SIF exists, then SIF filename will be written in this char pointer (space needs to allocated by caller); NULL if not needed. */ char *siffile ) { char *cptr, basefile[FILENAME_MAX], temp[FILENAME_MAX]; ANALYZE_DSR h; int ret; if(filename==NULL || strlen(filename)==0) return(0); if(ANALYZE_TEST>1) printf("\nanaExistsNew(%s, *str, *str, *str)\n", filename); /* Construct the base file name wo extensions */ strcpy(basefile, filename); cptr=strrchr(basefile, '.'); if(cptr!=NULL) { if(strncasecmp(cptr, ".HDR", 4)==0 || strncasecmp(cptr, ".IMG", 4)==0 ) *cptr=(char)0; } cptr=strrchr(basefile, '.'); if(cptr!=NULL) { if(strncasecmp(cptr, ".IMG", 4)==0 ) *cptr=(char)0; } if(ANALYZE_TEST>2) printf("\n basefile := %s\n", basefile); /* Header file exists? */ strcpy(temp, basefile); strcat(temp, ".hdr"); if(access(temp, 0) == -1) { strcpy(temp, basefile); strcat(temp, ".img.hdr"); if(access(temp, 0) == -1) { if(ANALYZE_TEST) printf("\n hdr file not found or accessible.\n"); return(0); } } /* Is this Analyze header file? */ if((ret=anaReadHeader(temp, &h))!=0) { if(ANALYZE_TEST) { printf("\n %s was not identified as Analyze header file (%d).\n", temp, ret); } return(0); } /* Preserve header filename */ if(hdrfile!=NULL) strcpy(hdrfile, temp); /* Image file exists? */ strcpy(temp, basefile); strcat(temp, ".img"); if(access(temp, 0) == -1) { if(ANALYZE_TEST) printf("\n %s not found or accessible.\n", temp); return(0); } /* Preserve image filename */ if(imgfile!=NULL) strcpy(imgfile, temp); /* SIF exists? */ strcpy(temp, basefile); strcat(temp, ".sif"); if(access(temp, 0) == -1) { strcpy(temp, basefile); strcat(temp, ".img.sif"); if(access(temp, 0) == -1) { if(ANALYZE_TEST) printf("\n SIF not found or accessible.\n"); if(siffile!=NULL) strcpy(siffile, ""); return(1); // but otherwise ok } } /* Preserve SIF filename */ if(siffile!=NULL) strcpy(siffile, temp); return(2); }