vircam_imcombine.c

00001 /* $Id: vircam_imcombine.c,v 1.30 2012/01/27 12:25:10 jim Exp $
00002  *
00003  * This file is part of the VIRCAM Pipeline
00004  * Copyright (C) 2005 Cambridge Astronomy Survey Unit
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: jim $
00023  * $Date: 2012/01/27 12:25:10 $
00024  * $Revision: 1.30 $
00025  * $Name: vcam-1_3_2 $
00026  */
00027 
00028 /* Includes */
00029 
00030 #ifdef HAVE_CONFIG_H
00031 #include <config.h>
00032 #endif
00033 
00034 #include <math.h>
00035 #include <cpl.h>
00036 
00037 #include "vircam_utils.h"
00038 #include "vircam_pfits.h"
00039 #include "vircam_stats.h"
00040 #include "vircam_fits.h"
00041 #include "vircam_mods.h"
00042 
00043 /* Macro definitions */
00044 
00045 #define FATAL_ERR(_f,_a) {cpl_msg_error(_f,"%s",_a); tidy(); *status = VIR_FATAL; return(*status);}
00046 #define WARN_ERR(_f,_a) {cpl_msg_error(_f,"%s",_a); tidy(); *status = VIR_WARN; return(VIR_WARN);}
00047 #define INFO_ERR(_f,_a) {cpl_msg_info(_f,"%s",_a);}
00048 #define MEDIANCALC 1
00049 #define MEANCALC 2
00050 #define SZBUF 1024
00051 
00052 /* Definition of litestruct which is used to hold useful information about
00053    each of the input frames and their associated images */
00054 
00055 typedef struct {
00056     vir_fits         *frame;
00057     float            exptime;
00058     float            expfudge;
00059     float            skylevel;
00060     float            skynoise;
00061     float            skyfudge;
00062     float            skyrenorm;
00063 } litestruct;
00064 
00065 /* Static Global variables */
00066 
00067 static litestruct *fileptrs = NULL;
00068 static float **datas = NULL;
00069 static cpl_binary **masks = NULL;
00070 static float *odata;
00071 static cpl_binary *omask;
00072 static long npts;
00073 static int nf;
00074 static float oskylevel;
00075 static long nx;
00076 static long ny;
00077 static unsigned char *rmask = NULL;
00078 static unsigned char *rplus = NULL;
00079 
00080 /* Static subroutine prototypes */
00081 
00082 static void skyest(float *data, cpl_binary *bpm, float thresh, float *skymed, 
00083                    float *skynoise);
00084 static void medcalc(float, float, int);
00085 static void meancalc(float, float, int);
00086 static void xclip_med(float thresh, int scaletype);
00087 static void xclip_mean(float thresh, int scaletype);
00088 
00089 static void tidy(void);
00090 
00093 /*---------------------------------------------------------------------------*/
00153 /*---------------------------------------------------------------------------*/
00154 
00155 extern int vircam_imcombine(vir_fits **fset, int nfits, int combtype, 
00156                             int scaletype, int xrej, float thresh,
00157                             cpl_image **outimage, unsigned char **rejmask,
00158                             unsigned char **rejplus, cpl_propertylist **drs,
00159                             int *status) {
00160     int i,k,j;
00161     const char *ic_fctid = "vircam_imcombine";
00162     char msg[SZBUF];
00163     float sumsky,sumsig,texp1,texp2,expfudge,skylevel,skynoise,oskynoise;
00164     float *dat,*work;
00165     litestruct *ff;
00166     cpl_image *im;
00167     cpl_propertylist *plist_p;
00168 
00169     /* Inherited status */
00170 
00171     *rejmask = NULL;
00172     *rejplus = NULL;
00173     *drs = NULL;
00174     *outimage = NULL;
00175     if (*status != VIR_OK) 
00176         return(*status);
00177 
00178     /* Check that there are any files in the first place...*/ 
00179 
00180     nf = nfits;
00181     if (nf == 0) 
00182         WARN_ERR(ic_fctid,"No files to combine")
00183 
00184     /* Get some file structures */
00185 
00186     fileptrs = cpl_calloc(nf,sizeof(litestruct));
00187 
00188     /* Get workspace for convenience arrays */
00189 
00190     datas = cpl_malloc(nf*sizeof(float *));
00191     npts = vircam_getnpts(vircam_fits_get_image(fset[0]));
00192     for (k = 0; k < nf; k++)
00193         datas[k] = cpl_malloc(npts*sizeof(float));
00194     masks = cpl_malloc(nf*sizeof(cpl_binary *));
00195 
00196     /* Get pointers to the data arrays */
00197 
00198     for (k = 0; k < nf; k++) {
00199         im = vircam_fits_get_image(fset[k]);
00200         dat = cpl_image_get_data_float(im);
00201         if (dat == NULL) {
00202             snprintf(msg,SZBUF,"Failed to load data from extension %d in %s",
00203                      vircam_fits_get_nexten(fset[k]),
00204                      vircam_fits_get_filename(fset[k]));
00205             FATAL_ERR(ic_fctid,msg)
00206         }
00207         for (i = 0; i < npts; i++)
00208             datas[k][i] = dat[i];
00209         masks[k] = cpl_mask_get_data(cpl_image_get_bpm(im));
00210     }
00211 
00212     /* Open each file in turn and fill in the necessary information. Start with
00213        the file name...*/
00214 
00215     for (i = 0; i < nf; i++) {
00216         ff = fileptrs + i;
00217         ff->frame = fset[i];
00218 
00219         /* If this is the first frame, then keep the size of the data
00220            array for future reference */
00221 
00222         if (i == 0) {
00223             nx = (long)cpl_image_get_size_x(vircam_fits_get_image(fset[0]));
00224             ny = (long)cpl_image_get_size_y(vircam_fits_get_image(fset[0]));
00225             npts = nx*ny;
00226         }
00227 
00228         /* Get the header and the exposure time */
00229 
00230         plist_p = vircam_fits_get_phu(ff->frame);
00231         if (plist_p == NULL) {
00232             snprintf(msg,SZBUF,"Failed to load primary property list %s",
00233                      vircam_fits_get_filename(ff->frame));
00234             INFO_ERR(ic_fctid,msg)
00235             texp2 = 1.0;
00236         } else {
00237             if (vircam_pfits_get_exptime(plist_p,&texp2) != VIR_OK) {
00238                 texp2 = 1.0;
00239                 snprintf(msg,SZBUF,"Failed to get exposure time from %s",
00240                          vircam_fits_get_filename(ff->frame));
00241                 INFO_ERR(ic_fctid,msg)
00242             }
00243         }
00244 
00245         /* Set a few properties */
00246 
00247         ff->exptime = texp2;
00248         texp1 = fileptrs->exptime;
00249         expfudge = texp1/texp2;
00250         ff->expfudge = expfudge;
00251 
00252         /* If scaling by relative exposure time, then do it now. NB: This
00253            isn't necessary for the first file as all the others are scaled
00254            relative to it */
00255 
00256         if (scaletype == 3 && i > 0) {
00257             for (j = 0; j < npts; j++) 
00258                 datas[i][j] *= ff->expfudge;
00259         }
00260 
00261         /* Get the background estimate and noise */
00262 
00263         skyest(datas[i],masks[i],thresh,&skylevel,&skynoise);
00264         ff->skylevel = skylevel;
00265         ff->skynoise = skynoise;
00266     }
00267 
00268     /* Work out average background and noise. Then create background zeropoint
00269        or scale factor, depending upon which was requested in the call */
00270 
00271     work = cpl_malloc(nf*sizeof(float));
00272     for (i = 0; i < nf; i++)
00273         work[i] = (fileptrs+i)->skylevel;
00274     sumsky = vircam_med(work,NULL,(long)nf);
00275     for (i = 0; i < nf; i++)
00276         work[i] = (fileptrs+i)->skynoise;
00277     sumsig = vircam_med(work,NULL,(long)nf);
00278     cpl_free(work);
00279     switch (scaletype) {
00280     case 1:
00281         for (i = 0; i < nf; i++)
00282             (fileptrs+i)->skyfudge = sumsky - (fileptrs+i)->skylevel;
00283         break;
00284     case 2:
00285         for (i = 0; i < nf; i++) 
00286             (fileptrs+i)->skyfudge = sumsky/(fileptrs+i)->skylevel;
00287         break;      
00288     case 3:
00289         for (i = 0; i < nf; i++)
00290             (fileptrs+i)->skyfudge = sumsky - (fileptrs+i)->skylevel;
00291         break;
00292     default:
00293         for (i = 0; i < nf; i++) 
00294             (fileptrs+i)->skyfudge = 0.0;
00295         break;
00296     }
00297 
00298     /* Open an output image based on the first frame in the frameset */
00299 
00300     *outimage = cpl_image_new((cpl_size)nx,(cpl_size)ny,CPL_TYPE_FLOAT);
00301     odata = cpl_image_get_data_float(*outimage);
00302     omask = cpl_mask_get_data(cpl_image_get_bpm(*outimage));
00303     if (*outimage == NULL || odata == NULL) 
00304         FATAL_ERR(ic_fctid,"Couldn't create output image")
00305     *rejmask = cpl_calloc(npts,sizeof(*rejmask));
00306     rmask = *rejmask;
00307     *rejplus = cpl_calloc(npts,sizeof(*rejplus));
00308     rplus = *rejplus;
00309 
00310     /* Now do the averaging/medianing */
00311 
00312     switch (combtype) {
00313     case MEDIANCALC:
00314         medcalc(thresh,sumsig,scaletype);
00315         break;
00316     case MEANCALC:
00317         meancalc(thresh,sumsig,scaletype);
00318         break;
00319     }
00320 
00321     /* Do the extra clipping here if you want it */
00322 
00323     if (xrej) {
00324         
00325         /* First get sky background and sigma from output data */
00326 
00327         skyest(odata,omask,thresh,&oskylevel,&oskynoise);
00328 
00329         /* Now loop for all the files subtract off the mean frame (suitably
00330            scaled and zero pointed depending on what was done in the first 
00331            place) */
00332 
00333         for (i = 0; i < nf; i++) {
00334             ff = fileptrs + i;
00335             ff->skyrenorm = ff->skylevel/oskylevel;
00336             switch (scaletype) {
00337             case 1:
00338                 for (k = 0; k < npts; k++) 
00339                     datas[i][k] -= (odata[k] - oskylevel);
00340                 break;
00341             case 2:
00342                 for (k = 0; k < npts; k++)
00343                     datas[i][k] -= (odata[k] - oskylevel)*ff->skyrenorm;
00344                 break;
00345             case 3:
00346                 for (k = 0; k < npts; k++) 
00347                     datas[i][k] -= (odata[k] - oskylevel);
00348                 break;
00349             case 0:
00350                 for (k = 0; k < npts; k++) 
00351                     datas[i][k] -= (odata[k] - oskylevel);
00352                 break;
00353             }
00354 
00355             /* Re-estimate the noise for this image */
00356 
00357             skyest(datas[i],masks[i],thresh,&skylevel,&skynoise);
00358             ff->skynoise = skynoise;
00359         }
00360 
00361         /* Now do the extra clip... */
00362 
00363         switch (combtype) {
00364         case MEDIANCALC:
00365             xclip_med(thresh,scaletype);
00366             break;
00367         case MEANCALC:
00368             xclip_mean(thresh,scaletype);
00369             break;
00370         }
00371     }
00372 
00373     /* Write provenance keywords */
00374 
00375     *drs = cpl_propertylist_new();
00376     vircam_prov(*drs,fset,nfits);
00377 
00378     /* Right, tidy and get out of here */
00379 
00380     tidy();
00381     return(VIR_OK);
00382 }
00383 
00384 /*---------------------------------------------------------------------------*/
00406 /*---------------------------------------------------------------------------*/
00407 
00408 static void xclip_med(float thresh, int scaletype) {
00409     int nf1,nf2,nfm,nrejmax,is_even,k,is_even2,nrej,nremain,nm,nmm,nplus;
00410     int nminus,nn,j;
00411     float **work,*dork,value,cliplev;
00412     long i;
00413     litestruct *ff;
00414 
00415     /* Get some workspace */
00416 
00417     work = cpl_malloc(3*sizeof(float *));
00418     for (i = 0; i < 3; i++)
00419         work[i] = cpl_malloc(nf*sizeof(float));
00420     dork = cpl_malloc(nf*sizeof(float));
00421 
00422     /* Loop for each input pixel now... */
00423 
00424     for (i = 0; i < npts; i++) {
00425         if (omask[i])
00426             continue;
00427 
00428         /* Scale or shift data */
00429 
00430         nn = 0;
00431         switch (scaletype) {
00432         case 0:
00433             for (k = 0; k < nf; k++) {
00434                 if (masks[k][i])
00435                     continue;
00436                 ff = fileptrs + k;
00437                 work[0][nn] = datas[k][i];
00438                 work[1][nn] = ff->skynoise;
00439                 work[2][nn++] = datas[k][i] + odata[i] - oskylevel;
00440             }
00441             break;
00442         case 1:
00443             for (k = 0; k < nf; k++) {
00444                 if (masks[k][i])
00445                     continue;
00446                 ff = fileptrs + k;
00447                 work[0][nn] = datas[k][i] + ff->skyfudge;
00448                 work[1][nn] = ff->skynoise;
00449                 work[2][nn++] = datas[k][i] + odata[i] - oskylevel + 
00450                     ff->skyfudge;
00451             }
00452             break;
00453         case 2:
00454             for (k = 0; k < nf; k++) {
00455                 if (masks[k][i])
00456                     continue;
00457                 ff = fileptrs + k;
00458                 work[0][nn] = datas[k][i]*ff->skyfudge;
00459                 work[1][nn] = ff->skynoise*ff->skyfudge;
00460                 work[2][nn++] = (datas[k][i] + odata[i]*ff->skyrenorm - 
00461                                  ff->skylevel)*ff->skyfudge;
00462             }
00463             break;
00464         case 3:
00465             for (k = 0; k < nf; k++) {
00466                 if (masks[k][i])
00467                     continue;
00468                 ff = fileptrs + k;
00469                 work[0][nn] = datas[k][i] + ff->skyfudge;
00470                 work[1][nn] = ff->skynoise;
00471                 work[2][nn++] = datas[k][i] + odata[i] - oskylevel + 
00472                     ff->skyfudge;
00473             }
00474             break;
00475         }       
00476 
00477         /* Set up a few useful variables */
00478 
00479         nf1 = nn/2 - 1;
00480         nf2 = nf1 + 1;
00481         nfm = (nn + 1)/2 - 1;
00482         nrejmax = nn/2;
00483         is_even = !(nn & 1);
00484 
00485         /* Sort and get a first pass median */
00486 
00487         vircam_sort(work,nn,3);
00488         if (is_even)
00489             value = 0.5*(work[0][nf1] + work[0][nf2]);
00490         else 
00491             if (nn < 5) 
00492                 value = work[0][nfm];
00493             else 
00494                 value = 0.25*(work[0][nfm-1] + work[0][nfm+1]) + 0.5*work[0][nfm];
00495         
00496         /* Do clipping */
00497 
00498         nplus = 0;
00499         cliplev = value + thresh*work[1][nn-1];
00500         while (nplus < nrejmax && work[0][nn-nplus-1] > cliplev)
00501             nplus++;
00502         nminus = 0;
00503         cliplev = value - thresh*work[1][nn-1];
00504         while ((nplus+nminus) < nrejmax && work[0][nminus] < cliplev)
00505             nminus++;
00506         nrej = nplus + nminus;
00507 
00508         /* If there were any clipped out, the re-estimate the value */
00509 
00510         if (nrej > 0) {
00511             nremain = nn - nrej;
00512             if (nremain != 0) {
00513                 nm = nremain/2 - 1;
00514                 for (j = 0; j < nremain; j++) 
00515                     dork[j] = work[2][j+nminus];
00516                 nmm = (nremain + 1)/2 - 1;
00517                 is_even2 = !(nremain & 1);
00518                 vircam_sort(&dork,nm,1);
00519                 if (is_even2) 
00520                     value = 0.5*(dork[nm] + dork[nm+1]);
00521                 else 
00522                     if (nremain < 3) 
00523                         value = dork[nmm];
00524                     else 
00525                         value = 0.5*dork[nmm] + 0.25*(dork[nmm-1] + dork[nmm+1]);
00526             }
00527         
00528             /* Store the result away */
00529 
00530             odata[i] = value;
00531             rmask[i] = min(255,nrej);
00532             rplus[i] = min(255,nplus);
00533         } else {
00534             rmask[i] = 0;
00535             rplus[i] = 0;
00536         }
00537     }
00538 
00539     /* Ditch workspace and get out of here */
00540 
00541     for (i = 0; i < 3; i++)
00542         cpl_free(work[i]);
00543     cpl_free(work);
00544     cpl_free(dork);
00545 }
00546 
00547 /*---------------------------------------------------------------------------*/
00569 /*---------------------------------------------------------------------------*/
00570 
00571 static void xclip_mean(float thresh, int scaletype) {
00572     int k,nf2,nrej,nplus,kk,krem;
00573     float *work[3],value,value2,nrejmax,resid,maxresid;
00574     long i,nn;
00575     litestruct *ff;
00576     unsigned char *iflag;
00577 
00578     /* Get some workspace */
00579 
00580     for (i = 0; i < 3; i++)
00581         work[i] = cpl_malloc(nf*sizeof(float));
00582     iflag = cpl_malloc(nf*sizeof(unsigned char));
00583 
00584     /* Loop for each input pixel now... */
00585 
00586     nrejmax = nf/2;
00587     for (i = 0; i < npts; i++) {
00588         if (omask[i])
00589             continue;
00590 
00591         /* Scale or shift data */
00592 
00593         nn = 0;
00594         switch (scaletype) {
00595         case 0:
00596             for (k = 0; k < nf; k++) {
00597                 if (masks[k][i])
00598                     continue;
00599                 ff = fileptrs + k;
00600                 work[0][nn] = datas[k][i];
00601                 work[1][nn] = ff->skynoise;
00602                 work[2][nn] = datas[k][i] + odata[i] - oskylevel;
00603                 iflag[nn++] = 0;
00604             }
00605             break;
00606         case 1:
00607             for (k = 0; k < nf; k++) {
00608                 if (masks[k][i])
00609                     continue;
00610                 ff = fileptrs + k;
00611                 work[0][nn] = datas[k][i] + ff->skyfudge;
00612                 work[1][nn] = ff->skynoise;
00613                 work[2][nn] = datas[k][i] + odata[i] - oskylevel + ff->skyfudge;
00614                 iflag[nn++] = 0;
00615             }
00616             break;
00617         case 2:
00618             for (k = 0; k < nf; k++) {
00619                 if (masks[k][i])
00620                     continue;
00621                 ff = fileptrs + k;
00622                 work[0][nn] = datas[k][i]*ff->skyfudge;
00623                 work[1][nn] = ff->skynoise*ff->skyfudge;
00624                 work[2][nn] = (datas[k][i] + odata[i]*ff->skyrenorm - 
00625                                ff->skylevel)*ff->skyfudge;
00626                 iflag[nn++] = 0;
00627             }
00628             break;
00629         case 3:
00630             for (k = 0; k < nf; k++) {
00631                 if (masks[k][i])
00632                     continue;
00633                 ff = fileptrs + k;
00634                 work[0][nn] = datas[k][i] + ff->skyfudge;
00635                 work[1][nn] = ff->skynoise;
00636                 work[2][nn] = datas[k][i] + odata[i] - oskylevel + ff->skyfudge;
00637                 iflag[nn++] = 0;
00638             }
00639             break;
00640         }       
00641 
00642         /* Get a first pass mean */
00643 
00644         value = 0.0;
00645         for (k = 0; k < nn; k++) 
00646             value += work[0][k];
00647         value /= (float)nn;
00648         
00649         /* Enter a rejection loop. Reject pixels one at a time  */
00650 
00651         nplus = 0;
00652         nrej = 0;
00653         for (kk = 0; kk < nrejmax; kk++) {
00654             maxresid = 0.0;
00655             krem = -1;
00656             for (k = 0; k < nn; k++) {
00657                 if (iflag[k] == 1)
00658                     continue;
00659                 resid = fabs(work[0][k] - value);
00660                 if (resid > thresh*work[1][k]) {
00661                     if (resid > maxresid) {
00662                         krem = k;
00663                         maxresid = resid;
00664                     }
00665                 }
00666             }
00667             
00668             /* No further rejections */
00669 
00670             if (krem == -1)
00671                 break;
00672 
00673             /* Another pixel is rejected. If it's positive count it */
00674 
00675             iflag[krem] = 1;
00676             if ((work[0][krem] - value) > 0.0)
00677                 nplus++;
00678             nrej++;
00679 
00680             /* Re-evaluate the mean */
00681 
00682             nf2 = 0;
00683             value2 = 0;
00684             for (k = 0; k < nn; k++) {
00685                 if (iflag[k] == 0) {
00686                     value2 += work[0][k];
00687                     nf2++;
00688                 }
00689             }
00690             if (nf2 != 0) 
00691                 value = value2/(float)nf2;
00692             else
00693                 break;
00694         }
00695 
00696         /* If there were any clipped out store the new value */
00697 
00698         if (nrej > 0) 
00699             odata[i] = value;
00700         rmask[i] = min(255,nrej);       
00701         rplus[i] = min(255,nplus);
00702     }
00703 
00704     /* Ditch workspace and get out of here */
00705 
00706     for (k = 0; k < 3; k++)
00707         cpl_free(work[k]);
00708     cpl_free(iflag);
00709 }
00710 
00711 
00712 /*---------------------------------------------------------------------------*/
00735 /*---------------------------------------------------------------------------*/
00736 
00737 static void medcalc(float thresh, float avskynoise, int scaletype) {
00738     int nf1,nf2,nfm,nrejmax,is_even,nrej,nremain,nm,nmm,is_even2,k,nminus;
00739     int nplus,nn;
00740     long i;
00741     float value,cliplev,*work;
00742 
00743     /* Get a workspace */
00744 
00745     work = cpl_malloc(nf*sizeof(*work));
00746 
00747     /* Ok, loop for each pixel... */
00748 
00749     for (i = 0; i < npts; i++) {
00750 
00751         /* Scale or shift data */
00752 
00753         nn = 0;
00754         switch (scaletype) {
00755         case 0:
00756             for (k = 0; k < nf; k++) {
00757                 if (masks[k][i])
00758                     continue;
00759                 work[nn++] = datas[k][i];
00760             }
00761             break;
00762         case 1:
00763             for (k = 0; k < nf; k++) {
00764                 if (masks[k][i])
00765                     continue;
00766                 work[nn++] = datas[k][i] + (fileptrs+k)->skyfudge;
00767             }
00768             break;
00769         case 2:
00770             for (k = 0; k < nf; k++) {
00771                 if (masks[k][i])
00772                     continue;
00773                 work[nn++] = datas[k][i]*(fileptrs+k)->skyfudge;
00774             }
00775             break;
00776         case 3:
00777             for (k = 0; k < nf; k++) {
00778                 if (masks[k][i])
00779                     continue;
00780                 work[nn++] = datas[k][i] + (fileptrs+k)->skyfudge;
00781             }
00782             break;
00783         }
00784         
00785         /* If nothing is available, then flag the output pixel */
00786 
00787         if (nn == 0) {
00788             odata[i] = 0;
00789             omask[i] = 1;
00790             rmask[i] = 0;
00791             rplus[i] = 0;
00792             continue;
00793         }
00794             
00795         /* Set up a few useful variables */
00796 
00797         nf1 = nn/2 - 1;
00798         nf2 = nf1 + 1;
00799         nfm = (nn + 1)/2 - 1;
00800         nrejmax = nn/2;
00801         is_even = !(nn & 1);
00802 
00803         /* Sort data and get the median */
00804 
00805         vircam_sort(&work,nn,1);
00806         if (is_even)
00807             value = 0.5*(work[nf1] + work[nf2]);
00808         else 
00809             if (nn < 5) 
00810                 value = work[nfm];
00811             else 
00812                 value = 0.25*(work[nfm-1] + work[nfm+1]) + 0.5*work[nfm];
00813 
00814         /* Enter a rejection loop */
00815 
00816         nplus = 0;
00817         cliplev = value + thresh*avskynoise;
00818         while (nplus < nrejmax && work[nn-nplus-1] > cliplev)
00819             nplus++;
00820         nminus = 0;
00821         cliplev = value - thresh*avskynoise;
00822         while ((nplus+nminus) < nrejmax && work[nminus] < cliplev)
00823             nminus++;
00824         nrej = nplus + nminus;
00825 
00826         /* If you've clipped any, then recalculate the median...*/
00827 
00828         if (nrej > 0) {
00829             nremain = nn - nrej;
00830             nm = nremain/2 - 1 + nminus;
00831             nmm = (nremain + 1)/2 - 1 + nminus;
00832             is_even2 = !(nremain & 1);
00833             if (is_even2) 
00834                 value = 0.5*(work[nm] + work[nm+1]);
00835             else 
00836                 if (nremain < 3) 
00837                     value = work[nmm];
00838                 else 
00839                     value = 0.5*work[nmm] + 0.25*(work[nmm-1] + work[nmm+1]);
00840         }
00841 
00842         /* Store the result away */
00843 
00844         odata[i] = value;
00845         omask[i] = 0;
00846         rmask[i] = min(255,nrej);
00847         rplus[i] = min(255,nplus);
00848     }
00849 
00850     /* Get rid of workspace */
00851 
00852     cpl_free(work);
00853 }
00854 
00855 /*---------------------------------------------------------------------------*/
00878 /*---------------------------------------------------------------------------*/
00879 
00880 static void meancalc(float thresh, float avskynoise, int scaletype) {
00881     int nf2,k,nrej,nplus,nrejmax,kk,krem;
00882     long i,nn;
00883     float *work,value,value2,maxresid,resid,fresid,cliplev;
00884     unsigned char *iflag;
00885 
00886     /* Get vectors for workspace */
00887 
00888     work = cpl_malloc(nf*sizeof(*work));
00889     iflag = cpl_malloc(nf*sizeof(unsigned char));
00890 
00891     /* Ok, loop for each pixel... */
00892 
00893     cliplev = thresh*avskynoise;
00894     for (i = 0; i < npts; i++) {
00895 
00896         /* Scale or shift data */
00897 
00898         nn = 0;
00899         switch (scaletype) {
00900         case 0:
00901             for (k = 0; k < nf; k++) {
00902                 if (masks[k][i])
00903                     continue;
00904                 work[nn++] = datas[k][i];
00905             }
00906             break;
00907         case 1:
00908             for (k = 0; k < nf; k++) {
00909                 if (masks[k][i])
00910                     continue;
00911                 work[nn++] = datas[k][i] + (fileptrs+k)->skyfudge;
00912             }
00913             break;
00914         case 2:
00915             for (k = 0; k < nf; k++) {
00916                 if (masks[k][i])
00917                     continue;
00918                 work[nn++] = datas[k][i]*(fileptrs+k)->skyfudge;
00919             }
00920             break;
00921         case 3:
00922             for (k = 0; k < nf; k++) {
00923                 if (masks[k][i])
00924                     continue;
00925                 work[nn++] = datas[k][i] + (fileptrs+k)->skyfudge;
00926             }
00927             break;
00928         }
00929         
00930         /* If nothing is available, then flag the output pixel */
00931 
00932         if (nn == 0) {
00933             odata[i] = 0;
00934             omask[i] = 1;
00935             rmask[i] = 0;
00936             rplus[i] = 0;
00937             continue;
00938         }
00939             
00940         /* Get the mean */
00941         
00942         value = 0.0;
00943         for (k = 0; k < nn; k++) {
00944             value += work[k];
00945             iflag[k] = 0;
00946         }
00947         value /= (float)nn;
00948 
00949         /* Enter a rejection loop  */
00950         
00951         nrejmax = nn - 1;
00952         nplus = 0;
00953         nf2 = 0;
00954         for (kk = 0; kk < nrejmax; kk++) {
00955             maxresid = 0.0;
00956             krem = -1;
00957             for (k = 0; k < nn; k++) {
00958                 if (iflag[k] == 1) 
00959                     continue;
00960                 resid = work[k] - value;
00961                 fresid = (float)fabs((double)resid);
00962                 if (fresid > cliplev) {
00963                     if (fresid > maxresid) {
00964                         krem = k;
00965                         maxresid = fresid;
00966                     }
00967                 }
00968             }
00969             if (krem == -1)
00970                 break;
00971             if ((work[krem] - value) > 0.0)
00972                 nplus++;
00973             value2 = 0.0;
00974             iflag[krem] = 1;
00975             nf2 = 0;
00976             for (k = 0; k < nn; k++) {
00977                 if (iflag[k] == 0) {
00978                     value2 += work[k];
00979                     nf2 += 1;
00980                 }
00981             }
00982             value = value2/(float)nf2;
00983         }
00984 
00985         /* If you've clipped any, then recalculate the mean...*/
00986 
00987         nrej = nn - nf2;
00988 
00989         /* Store the result away */
00990 
00991         odata[i] = value;
00992         omask[i] = 0;
00993         rmask[i] = min(255,nrej);
00994         rplus[i] = min(255,nplus);
00995     }
00996 
00997     /* Get rid of workspace */
00998 
00999     cpl_free(work);
01000     cpl_free(iflag);
01001 }
01002             
01003 /*---------------------------------------------------------------------------*/
01028 /*---------------------------------------------------------------------------*/
01029 
01030 static void skyest(float *data, cpl_binary *mask, float thresh, float *skymed, 
01031                    float *skynoise) {
01032     unsigned char *bpm;
01033 
01034     /* Set up the bad pixel mask */
01035 
01036     bpm = (unsigned char *)mask;
01037 
01038     /* Get the stats */
01039 
01040     vircam_qmedsig(data,bpm,npts,thresh,3,-65535.0,65535.0,skymed,
01041                    skynoise);
01042 
01043 }
01044 
01045 /*---------------------------------------------------------------------------*/
01049 /*---------------------------------------------------------------------------*/
01050 
01051 static void tidy(void) {
01052     int i;
01053 
01054     /* Free up work space associated with file structures */
01055 
01056     freespace(fileptrs);
01057     for (i = 0; i < nf; i++)
01058         freespace(datas[i]);
01059     freespace(datas);
01060     freespace(masks);
01061 }
01062 
01066 /*
01067 
01068 $Log: vircam_imcombine.c,v $
01069 Revision 1.30  2012/01/27 12:25:10  jim
01070 Fixed some casts
01071 
01072 Revision 1.29  2012/01/15 17:40:09  jim
01073 Minor modifications to take into accout the changes in cpl API for v6
01074 
01075 Revision 1.28  2010/07/13 11:16:50  jim
01076 A few changes to deal with compiler whinges
01077 
01078 Revision 1.27  2010/06/03 12:15:31  jim
01079 A few mods to get rid of compiler warnings
01080 
01081 Revision 1.26  2008/10/13 08:14:23  jim
01082 Will now take object masks into account
01083 
01084 Revision 1.25  2008/09/29 11:27:53  jim
01085 Fixed bug in median clipping algorithm. Also fixed a bug that stopped the
01086 scaling from working in some cases
01087 
01088 Revision 1.24  2007/05/14 15:26:03  jim
01089 Fixed bug in multiplicative scaling
01090 
01091 Revision 1.23  2007/03/29 12:19:39  jim
01092 Little changes to improve documentation
01093 
01094 Revision 1.22  2007/03/01 12:42:41  jim
01095 Modified slightly after code checking
01096 
01097 Revision 1.21  2006/10/02 13:47:33  jim
01098 Added missing .h file to include list
01099 
01100 Revision 1.20  2006/09/08 09:21:37  jim
01101 Fixed bug in median routine
01102 
01103 Revision 1.19  2006/08/21 09:08:10  jim
01104 Fixed a few subtle bugs in the median routines
01105 
01106 Revision 1.18  2006/07/04 09:19:05  jim
01107 replaced all sprintf statements with snprintf
01108 
01109 Revision 1.17  2006/05/08 10:56:14  jim
01110 Fixed bug where exposure time scaling was not happening to the data copy
01111 
01112 Revision 1.16  2006/04/20 11:26:45  jim
01113 Fixed so that original data isn't modified in the input vir_fits list.
01114 
01115 Revision 1.15  2006/03/23 21:18:48  jim
01116 Minor changes mainly to comment headers
01117 
01118 Revision 1.14  2006/03/22 13:58:31  jim
01119 Cosmetic fixes to keep lint happy
01120 
01121 Revision 1.13  2006/03/08 14:32:21  jim
01122 Lots of little modifications
01123 
01124 Revision 1.12  2006/03/03 14:29:46  jim
01125 Modified definition of vir_fits and channel table
01126 
01127 Revision 1.11  2006/03/01 10:31:28  jim
01128 Now uses new vir_fits objects
01129 
01130 Revision 1.10  2006/02/22 10:09:09  jim
01131 Added status variable to call
01132 
01133 Revision 1.9  2006/01/23 10:30:49  jim
01134 Mainly documentation mods
01135 
01136 Revision 1.8  2005/12/14 22:17:33  jim
01137 Updated docs
01138 
01139 Revision 1.7  2005/11/29 11:54:19  jim
01140 Modified call in skyest to allow for larger negative numbers as it is
01141 likely that the reset frames will be negative.
01142 
01143 Revision 1.6  2005/11/25 09:56:15  jim
01144 Tidied up some more documentation
01145 
01146 Revision 1.5  2005/11/08 12:47:44  jim
01147 Made garbage collection a little better
01148 
01149 Revision 1.4  2005/11/07 13:15:16  jim
01150 Fixed lots of bugs and added some error checking
01151 
01152 Revision 1.3  2005/11/03 13:28:49  jim
01153 All sorts of changes to tighten up error handling
01154 
01155 Revision 1.2  2005/10/14 13:17:54  jim
01156 Now spews out a mask of rejected pixels and rejected positive pixels
01157 (indicative of cosmic ray hits)
01158 
01159 Revision 1.1.1.1  2005/08/05 08:29:09  jim
01160 Initial import
01161 
01162 
01163 */
01164 

Generated on 5 Mar 2013 for VIRCAM Pipeline by  doxygen 1.6.1