/* medcorrect.c Last modified 2 April 2003 For brief usage, type "medcorrect". For more extensive help and code history, type "medcorrect --help" or see the strings usage_str and help_str below. See COMMENTS section at the end of source code for additional notes, todo lists, etc. TODO: 1) Pedestal - is it necessary? If so when? 2) Obliquity correction has been disabled, since a - I haven't tested it b - It's menu driven c - I don't anticipate SAXS folks needing it (I'm probably wrong) Note that although the structure oblique is passed to intcorr_int, intcorr_int only uses one of oblique's fields, namely oblique.satn_level, which I've alread made a separate variable (oblique is defined in objects.h). 3) Versions for Finger Lakes, Gruner 1K detector? Perhaps there will be a correct_base program that all of these other programs will link to (use argv[0] to set the defaults?) 4) Incorporate Gil's multi-image dezingering code. 5) Mention DEBUG flag in help string probably can define with gcc or make flag */ #include <math.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include "objects.h" #define MAX_FILENAME_SIZE 100 /* Apparently have to define constants this (rather than const int ...) way if needed for passing 2D arrays to a function (we're not doing that, however, since infilenames is now type char ** and uses the space allocated for argv, rather than allocating its own space as char [][MAX_FILENAME_SIZE]) */ /* change to 1 or issue -DDEBUG at gcc for lots of extra messages */ #ifndef DEBUG #define DEBUG 0 #endif #ifdef __GNUC__ const char usage_str[]=" Usage: medcorrect [i|id|d|di] -s[z] image_file(s) [-o output_filename] [-t int_correct_file] [-x x_distortion_file] [-b back_file(s)] [--help] ** At least two arguments are required: '-s[z]' and an image filename.** ** If present, [i|id|d|di] must come first. Other arguments in any order.**\n\n"; #else const char usage_str[]="Usage: medcorrect [i|id|d|di] -s[z] image_file(s) [-o output_filename]\n [-t int_correct_file] [-x x_distortion_file] [-b back_file(s)] \n [--help]\n See source medcorrect.c for more extensive documentation\n"; #endif #ifdef __GNUC__ const char help_str[]=" medcorrect.c: This program corrects x-ray image files taken by the medoptics detector, but can be easily adapted for other detectors. FEATURES: 1) The images may be dezingered, background subtracted, distortion and/or intensity corrected. Corrections are chosen by command line options. 2) The background images may also be dezingered. This is always done if more than one background image (eventually more than two will be allowed, but not now) 3) Command line substitution can be used to specificy multiple image files. See example (4) NOTE: Although the program allows complete flexibility, the proper correction order is determined when correction files are made (see TV6 command 'cath'). For the medoptics detector intensity correction file medi12b1.tif, this order is raw->dezing -> back sub -> intensity correct -> distortion correct. If using the intensity correction file moi12b1.tif, the order of intensity and distortion correction are swapped. Usage: medcorrect [i|id|d|di] -s[z] image_file(s) [-o output_filename] [-t int_correct_file] [-x x_distortion_file] [-b back_file(s)] [--help] At least two arguments are required: '-s[z]' and an image filename. If present, [i|id|d|di] must come first. Other arguments in any order. OPTIONS: i: intensity correction. uses default intensity correction unless -t is also present d: distortion correction. uses default files unless -x is also present NOTE 1: Correction is done in the order specificied. Make sure that the this order (id vs. di) matches the type of intensity correction file being used. (For the Medoptics decector, see C:\\perm\\README on the Medoptics computer). -t: explicitly name intensity correction file (see NOTE 2) -x: explicitly name only the x-distortion correction file. (see NOTE 2) The y-distortion file must have the same name but with 'y' in place of the final appearance of 'x' in the filename , e.g. medxbin1.tif & medybin1.tif -s[z] image_file(s): if more than one is specified, images are either combined and dezingered (if z is present) or processed sequentially. Current limit of 2 images for dezingering -b background file(s). If more than one is specified, images are combined and dezingered. -o output_file_name. If present, this takes precedence. If not present, then the output filename depends on the action. If multiple images are being corrected but NOT dezingered, then the name is generated from the input file by the insertion of \"_c\" before the extension (e.g. fish.tif -> fish_c.tif, fish -> fish_c). This is useful for correcting a whole sequence of images that do not need to be dezingered in a single command (see example below). If two images are being dezingered, the default name medcorr.out is used unless an explicit filename is specified. NOTE that medcorrect NEVER overwrites files. If the output filename it wants to already exists, medcorrect aborts with a message to that effect. --help: Print this help message and exit NOTE 2: If distortion or intensity correction files are not explicitly named: 1) Look for environment variable CCDCORR_FILES to determine directory in which to look for the correction files named in (default to /usr/local/lib). 2) Filenames found in the CCDCORR_FILES directory are SUPERCEDED by the contents of medcorrect.cfg, if found inthe local directory. This file is written whenever intensity and distortion correction are both performed Successfully opened correction filenames are saved to medcorrect.cfg which, if found in the working directory, supercedes the default files in /usr/local/lib. EXAMPLES: 1) Dezinger a pair of images: >medcorrect -sz image1.tif image2.tif -o image1z2.tif ** or using tcsh command line substitution ** >medcorrect -sz image[12].tif -o image1z2.tif 2) Dezinger two images and backgrounds and subtract the dezingered background from the dezingered image: >medcorrect -sz image1.tif image2.tif -o image1z2.tif -b b1.tif b2.tif ** or using tcsh command line substitution ** >medcorrect -sz image[12].tif -b b[12].tif -o image1z2.tif 3) The whole shabang (dezinger image & backs, then subtract background, then intensity and distortion correct). >medcorrect id -sz image[12].tif -b b[12].tif ** output stored in medcorr.out ** 4) Correct but don't dezinger many files at once. >medcorrect id -s images*.tif -b backround.tif Originally written by Sandor L. Barna Princeton University Physics Department Biophysics Group December 1993 Marian Szebenyi (CHESS) made many modifications, including pedestal, through 2003. Converted from text-menu/prompt to UNIX command-line-option style by Arthur Woll, March 2003 NOTE: The UNIX shell expands wildcard characters like *, ?, and [] before sending the command line to the program. See your sh or csh manual for details. Turbo C++ and Borland C++ expand wildcard characters if the file WILDARG.OBJ is linked with your program. See the manual for details. Almost all UNIX commands use a standard command-line format. This standard has carried over into other environments. A standard UNIX command has the form: command options file1 file1 file3 Please refer to TV6 (Gruner, Eikenberry and Tate) for more information on the correction procedures.\n"; #else const char help_str[]="medcorrect help string not available on this (non-GNU) system.\n See the source file or the file USAGE in the distribution directory for the full string (help_str[]).\n"; #endif const char insert[]="_c"; /* For automatic filename generation */ const char dot = '.'; /* Put insert[] just before dot */ const char default_outname[]="medcorr.out"; const char help_flag[]= "--help"; main(int argc, char *argv[]) { /* -------------------- DECLARATIONS -------------------- */ extern const char help_flag[]; /* extern const int MAX_FILENAME_SIZE; */ const int TV6_HEADER_BYTES = 4096; /* Header size for all of the correction files */ int bsub_flag = 0; int intens_flag = 0; int dist_flag = 0; int obliq_flag = 0; /* In case we want to introduce it... */ int dist_first = 0; int explicit_int = 0; int explicit_dist = 0; int explicit_outname = 0; int dezing_images = 0; /* started life as combine_images */ int dezing_back = 0; int max_images = 1; /* This is only used if either images or backgrounds will be dezingered. In that case this is the larger number of images to be dezingered. Right now we can only dezinger two -- see COMMENTS */ char *x_addr; int bfilen = 0; int infilen = 0; char dxfilename[MAX_FILENAME_SIZE]; char dyfilename[MAX_FILENAME_SIZE]; char intfilename[MAX_FILENAME_SIZE]; FILE *distx=NULL; FILE *disty=NULL; FILE *intens=NULL; float *dxcorr=NULL; float *dycorr=NULL; float *intcorr=NULL; float *tempbuf=NULL; /* Needed for intensity and distortion correction */ char **bfilenames; char **infilenames; FILE *bfile=NULL; FILE *infile=NULL; /* In main for checking existance & reading header & byte order. Also local in read_data for reading actual data */ unsigned short *indat=NULL; unsigned short *bdat=NULL; unsigned short *dat_ptr; /* Never to have its own allocation. */ unsigned short **image_stack = NULL; /* A 2-D array to be malloc'd and to hold multiple data arrays in the case of dezingering either the background or input files */ char outname[MAX_FILENAME_SIZE] = ""; unsigned short *outdat; char *header = NULL, *trailer = NULL; int header_bytes = 0, trailer_bytes = 0; int err = 0; /* Initialize to zero - be optimistic! */ int length; int tiff_format; int swizdetect_flag; int *swizdetect; int swizzle=0; /*--- swizzle = 0: little endian/PC byte order swizzle = 1: big endian as for SGI ----*/ register i; const char cffilename[] = "medcorrect.cfg"; FILE *config; char cfilesdir[MAX_FILENAME_SIZE]; char *corrfiles; char tempname[MAX_FILENAME_SIZE]; char suffix[8]; char hold_file[3][MAX_FILENAME_SIZE]; char yesno[1]; char response[2]; int pedestal = 0; int saturated; struct oblparams oblique; char *program_name; void usage(); void help(); void my_abort(char message[]); void gen_outname(char outfilename[],int outchars, char**filenames, int nfiles); int tiff_big_endian(FILE *); /* Determines tiff file byte order */ void read_data(char infilename[],char *head, int headn, unsigned short *data, int datan, char *trail, int trailn); int correct_data(int bsub_flag, int intens_flag, int dist_flag, int obliq_flag, int dist_first, int det_size, int pedestal, unsigned short *bdat, unsigned short *indat, float *intcorr, float *dxcorr, float *dycorr, float *tempbuf, struct oblparams oblique); void save_corrected(char outname[], char *head, int headn, unsigned short *data, int datan, char *trail, int trailn); /* ------------------------ BEGIN -------------------- */ printf("MedOptics CCD file correction program\n"); printf("Sandor Barna (Princeton), Marian Szebenyi (CHESS), "); printf("Arthur Woll (CHESS)\n"); /* ----------------- DETECTOR PARAMETER INITIALIZATION ----------------- */ /* Check default location for correction files */ corrfiles = getenv ("CCDCORR_FILES"); if (corrfiles != NULL) strcpy (cfilesdir,corrfiles); else strcpy (cfilesdir,"/usr/local/lib/"); /* MEDOPTICS PARAMETERS */ det_size = 1024; header_bytes = 8; trailer_bytes = 190; swizdetect_flag = 1; tiff_format = 1; /* If 0, swizzle must be chosen here. PC byte order is the default, and corresponds to swizzle = 0. */ /* dist_first = 0; if dist_first = 1; then use MOI12B1.TIF or MOI18B1.TIF */ strcpy (suffix,".tif"); oblique.wdpix = 0.00472; oblique.hgtpix = 0.00472; oblique.satn_level = 16384; saturated = 16384; strcpy (phos_name,"current.phs"); /* Taken directly the Correct package directory. -Adjust? */ strcpy (dxfilename,cfilesdir); strcat (dxfilename,"medxbin1.tif"); strcpy (dyfilename,cfilesdir); strcat (dyfilename,"medybin1.tif"); strcpy (intfilename,cfilesdir); strcat (intfilename,"medi12b1.tif"); /*------------------------- Process Args --------------------*/ if (DEBUG) printf("Process Args\n"); program_name=argv[0]; if (argc<2){ printf("Too few input parameters. Type %s --help for more extensive help.\n", program_name); usage(); } /* Process First Argument */ for (i=0; ((i<2) && (i<strlen(argv[1]))) ;i++){ switch (argv[1][i]) { case 'i': dist_first = dist_flag; intens_flag = 1; break; case 'd': dist_flag = 1; break; case '-': /* Dezinger and/or background subtract only */ if (i==0) { goto process_input_files; /* Skip arg advance. Style Choice? */ /* ++argc; --argv; Counteract arg advance occuring after loop break; */ } else { printf("Invalid first argument\n"); usage(); } default: printf("Invalid first argument\n"); usage(); } } --argc; ++argv; /* Process all other arguments */ process_input_files: while( (argc>1) && (argv[1][0] == '-')) { switch (argv[1][1]) { case 't': explicit_int = 1; strcpy(intfilename,argv[2]); --argc; ++argv; break; case 'x': explicit_dist = 1; strcpy(dxfilename,argv[2]); strcpy(dyfilename, dxfilename); x_addr = strrchr(dyfilename,'x'); /* same as strrchr */ /* Address of last occurance of 'x' in the filename */ if (x_addr != NULL) *x_addr = 'y'; else my_abort("Invalid distortion filename -- must contain an \'x\'\n"); --argc; ++argv; break; case 'o': explicit_outname = 1; strcpy(outname,argv[2]); /* outname=argv[2]; */ --argc; ++argv; break; case 'b': /* --- bfilen was initizialized to 0 --- */ bfilenames=&argv[2]; bsub_flag = 1; while ((argc >2) && (argv[2][0] != '-')) { if (bfilen>1) { printf("Error,max 2 back files allowed\n"); usage(); } /* strcpy(bfilenames[bfilen],argv[2]); */ bfilen++; /* On exit, this is the number of background files. This should never be modified except here. */ --argc; ++argv; } if (bfilen>1) dezing_back = 1; break; case 's': if (argv[1][2] == 'z') dezing_images = 1; /* Combine all images by dezingering (max 2 for the moment) */ /* infilen was initialized to 0 */ infilenames = &argv[2]; /* infilenames points to part of argv */ while ((argc >2) && (argv[2][0] != '-')) { if ((dezing_images) && (infilen>1)) my_abort("Error, max 2 input files if combining & dezingering\n"); else if (infilen>99) my_abort("Error, max 100 input files when not combining\n"); /* strcpy(infilenames[infilen],argv[2]); */ infile = fopen(infilenames[infilen], "rb"); if (infile==NULL) { printf("Error opening input file %s\n",infilenames[infilen]); my_abort(""); } else if ((infilen==0) && swizdetect_flag) swizzle=tiff_big_endian(infile); fclose(infile); infilen++; /* infilen should never be modified except here, since it keeps track of the number of infiles that infilenames points to */ --argc; ++argv; } break; case '-': if (strcmp(argv[1],help_flag)==0) help(); default: printf(" %s: Bad Option, try --help for more options\n", argv[1][0]); usage(); } --argc; ++argv; } /* -------------------- End Arg Processing -------------------- */ /* ---- If appropriate, read correction file names from file ----- */ config=fopen(cffilename,"r"); if ( (config!=NULL) && (!explicit_int) && (!explicit_dist) ) { /* Marian's code also looked for the config file in the cffilesdir default directory. Command line over-rides the contents of this file */ printf("Looking in %s for files\n", cffilename); for (i=0; i<3; i++) { fscanf(config,"%s",hold_file[i]); } if (!explicit_dist) { strcpy (dxfilename,hold_file[0]); strcpy (dyfilename,hold_file[1]); } if (!explicit_int) strcpy (intfilename,hold_file[2]); fclose(config); } /* ---------------------------------------------------------------------- DONE WITH FRONT MATTER. STATUS: intfilename, dxfilename, dyfilename defined, not tested or opened (if necessary). bfilenames (<=2) and infilenames (<=100) are defined and tested, but bfile and infile are closed. (Will probably move test to later). infilen and bfilen hold the number of input and background files dezing_images BOOLEAN whether to loop through input or dezinger a pair then correct dezing_back BOOLEAN indicating whether background needs dezingering */ /* -------------------- Begin Main Program --------------------*/ /* -------------------- INITIAL MEMORY CHECK -------------------- */ if (DEBUG) printf("Initial Memory Check\n"); length=det_size*det_size; header=(char *)malloc(header_bytes); if (trailer_bytes > 0) trailer = (char *)malloc(trailer_bytes); if (dist_flag || intens_flag || dezing_images || dezing_back){ tempbuf=(float *)malloc(length*4); if (tempbuf == NULL) my_abort("No memory for tempbuf -- Try upgrading from your Commodore 64!\n"); } if ((dezing_images) || (dezing_back)) { /* Dynamically allocate a 2D array of shorts. (see love_C.ps -- ANSI C for Programmers, Tim Love, p. 57) Currently, the limit is 2, but we want to be able to dezinger more than one at a time */ max_images = (infilen>bfilen?infilen:bfilen); if (DEBUG) printf("About to allocate image_stack for %d images\n", max_images); image_stack=(unsigned short **)malloc(max_images*sizeof(unsigned short *)); if (image_stack == NULL) my_abort("Out of memory when trying to allocate pointers to image_stack\n"); image_stack[0] = (unsigned short *)malloc(max_images * length * sizeof(short)); if (image_stack[0] == NULL) my_abort("Out of memory when trying to allocate image_stack\n"); for (i=1; i < max_images; i++) image_stack[i] = image_stack[0] + i * length; } /* -------------- BACKGROUND INIT --------------------- */ if (DEBUG) printf("Background Init\n"); if (bsub_flag) { if (!(dezing_back && !dezing_images)){ /* Case 4 of TRUTH TABLE below */ bdat=(unsigned short *)malloc(length*2); if (bdat == NULL) { my_abort("No memory for bdat -- Try upgrading you Commodore 64!\n"); } } for(i=0;i<bfilen;i++){ bfile = fopen(bfilenames[i],"rb"); if (bfile==NULL) { printf("Error opening background file %s\n",bfilenames[i]); my_abort(""); } dat_ptr = dezing_back ? image_stack[i] : bdat; /* If only one background file (not dezingering),don't use image_stack */ if ((fread(header,1,header_bytes,bfile)!=header_bytes) || (fread(dat_ptr,2,length,bfile)!=length)) my_abort("Error reading background file!\n"); else fclose(bfile); } if (dezing_back){ dezing(image_stack[0],image_stack[1],det_size,det_size,saturated,tempbuf); if (dezing_images) { /* In this case, free up image_stack to use again */ for(i=0;i<length;i++) bdat[i]=image_stack[0][i]; } else bdat = image_stack[0]; /* For explanation, see comments & TRUTH TABLE at DATA CORRECTION CODE */ } /* shortbg=bdat; PURPOSE UNSURE */ /* Result is put into bdat -- which is also the first image */ /* Gil's dizinger code can take more than two images... */ } /* ..... if bsub_flag */ /* ----- END BACKGROUND INIT. if bsub_flag, then bdat[] is defined ------- */ /* ----- CORRECTION FILE CHECK & INIT --------- */ if (DEBUG) printf("Correction File Init\n"); if (intens_flag){ intens=fopen(intfilename,"rb"); if (intens==NULL) { printf("Error opening intensity correction file\n\t %s\n",intfilename); usage(); } intcorr=(float *)malloc(length*4); if (intcorr == NULL) my_abort("No memory for intcorr - quit \n"); if ( (fseek(intens,TV6_HEADER_BYTES,0)) || /* fseek returns 0 on success!? */ (fread(intcorr,4,length,intens)!=length)) { printf("Error reading Intensity Correction file %s\n", intfilename); my_abort(""); } fclose(intens); /* Uncomment below (and updated makefile) to re-insert Obliquity correct intensity correction. */ /* if ( (obliq_flag) && (obliq(intcorr,oblique,det_size)) ) my_abort("Error performing obliquity correction!\n"); */ } if (dist_flag){ distx=fopen(dxfilename,"rb"); if (distx==NULL) { printf("Error opening x distortion file %s\n",dxfilename); usage(); } disty=fopen(dyfilename,"rb"); if (disty==NULL) { printf("Error opening y distortion file %s\n",dyfilename); usage(); } dxcorr=(float *)malloc(length*4); dycorr=(float *)malloc(length*4); if (!dxcorr || !dycorr) my_abort("No memory for dxcorr & dycorr - quit \n"); if ( (fseek(distx,TV6_HEADER_BYTES,0)) || /* fseek returns 0 on success!? */ (fread(dxcorr,4,length,distx)!=length)) { printf("Error reading X-Dist file %s!\n", dxfilename); my_abort(""); /* -- goto qout -- */ } if ( (fseek(disty,TV6_HEADER_BYTES,0)) || /* fseek returns 0 on success!? */ (fread(dycorr,4,length,disty)!=length)) { printf("Error reading Y-Dist file %s!\n", dyfilename); my_abort(""); } fclose(distx); fclose(disty); } /* If doing distortion and intensity correction, save the filenames to configuration file */ if (dist_flag && intens_flag) { strcpy (hold_file[0],dxfilename); strcpy (hold_file[1],dyfilename); strcpy (hold_file[2],intfilename); printf("Writing correction filenames to %s\n", cffilename); config=fopen(cffilename,"w+"); if (config!=NULL) { fprintf(config,"%s\n%s\n%s\n", hold_file[0],hold_file[1],hold_file[2]); } fclose(config); } /* ----- END CORRECTION INIT, intcorr, dxcorr, dycorr defined if necessary --- */ /* ----- BEGIN CORRECTION ----- dezing_images? Yes -> load & dezing the images, then correct in proper order, then save No -> Begin loop to load images, correct, save Probably define saparate routines correct_dist and correct_int (ala matlab) */ if (DEBUG) printf("Swizzle, oblique check\n"); if (swizzle) { if (bsub_flag) swizit((char *)bdat,2,length); if (dist_flag){ swizit((char *)dxcorr,4,length); swizit((char *)dycorr,4,length); } if (intens_flag) swizit((char *)intcorr,4,length); } /* if (pedestal == 0) shift(bdat,length); Divide background by two to match data!*/ /* ---------> BEGIN NEW DATA CORRECTION CODE <-------------- */ /* If dezingering, it isn't really necessary to allocate separate space for indat, since we can re-use image_stack[0] (which is defined when dezingering either images or background. Here is the following TRUTH TABLE to minimize memory usage: ------------------------------------------------------------ | Boolean Value | Needs own allocation | | dezing_back |dezing_images |image_stack | indat | bdat | | 1 | 0 | Yes | Yes | No | | 0 | 1 | Yes | No | Yes | | 0 | 0 | No | Yes | Yes | | 1 | 1 | Yes | No | Yes | ------------------------------------------------------------ When not given their own allocation, bdat and/or indat just use image_stack[0]. These optimizations rely on: 1) the background being processed before the image 2) dezing doesn't ask for a separate destination array. This is not true of the multiple image dezinger code - see COMMENTS below */ if (DEBUG) printf("Correction begin\n"); if (dezing_images){ if (DEBUG) printf("Dezingering input images\n"); for(i=0;i<infilen;i++){ dat_ptr = image_stack[i]; read_data(infilenames[i], header, header_bytes, dat_ptr, length, trailer, trailer_bytes); if (swizzle) swizit((char *)dat_ptr,2,length); } dezing(image_stack[0],image_stack[1],det_size,det_size,saturated,tempbuf); if (DEBUG) printf("Back grom dezing\n"); indat=image_stack[0]; err = correct_data(bsub_flag, intens_flag, dist_flag, obliq_flag, dist_first, det_size, pedestal, bdat, indat, intcorr, dxcorr, dycorr, tempbuf, oblique); if (DEBUG) printf("Back grom correct_data\n"); if (err) my_abort("Error performing distortion correction!\n"); outdat=indat; if (!explicit_outname) gen_outname(outname, sizeof(outname),infilenames, infilen); /* Now convert back from float to short integer format */ if ((dist_flag) || (intens_flag)) shrink(tempbuf,outdat,length,pedestal); /* If necessary, re-swap byte order to that of the input file */ if (swizzle) swizit((char *)outdat,2,length); save_corrected(outname, header, header_bytes, outdat, length, trailer, trailer_bytes); } else { /* dezing_images == 0 */ if (DEBUG) printf("Not dezingering input images\n"); indat=(unsigned short *)malloc(length*2); if (indat == NULL) my_abort("No memory for indat --quit\n"); for(i=0;i<infilen;i++){ read_data(infilenames[i], header, header_bytes, indat, length, trailer, trailer_bytes); if (swizzle) swizit((char *)indat,2,length); err = correct_data(bsub_flag, intens_flag, dist_flag, obliq_flag, dist_first, det_size, pedestal, bdat, indat, intcorr, dxcorr, dycorr, tempbuf, oblique); if (err) goto skipthis; outdat=indat; if (!explicit_outname){ if (DEBUG) printf("Generating Output filename\n"); gen_outname(outname, sizeof(outname),&infilenames[i], 1); /* Need &infilenames[i] == infilenames + i, since gen_outname expects a pointer to a string, not a string */ } if ((dist_flag) || (intens_flag)){ if (DEBUG) printf("Now convert back from float to short integer format\n"); shrink(tempbuf,outdat,length,pedestal); } /* If necessary, re-swap byte order to that of the input file */ if (swizzle) { if (DEBUG) printf("Unswizzling data\n"); swizit((char *)outdat,2,length); } save_corrected(outname, header, header_bytes, outdat, length, trailer, trailer_bytes); skipthis: if (err) { strcpy(response,"Y"); editin("Continue?",response,2); if (response[0] != 'Y' && response[0] !='y') my_abort(""); } err=0; if (DEBUG) printf("End (dezing_image == 0) branch, i = %d\n", i); } /* End for loop within dezing_image == 0 branch */ } /* ... else .... */ if (DEBUG) printf("End main()\n"); /* ---------> END NEW DATA CORRECTION CODE <-------------- */ } int correct_data(int bsub_flag, int intens_flag, int dist_flag, int obliq_flag, int dist_first, int det_size, int pedestal, unsigned short *bdat, unsigned short *indat, float *intcorr, float *dxcorr, float *dycorr, float *tempbuf, struct oblparams oblique) { void intenscorr(float *buffer,float *intcorr,int size, struct oblparams *params); int distcorr(unsigned short *indat,float *tempbuf,float *delx,float *dely, int size, int pedestal); void my_abort(char message[]); if (bsub_flag){ printf("Subtracting background.\n"); bsub(indat,bdat,det_size,pedestal); } if (dist_first){ printf("Performing distortion correction.\n"); if (distcorr(indat,tempbuf,dxcorr,dycorr,det_size,pedestal)) return(1); /* returns 0 on success */ printf("Performing intensity correction.\n"); intenscorr_int(indat,intcorr,det_size,&oblique); } else if (intens_flag){ printf("Performing intensity correction.\n"); intenscorr_int(indat,intcorr,det_size,&oblique); } if (dist_flag){ printf("Performing distortion correction.\n"); if (distcorr(indat,tempbuf,dxcorr,dycorr,det_size,pedestal)) return(1); } return(0); } void read_data(char infilename[],char *head, int headn, unsigned short *data, int datan, char *trail, int trailn) { FILE *infile = NULL; void my_abort(char message[]); infile = fopen(infilename,"rb"); if (infile==NULL) { printf("Error opening input data file %s\n",infilename); my_abort(""); } if ( (fread(head,1,headn,infile)!=headn) || (fread(data,2,datan,infile)!=datan) ) { printf("Error reading input data file %s\n",infilename); my_abort(""); } if (trailn > 0) { if(fread(trail,1,trailn,infile)!=trailn){ printf("Error reading trailer bytes from %s\n",infilename); my_abort(""); } } fclose(infile); } void save_corrected(char outname[], char *head, int headn, unsigned short *data, int datan, char *trail, int trailn) { FILE *outfile = NULL; void my_abort(char message[]); outfile = fopen(outname,"r"); if (outfile !=NULL){ /* IF this file exists, close file and abort */ fclose(outfile); printf("Error: Output file %s already exists\n", outname); my_abort(""); } if((outfile=fopen(outname,"wb"))==NULL) { printf("Error opening %s\n",outname); my_abort(""); } printf("Now writing data to output file %s\n",outname); if ( (fwrite(head,1,headn,outfile)!=headn) || (fwrite(data,2,datan,outfile)!=datan)) { printf("Error writing to %s\n",outname); my_abort(""); } /* printf("Now writing trailer bytes to output file %s\n",outname); */ if (trailn > 0) { if (fwrite(trail,1,trailn,outfile)!=trailn) { printf("Error writing trailer bytes to to %s\n",outname); my_abort(""); } } fclose(outfile); } void gen_outname(char outfilename[], int outchars,char **filenames, int nfilenames) /* Takes an array of number filenames (infiles[][]), each no more than outsize long, and generates another string based on an algorithm. Uses a different algorithm depending on how many filenames are given */ { extern const char insert[]; extern const char dot; extern const char default_outname[]; char *insert_addr; void str_ins(char [], int, char [], const char [], const char); if (nfilenames == 1) str_ins(outfilename,outchars,filenames[0],insert,dot); else outfilename=strncpy(outfilename,default_outname,outchars); return; } void str_ins(char out[], int outsize,char in[], const char ins[], const char tok) /* str_ins inserts the string ins[] just in front of the right-most instance of tok in string in[], the result being placed in out[]. if tok is not found in in[], in and ins are concatenated */ { void my_abort(char message[]); char *ins_addr; /* Where to insert new sting ins []*/ int ins_ind, last_ind, i, slide; strcpy(out,in); if (ins_addr=(strrchr(out,tok))) ins_ind=(int)(ins_addr-out); else{ /* tok not found in out[], put ins[] at the end */ out=strcat(out,ins); return; } last_ind = strlen(out); /* out[last_ind] is the terminating null char */ slide = strlen(ins); if (last_ind+slide > outsize-1) my_abort("in str_ins, out[] not big enough to insert ins[]\n"); for(i=last_ind;i>=ins_ind;i--) out[i+slide]=out[i]; for(i=ins_ind ; i < (ins_ind + slide) ; i++) out[i]=ins[i-ins_ind]; return; /* NOTE: for the above, might be better to concatenate and THEN move, rather than doing it as I've done here. */ } void usage() { extern const char usage_str[]; printf(usage_str); exit(0); } void help() { extern const char help_str[]; printf(help_str); exit(0); } void my_abort(char message[]){ printf(message); printf("Aborting\n"); exit(0); } int tiff_big_endian(FILE *datfile) /* datfile is an open binary file. Reads the first 4 bytes and, assuming that they correspond to the Tiff 'magic number' (I think that's right), determines byte order. ASSUMES type int has 4 bytes. PC byte order (default) = little endian SGI byte order = big endian */ { int magic; int big_endian = 0; rewind(datfile); if (fread(&magic,sizeof(int),1,datfile)!=1) my_abort("Error reading data file (in tiff_big_endian)\n"); if (magic == 0x002A4949) big_endian=0; /* PC byte order - little endian */ else if (magic ==0x49492A00) { /* SGI byte order - big endian */ big_endian=1; printf("Reversing byte order of input files for the calculations.\n"); printf("They will be output in the original format.\n"); } else my_abort("Image file doens't appear to be a tiff file after all\n"); return big_endian; } /* COMMENTS DEZINGERING: Currently, use dezinger.c declared as: void dezing(unsigned short \*indat1, unsigned short \*indat2, int slow_max, int fast_max, int saturated, float \*tempbuf) The current code anticipates a switch to the following, which dezingers >2 files, by implementing the 2D array **image_stack, required to make this switch (From Zingers.c on Gil Toombes\' web site -- Gruner group home page) int remove_zingers(int num_images, uint16 \*\*data_ptrs, double \*dest, int width, int height, long bkg, double sigma, double sigma_cut, double gain, long int *num_zingers) BITSHIFTING: Bitshifting is NOT done. Instead, if the a background pixel has more counts than the data pixel, bsub (in medbsub) just sets the pixel to zero Bitshifting is necessary for any signal that can exceed 2^15 in order to do background subtraction. The MedOptics detector\'s ADC is only 14 bits and so constitutes a special case in which the output never exceeds 2^14=16,384. PEDESTAL: Not used at present -- may have to re-insert. SATURATION: Any saturated pixel (detector specific) will maintain its value throughout the correction procedure. OBLIQUITY: Disabled, but flag obliq_flag is defined in case we want to replace. Current version uses prompts (within module GetObl) to determine parameters. BYTE ORDER: For tiff files, program detects whether or not swizzling of the byte order is needed. If so, it is automatically performed by module \'swizit\': swizit: Swizzles the byte order (used for SGI computers) for n-byte variables. */