vircam_imdither.c

00001 /* $Id: vircam_imdither.c,v 1.14 2007/10/25 17:34:00 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: 2007/10/25 17:34:00 $
00024  * $Revision: 1.14 $
00025  * $Name:  $
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 #include "vircam_mods.h"
00037 #include "vircam_utils.h"
00038 #include "vircam_fits.h"
00039 #include "vircam_stats.h"
00040 #include "vircam_pfits.h"
00041 
00042 typedef struct {
00043     vir_fits  *fname;
00044     vir_fits  *conf;
00045     float     xoff;
00046     float     yoff;
00047     int       ixoff;
00048     int       iyoff;
00049     int       nx;
00050     int       ny;
00051     float     sky;
00052     float     skydiff;
00053     float     noise;
00054     float     expscale;
00055     float     weight;
00056     float     *data;
00057     int       *cdata;
00058     int       ndata;
00059 } dstrct;
00060 
00061 typedef struct {
00062     float         *values;
00063     float         *confs;
00064     float         *weights;
00065     short int     *iff;
00066     int           n;
00067     long          outindex;
00068     unsigned char clipped;
00069 } keeptabs;
00070 
00071 #define NROWSBUF 512
00072 
00073 static dstrct *fileptrs = NULL;
00074 static float *odata = NULL;
00075 static float *owdata = NULL;
00076 static keeptabs *clipmon = NULL;
00077 
00078 static float lsig;
00079 static float hsig;
00080 static float sumweight;
00081 static int   nxo;
00082 static int   nyo;
00083 
00084 static void average(keeptabs *, float *, float *, float, float, float);
00085 static keeptabs *clip_open( int);
00086 static void clip_close(keeptabs **);
00087 static void fileptrs_close(void);
00088 static void skyest(float *, long, float, float *, float *);
00089 static void tidy(void);
00090 
00093 /*---------------------------------------------------------------------------*/
00154 /*---------------------------------------------------------------------------*/
00155     
00156 extern int vircam_imdither(vir_fits **inf, vir_fits **inconf, int nimages, 
00157                            int nconfs, float lthr, float hthr,
00158                            cpl_propertylist **p, cpl_image **out, 
00159                            cpl_image **outc, int *status) {
00160 
00161     int i,itx,iy,ccur,clast,ix,n,iline,icol,jy,jx,*ocdata;
00162     long npts,ielm,iloc,index_y,index;
00163     dstrct *dd;
00164     keeptabs *c;
00165     float minxoff,minyoff,expref,sky,skynoise,clip1,clip2,outdata;
00166     float outconf,avlev,avvar,renorm,exposure;
00167     double crpix1,crpix2;
00168     cpl_propertylist *ehu,*p2;
00169     const char *fctid = "vircam_imdither";
00170     char timestamp[25];
00171 
00172     /* Inherited status */
00173 
00174     *out = NULL;
00175     *outc = NULL;
00176     *p = NULL;
00177     if (*status != VIR_OK)
00178         return(*status);
00179 
00180     /* Is there any point in being here? */
00181 
00182     if (nimages == 0) {
00183         cpl_msg_error(fctid,"No input files to combine");
00184         tidy();
00185         FATAL_ERROR
00186     }
00187 
00188     /* Initialise some global variables */
00189 
00190     lsig = lthr;
00191     hsig = hthr;
00192 
00193     /* Allocate file struct array and fill in some values */
00194 
00195     fileptrs = cpl_malloc(nimages*sizeof(dstrct));
00196     (void)vircam_pfits_get_exptime(vircam_fits_get_phu(inf[0]),&exposure);
00197     expref = max(0.5,exposure);
00198     minxoff = 1.0e10;
00199     minyoff = 1.0e10;
00200     for (i = 0; i < nimages; i++) {
00201         dd = fileptrs + i;
00202         dd->fname = inf[i];
00203         dd->data = cpl_image_get_data_float(vircam_fits_get_image(inf[i]));
00204         if (nconfs == 0) {
00205             dd->conf = NULL;
00206         } else if (nconfs == 1) {
00207             dd->conf = inconf[0];
00208             dd->cdata = cpl_image_get_data_int(vircam_fits_get_image(inconf[0]));
00209         } else {
00210             dd->conf = inconf[i];
00211             dd->cdata = cpl_image_get_data_int(vircam_fits_get_image(inconf[i]));
00212         }
00213         ehu = vircam_fits_get_ehu(dd->fname);
00214         (void)vircam_pfits_get_jxoff(ehu,&(dd->xoff));
00215         (void)vircam_pfits_get_jyoff(ehu,&(dd->yoff));
00216         minxoff = min(dd->xoff,minxoff);
00217         minyoff = min(dd->yoff,minyoff);
00218         (void)vircam_pfits_get_exptime(ehu,&exposure);
00219         dd->expscale = exposure/expref;
00220 
00221         /* Now work out a background and background noise estimate */
00222 
00223         dd->nx = cpl_image_get_size_x(vircam_fits_get_image(dd->fname));
00224         dd->ny = cpl_image_get_size_y(vircam_fits_get_image(dd->fname));
00225         npts = dd->nx*dd->ny;
00226         skyest(dd->data,npts,3.0,&sky,&skynoise);
00227         dd->sky = sky;
00228         dd->noise = skynoise;
00229         
00230         /* Double check to make sure the confidence maps and images have the
00231            same dimensions */
00232 
00233         if (cpl_image_get_size_x(vircam_fits_get_image(dd->conf)) != dd->nx || 
00234             cpl_image_get_size_y(vircam_fits_get_image(dd->conf)) != dd->ny) {
00235             cpl_msg_error(fctid,"VIRCAM_IMDITHER: Image %s and Confidence map %s don't match",
00236                           vircam_fits_get_fullname(dd->fname),
00237                           vircam_fits_get_fullname(dd->conf));
00238             tidy();
00239             FATAL_ERROR
00240         }
00241     }
00242 
00243     /* Redo the offsets so that they are all positive. */
00244 
00245     for (i = 0; i < nimages; i++) {
00246         dd = fileptrs + i;
00247         dd->xoff -= minxoff;
00248         dd->yoff -= minyoff;
00249         dd->ixoff = (int)(dd->xoff + 0.5);
00250         dd->iyoff = (int)(dd->yoff + 0.5);
00251     }
00252 
00253     /* Redo the zero point offsets so that they are all relative to
00254        the first image in the list. Make sure to divide by the relative
00255        exposure time first! Set up weights*/
00256 
00257     fileptrs->sky /= fileptrs->expscale;
00258     fileptrs->skydiff = 0.0;
00259     fileptrs->weight = 1.0;
00260     sumweight = 1.0;
00261     for (i = 1; i < nimages; i++) {
00262         dd = fileptrs + i;
00263         dd->sky /= dd->expscale;
00264         dd->skydiff = fileptrs->sky - dd->sky;
00265         dd->noise /= (float)sqrt((double)dd->expscale);
00266         dd->weight = (float)(pow((double)fileptrs->noise,2.0)/pow((double)dd->noise,2.0)); 
00267         sumweight += dd->weight;
00268     }
00269 
00270     /* Set up clipping levels */
00271 
00272     clip1 = fileptrs->sky - lthr*fileptrs->noise;
00273     clip2 = fileptrs->sky + hthr*fileptrs->noise;
00274 
00275     /* Open the output file. First of all work out how big the output map
00276        needs to be. Then create it based on the first image in the list */
00277 
00278     nxo = 0;
00279     nyo = 0;
00280     for (i = 0; i < nimages; i++) {
00281         dd = fileptrs + i;
00282         itx = dd->nx + dd->ixoff;
00283         nxo = max(nxo,itx);
00284         itx = dd->ny + dd->iyoff;
00285         nyo = max(nyo,itx);
00286     }
00287 
00288     /* Create the output image */
00289 
00290     *out = cpl_image_new(nxo,nyo,CPL_TYPE_FLOAT);
00291 
00292     /* If an output confidence map has been specified, then create it now. */
00293 
00294     if (nconfs != 0) 
00295         *outc = cpl_image_new(nxo,nyo,CPL_TYPE_INT);
00296     else 
00297         *outc = NULL;
00298 
00299     /* Get the data arrays for the output images */
00300 
00301     npts = nxo*nyo;
00302     odata = cpl_image_get_data_float(*out);
00303     if (*outc != NULL) 
00304         owdata = cpl_malloc(npts*sizeof(float));
00305     clipmon = clip_open(nimages);
00306 
00307     /* Right, now try and do the work. Start by deciding whether for a given
00308        output line an input line is able to contribute */
00309 
00310     for (iy = 0; iy < nyo; iy++) {
00311         ccur = (iy % 2)*nxo;
00312         clast = nxo - ccur;
00313         for (ix = 0; ix < nxo; ix++) {
00314             c = clipmon + ccur + ix;
00315             c->n = 0;
00316             c->clipped = 0;
00317             n = 0;
00318             for (i = 0; i < nimages; i++) {             
00319                 dd = fileptrs + i;
00320                 iline = iy - dd->iyoff;
00321                 if (iline < 0 || iline >= dd->ny)
00322                     continue;
00323                 icol = ix - dd->ixoff;
00324                 if (icol < 0 || icol >= dd->nx)
00325                     continue;
00326 
00327                 /* Load up any input data for this pixel from the current 
00328                    image */
00329                 
00330                 ielm = dd->nx*iline + icol;
00331                 c->values[n] = dd->data[ielm];
00332                 c->confs[n] = dd->cdata[ielm];
00333                 c->weights[n] = dd->weight;
00334                 c->iff[n] = (short int)i;
00335                 n++;
00336             }
00337             c->outindex = nxo*iy + ix;
00338             c->n = n;
00339             average(c,&outdata,&outconf,clip1,clip2,0.0);
00340             odata[c->outindex] = outdata;
00341             if (owdata != NULL) 
00342                 owdata[c->outindex] = outconf;
00343         }
00344 
00345         /* If we're away from the edges, have a look and see which pixels in
00346            the previous row had clipping. Evaluate whether that clipping was
00347            really justified or not */
00348 
00349         if (iy < 2)
00350             continue;
00351         for (ix = 1; ix < nxo-1; ix++) {
00352             c = clipmon + clast + ix;
00353             if (! c->clipped)
00354                 continue;
00355 
00356             /* If it was clipped, then evaluate the amount of 'noise' there 
00357                is spatially */
00358 
00359             iloc = c->outindex;
00360             avlev = 0.0;
00361             for (jy = -1; jy <= 1; jy++) {
00362                 index_y = iloc + jy*nxo;
00363                 for (jx = -1; jx <= 1; jx++) {
00364                     index = index_y + jx;
00365                     avlev += odata[index];
00366                 }
00367             }
00368             avlev /= 9.0;
00369             avvar = 0.0;
00370             for (jy = -1; jy <= 1; jy++) {
00371                 index_y = iloc + jy*nxo;
00372                 for (jx = -1; jx <= 1; jx++) {
00373                     index = index_y + jx;
00374                     avvar += fabs(odata[index] - avlev);
00375                 }
00376             }
00377             avvar /= 9.0;
00378 
00379             /* If the average level in this cell is below the upper clip level
00380                or the mean absolute deviation is smaller than the poisson 
00381                noise in the cell, then the clip was probably justified. */
00382 
00383             if (avlev < clip2 || avvar <= 2.0*fileptrs->noise)
00384                 continue;
00385 
00386             /* Otherwise, create new clip levels and redo the average */
00387 
00388             average(c,&outdata,&outconf,clip1,clip2,3.0*avvar);
00389             odata[c->outindex] = outdata;
00390             if (owdata != NULL) 
00391                 owdata[c->outindex] = outconf;
00392         }
00393     }
00394     
00395     /* Normalise the output confidence map */
00396     
00397     if (owdata != NULL) {
00398         skyest(owdata,npts,3.0,&sky,&skynoise);
00399         renorm = 100.0/sky;
00400         ocdata = cpl_image_get_data_int(*outc);
00401         for (i = 0; i < npts; i++) 
00402             ocdata[i] = max(0,min(110,((int)(owdata[i]*renorm + 0.5))));
00403     }
00404 
00405     /* Create the output propertylist with some provenance info */
00406 
00407     *p = cpl_propertylist_duplicate(vircam_fits_get_ehu(inf[0]));    
00408     vircam_prov(*p,inf,nimages);
00409 
00410     /* Add a timestamp to the propertylist */
00411 
00412     vircam_timestamp(timestamp,25);
00413     p2 = vircam_fits_get_phu(inf[0]);
00414     cpl_propertylist_update_string(p2,"VIR_TIME",timestamp);
00415     cpl_propertylist_set_comment(p2,"VIR_TIME",
00416                                  "Timestamp for matching to conf map");
00417 
00418     /* Update the WCS in the header to reflect the new offset */
00419 
00420     (void)vircam_pfits_get_crpix1(*p,&crpix1);
00421     (void)vircam_pfits_get_crpix2(*p,&crpix2);
00422     crpix1 += fileptrs->xoff;
00423     crpix2 += fileptrs->yoff;
00424     cpl_propertylist_update_double(*p,"CRPIX1",crpix1);
00425     cpl_propertylist_update_double(*p,"CRPIX2",crpix2);
00426 
00427     /* Get out of here */
00428 
00429     tidy();
00430     GOOD_STATUS
00431 }
00432 
00433 static void average(keeptabs *c, float *outdata, float *outconf, float cliplow,
00434                     float cliphigh, float extra) {
00435     int i,imin,imax;
00436     float valuemax,valuemin,cwmin,cwmax,sum,cnumb,numb,cw,cv,reflev,noise;
00437     float sky,clipval;
00438     
00439     /* If there aren't any pixels defined for this (kind of a funny state
00440        to be in, but never mind), give it some nominal value, which is the
00441        sky background of the first input image. Flag it with zero confidence */
00442     
00443     if (c->n <= 0) {
00444         *outdata = fileptrs->sky;
00445         *outconf = 0.0;
00446         return;
00447     }
00448     
00449     /* Initialise a few things (avoid boring compiler errors about 
00450        uninitialised variables */
00451     
00452     valuemin = 1.0e10;
00453     valuemax = -1.0e10;
00454     cwmin = 1.0e10;
00455     cwmax = -1.0e10;
00456     imin = 0;
00457     imax = 0;
00458     sum = 0.0;
00459     cnumb = 0.0;
00460     numb = 0.0;
00461     
00462     /* Now loop through all the data for this point, keeping track of the 
00463        min and max */
00464     
00465     for (i = 0; i < c->n; i++) {
00466         cw = c->weights[i]*c->confs[i];
00467         cv = c->values[i];
00468         sum += cv*cw;
00469         cnumb +=cw;
00470         numb += c->confs[i];
00471         if (cv < valuemin) {
00472             valuemin = cv;
00473             cwmin = cw;
00474             imin = i;
00475         } 
00476         if (cv > valuemax) {
00477             valuemax = cv;
00478             cwmax = cw;
00479             imax = i;
00480         }
00481     }
00482     if (cnumb > 0.0)
00483         *outdata = sum/cnumb;
00484     else
00485         *outdata = fileptrs->sky;
00486 
00487     /* See if we need to clip. Look at bright one first */
00488     
00489     if (valuemax > cliphigh && numb > 150.0 && cnumb > 150.0) {
00490         reflev = (sum - valuemax*cwmax)/(cnumb - cwmax);
00491         noise = (fileptrs+c->iff[imax])->noise;
00492         sky = (fileptrs+c->iff[imax])->sky;
00493         clipval = reflev + hsig*noise*max(1.0,reflev)/max(1.0,sky) + extra;
00494         if (valuemax > clipval) {
00495             sum -= valuemax*cwmax;
00496             cnumb -= cwmax;
00497             *outdata = reflev;
00498             c->clipped = 1;
00499         }
00500     }
00501     
00502     /* Now look at the lowest value */
00503     
00504     if (valuemin < cliplow && numb > 150.0 && cnumb > 150.0) {
00505         reflev = (sum - valuemin*cwmin)/(cnumb - cwmin);
00506         noise = (fileptrs+c->iff[imin])->noise;
00507         clipval = reflev - lsig*noise;
00508         if (valuemin < clipval) {
00509             cnumb -= cwmin;
00510             *outdata = reflev;
00511         }
00512     }
00513     
00514     /* Do the output confidence */
00515     
00516     *outconf = cnumb/sumweight;
00517 }
00518         
00519     
00520 static keeptabs *clip_open(int nimages) {
00521     keeptabs *c;
00522     int i;
00523     short int *iff;
00524     float *dptr;
00525 
00526     c = cpl_malloc(2*nxo*sizeof(keeptabs));
00527     for (i = 0; i < 2*nxo; i++) {
00528         dptr = cpl_malloc(3*nimages*sizeof(*dptr));
00529         iff = cpl_malloc(nimages*sizeof(*iff));
00530         (c+i)->values = dptr;
00531         (c+i)->confs = dptr + nimages;
00532         (c+i)->weights = dptr + 2*nimages;
00533         (c+i)->iff = iff;
00534         (c+i)->n = 0;
00535         (c+i)->outindex = -1;
00536         (c+i)->clipped = 0;
00537     }
00538     return(c);
00539 }
00540 
00541 static void clip_close(keeptabs **c) {
00542     int i;
00543 
00544     for (i = 0; i < 2*nxo; i++) {
00545         freespace((*c+i)->values);
00546         freespace((*c+i)->iff);
00547     }
00548     freespace(*c);
00549 }
00550 
00551 static void fileptrs_close(void) {
00552 
00553 
00554     freespace(fileptrs);
00555 }    
00556 
00557 
00558 static void skyest(float *data, long npts, float thresh, float *skymed,
00559                    float *skynoise) {
00560     unsigned char *bpm;
00561 
00562     /* Get a dummy bad pixel mask */
00563 
00564     bpm = cpl_calloc(npts,sizeof(*bpm));
00565 
00566     /* Get the stats */
00567 
00568     vircam_qmedsig(data,bpm,npts,thresh,2,-1000.0,65535.0,skymed,skynoise);
00569 
00570     /* Clean up */
00571 
00572     freespace(bpm);
00573 }
00574 
00575 static void tidy(void) {
00576 
00577     freespace(owdata);
00578     clip_close(&clipmon);
00579     fileptrs_close();
00580 }    
00581 
00584 /*
00585 
00586 $Log: vircam_imdither.c,v $
00587 Revision 1.14  2007/10/25 17:34:00  jim
00588 Modified to remove lint warnings
00589 
00590 Revision 1.13  2007/03/29 12:19:39  jim
00591 Little changes to improve documentation
00592 
00593 Revision 1.12  2007/03/01 12:42:41  jim
00594 Modified slightly after code checking
00595 
00596 Revision 1.11  2006/11/27 12:05:49  jim
00597 Changed call from cpl_propertylist_append to cpl_propertylist_update
00598 
00599 Revision 1.10  2006/10/02 13:47:33  jim
00600 Added missing .h file to include list
00601 
00602 Revision 1.9  2006/06/13 21:25:41  jim
00603 Fixed bug in normalising the offsets
00604 
00605 Revision 1.8  2006/06/09 22:25:06  jim
00606 tidied up a few bugs
00607 
00608 Revision 1.7  2006/06/09 11:26:26  jim
00609 Small changes to keep lint happy
00610 
00611 Revision 1.6  2006/06/08 14:53:18  jim
00612 Modified a few things to keep lint happy
00613 
00614 Revision 1.5  2006/06/06 13:05:52  jim
00615 Adds VIR_TIME to primary header
00616 
00617 Revision 1.4  2006/05/26 15:03:32  jim
00618 Fixed bug where status variable address was being changed
00619 
00620 Revision 1.3  2006/05/18 09:48:16  jim
00621 fixed docs
00622 
00623 Revision 1.2  2006/05/17 12:07:12  jim
00624 Fixed error condition returns
00625 
00626 Revision 1.1  2006/05/15 13:14:45  jim
00627 new routine
00628 
00629 
00630 */

Generated on Wed Apr 10 04:01:56 2013 for VIRCAM Pipeline by  doxygen 1.5.1