vircam_imdither.c

00001 /* $Id: vircam_imdither.c,v 1.19 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.19 $
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 #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 *, int *, 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,j;
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(vircam_fits_get_phu(dd->fname),&exposure);
00219         dd->expscale = exposure/expref;
00220 
00221         /* Now work out a background and background noise estimate */
00222 
00223         dd->nx = (int)cpl_image_get_size_x(vircam_fits_get_image(dd->fname));
00224         dd->ny = (int)cpl_image_get_size_y(vircam_fits_get_image(dd->fname));
00225         npts = dd->nx*dd->ny;
00226         skyest(dd->data,dd->cdata,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 ((int)cpl_image_get_size_x(vircam_fits_get_image(dd->conf)) != dd->nx || 
00234             (int)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     /* Scale data (don't do image 0 since that has 1 scale and 0 offset) */
00271 
00272     for (i = 1; i < nimages; i++) {
00273         dd = fileptrs + i;
00274         npts = dd->nx*dd->ny;
00275         for (j = 0; j < npts; j++) 
00276             dd->data[j] = dd->data[j]/dd->expscale + dd->skydiff;
00277     }
00278 
00279     /* Set up clipping levels */
00280 
00281     clip1 = fileptrs->sky - lthr*fileptrs->noise;
00282     clip2 = fileptrs->sky + hthr*fileptrs->noise;
00283 
00284     /* Open the output file. First of all work out how big the output map
00285        needs to be. Then create it based on the first image in the list */
00286 
00287     nxo = 0;
00288     nyo = 0;
00289     for (i = 0; i < nimages; i++) {
00290         dd = fileptrs + i;
00291         itx = dd->nx + dd->ixoff;
00292         nxo = max(nxo,itx);
00293         itx = dd->ny + dd->iyoff;
00294         nyo = max(nyo,itx);
00295     }
00296 
00297     /* Create the output image */
00298 
00299     *out = cpl_image_new((cpl_size)nxo,(cpl_size)nyo,CPL_TYPE_FLOAT);
00300 
00301     /* If an output confidence map has been specified, then create it now. */
00302 
00303     if (nconfs != 0) 
00304         *outc = cpl_image_new((cpl_size)nxo,(cpl_size)nyo,CPL_TYPE_INT);
00305     else 
00306         *outc = NULL;
00307 
00308     /* Get the data arrays for the output images */
00309 
00310     npts = nxo*nyo;
00311     odata = cpl_image_get_data_float(*out);
00312     if (*outc != NULL) 
00313         owdata = cpl_malloc(npts*sizeof(float));
00314     clipmon = clip_open(nimages);
00315 
00316     /* Right, now try and do the work. Start by deciding whether for a given
00317        output line an input line is able to contribute */
00318 
00319     for (iy = 0; iy < nyo; iy++) {
00320         ccur = (iy % 2)*nxo;
00321         clast = nxo - ccur;
00322         for (ix = 0; ix < nxo; ix++) {
00323             c = clipmon + ccur + ix;
00324             c->n = 0;
00325             c->clipped = 0;
00326             n = 0;
00327             for (i = 0; i < nimages; i++) {             
00328                 dd = fileptrs + i;
00329                 iline = iy - dd->iyoff;
00330                 if (iline < 0 || iline >= dd->ny)
00331                     continue;
00332                 icol = ix - dd->ixoff;
00333                 if (icol < 0 || icol >= dd->nx)
00334                     continue;
00335 
00336                 /* Load up any input data for this pixel from the current 
00337                    image */
00338                 
00339                 ielm = dd->nx*iline + icol;
00340                 c->values[n] = dd->data[ielm];
00341                 c->confs[n] = dd->cdata[ielm];
00342                 c->weights[n] = dd->weight;
00343                 c->iff[n] = (short int)i;
00344                 n++;
00345             }
00346             c->outindex = nxo*iy + ix;
00347             c->n = n;
00348             average(c,&outdata,&outconf,clip1,clip2,0.0);
00349             odata[c->outindex] = outdata;
00350             if (owdata != NULL) 
00351                 owdata[c->outindex] = outconf;
00352         }
00353 
00354         /* If we're away from the edges, have a look and see which pixels in
00355            the previous row had clipping. Evaluate whether that clipping was
00356            really justified or not */
00357 
00358         if (iy < 2)
00359             continue;
00360         for (ix = 1; ix < nxo-1; ix++) {
00361             c = clipmon + clast + ix;
00362             if (! c->clipped)
00363                 continue;
00364 
00365             /* If it was clipped, then evaluate the amount of 'noise' there 
00366                is spatially */
00367 
00368             iloc = c->outindex;
00369             avlev = 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                     avlev += odata[index];
00375                 }
00376             }
00377             avlev /= 9.0;
00378             avvar = 0.0;
00379             for (jy = -1; jy <= 1; jy++) {
00380                 index_y = iloc + jy*nxo;
00381                 for (jx = -1; jx <= 1; jx++) {
00382                     index = index_y + jx;
00383                     avvar += fabs(odata[index] - avlev);
00384                 }
00385             }
00386             avvar /= 9.0;
00387 
00388             /* If the average level in this cell is below the upper clip level
00389                or the mean absolute deviation is smaller than the poisson 
00390                noise in the cell, then the clip was probably justified. */
00391 
00392             if (avlev < clip2 || avvar <= 2.0*fileptrs->noise)
00393                 continue;
00394 
00395             /* Otherwise, create new clip levels and redo the average */
00396 
00397             average(c,&outdata,&outconf,clip1,clip2,3.0*avvar);
00398             odata[c->outindex] = outdata;
00399             if (owdata != NULL) 
00400                 owdata[c->outindex] = outconf;
00401         }
00402     }
00403     
00404     /* Normalise the output confidence map */
00405     
00406     if (owdata != NULL) {
00407         skyest(owdata,NULL,npts,3.0,&sky,&skynoise);
00408         renorm = 100.0/sky;
00409         ocdata = cpl_image_get_data_int(*outc);
00410         for (i = 0; i < npts; i++) 
00411             ocdata[i] = max(0,min(1000,((int)(owdata[i]*renorm + 0.5))));
00412     }
00413 
00414     /* Create the output propertylist with some provenance info */
00415 
00416     *p = cpl_propertylist_duplicate(vircam_fits_get_ehu(inf[0]));    
00417     vircam_prov(*p,inf,nimages);
00418 
00419     /* Add a timestamp to the propertylist */
00420 
00421     vircam_timestamp(timestamp,25);
00422     p2 = vircam_fits_get_phu(inf[0]);
00423     cpl_propertylist_update_string(p2,"VIR_TIME",timestamp);
00424     cpl_propertylist_set_comment(p2,"VIR_TIME",
00425                                  "Timestamp for matching to conf map");
00426 
00427     /* Update the WCS in the header to reflect the new offset */
00428 
00429     (void)vircam_pfits_get_crpix1(*p,&crpix1);
00430     (void)vircam_pfits_get_crpix2(*p,&crpix2);
00431     crpix1 += fileptrs->xoff;
00432     crpix2 += fileptrs->yoff;
00433     cpl_propertylist_update_double(*p,"CRPIX1",crpix1);
00434     cpl_propertylist_update_double(*p,"CRPIX2",crpix2);
00435 
00436     /* Get out of here */
00437 
00438     tidy();
00439     GOOD_STATUS
00440 }
00441 
00442 static void average(keeptabs *c, float *outdata, float *outconf, float cliplow,
00443                     float cliphigh, float extra) {
00444     int i,imin,imax;
00445     float valuemax,valuemin,cwmin,cwmax,sum,cnumb,numb,cw,cv,reflev,noise;
00446     float sky,clipval;
00447     
00448     /* If there aren't any pixels defined for this (kind of a funny state
00449        to be in, but never mind), give it some nominal value, which is the
00450        sky background of the first input image. Flag it with zero confidence */
00451     
00452     if (c->n <= 0) {
00453         *outdata = fileptrs->sky;
00454         *outconf = 0.0;
00455         return;
00456     }
00457     
00458     /* Initialise a few things (avoid boring compiler errors about 
00459        uninitialised variables */
00460     
00461     valuemin = 1.0e10;
00462     valuemax = -1.0e10;
00463     cwmin = 1.0e10;
00464     cwmax = -1.0e10;
00465     imin = 0;
00466     imax = 0;
00467     sum = 0.0;
00468     cnumb = 0.0;
00469     numb = 0.0;
00470     
00471     /* Now loop through all the data for this point, keeping track of the 
00472        min and max */
00473     
00474     for (i = 0; i < c->n; i++) {
00475         cw = c->weights[i]*c->confs[i];
00476         cv = c->values[i];
00477         sum += cv*cw;
00478         cnumb +=cw;
00479         numb += c->confs[i];
00480         if (cv < valuemin) {
00481             valuemin = cv;
00482             cwmin = cw;
00483             imin = i;
00484         } 
00485         if (cv > valuemax) {
00486             valuemax = cv;
00487             cwmax = cw;
00488             imax = i;
00489         }
00490     }
00491     if (cnumb > 0.0)
00492         *outdata = sum/cnumb;
00493     else
00494         *outdata = fileptrs->sky;
00495 
00496     /* See if we need to clip. Look at bright one first */
00497     
00498     if (valuemax > cliphigh && numb > 150.0 && cnumb > 150.0) {
00499         reflev = (sum - valuemax*cwmax)/(cnumb - cwmax);
00500         noise = (fileptrs+c->iff[imax])->noise;
00501         sky = (fileptrs+c->iff[imax])->sky;
00502         clipval = reflev + hsig*noise*max(1.0,reflev)/max(1.0,sky) + extra;
00503         if (valuemax > clipval) {
00504             sum -= valuemax*cwmax;
00505             cnumb -= cwmax;
00506             *outdata = reflev;
00507             c->clipped = 1;
00508         }
00509     }
00510     
00511     /* Now look at the lowest value */
00512     
00513     if (valuemin < cliplow && numb > 150.0 && cnumb > 150.0) {
00514         reflev = (sum - valuemin*cwmin)/(cnumb - cwmin);
00515         noise = (fileptrs+c->iff[imin])->noise;
00516         clipval = reflev - lsig*noise;
00517         if (valuemin < clipval) {
00518             cnumb -= cwmin;
00519             *outdata = reflev;
00520         }
00521     }
00522     
00523     /* Do the output confidence */
00524     
00525     *outconf = cnumb/sumweight;
00526 }
00527         
00528     
00529 static keeptabs *clip_open(int nimages) {
00530     keeptabs *c;
00531     int i;
00532     short int *iff;
00533     float *dptr;
00534 
00535     c = cpl_malloc(2*nxo*sizeof(keeptabs));
00536     for (i = 0; i < 2*nxo; i++) {
00537         dptr = cpl_malloc(3*nimages*sizeof(*dptr));
00538         iff = cpl_malloc(nimages*sizeof(*iff));
00539         (c+i)->values = dptr;
00540         (c+i)->confs = dptr + nimages;
00541         (c+i)->weights = dptr + 2*nimages;
00542         (c+i)->iff = iff;
00543         (c+i)->n = 0;
00544         (c+i)->outindex = -1;
00545         (c+i)->clipped = 0;
00546     }
00547     return(c);
00548 }
00549 
00550 static void clip_close(keeptabs **c) {
00551     int i;
00552 
00553     for (i = 0; i < 2*nxo; i++) {
00554         freespace((*c+i)->values);
00555         freespace((*c+i)->iff);
00556     }
00557     freespace(*c);
00558 }
00559 
00560 static void fileptrs_close(void) {
00561 
00562 
00563     freespace(fileptrs);
00564 }    
00565 
00566 
00567 static void skyest(float *data, int *cdata, long npts, float thresh, 
00568                    float *skymed, float *skynoise) {
00569     unsigned char *bpm;
00570     int i;
00571 
00572     /* Get a dummy bad pixel mask */
00573 
00574     bpm = cpl_calloc(npts,sizeof(*bpm));
00575     if (cdata != NULL) {
00576         for (i = 0; i < npts; i++) 
00577             bpm[i] = (cdata[i] == 0);
00578     }
00579 
00580     /* Get the stats */
00581 
00582     vircam_qmedsig(data,bpm,npts,thresh,2,-1000.0,65535.0,skymed,skynoise);
00583 
00584     /* Clean up */
00585 
00586     freespace(bpm);
00587 }
00588 
00589 static void tidy(void) {
00590 
00591     freespace(owdata);
00592     clip_close(&clipmon);
00593     fileptrs_close();
00594 }    
00595 
00598 /*
00599 
00600 $Log: vircam_imdither.c,v $
00601 Revision 1.19  2012/01/27 12:25:10  jim
00602 Fixed some casts
00603 
00604 Revision 1.18  2012/01/15 17:40:09  jim
00605 Minor modifications to take into accout the changes in cpl API for v6
00606 
00607 Revision 1.17  2009/11/17 10:04:14  jim
00608 Removed maximum limitation of 110 on output confidence
00609 
00610 Revision 1.16  2008/11/25 18:54:08  jim
00611 Background estimate now takes confidence map into account
00612 
00613 Revision 1.15  2008/08/28 09:03:31  jim
00614 Fixed bug that stopped the scaling being done properly
00615 
00616 Revision 1.14  2007/10/25 17:34:00  jim
00617 Modified to remove lint warnings
00618 
00619 Revision 1.13  2007/03/29 12:19:39  jim
00620 Little changes to improve documentation
00621 
00622 Revision 1.12  2007/03/01 12:42:41  jim
00623 Modified slightly after code checking
00624 
00625 Revision 1.11  2006/11/27 12:05:49  jim
00626 Changed call from cpl_propertylist_append to cpl_propertylist_update
00627 
00628 Revision 1.10  2006/10/02 13:47:33  jim
00629 Added missing .h file to include list
00630 
00631 Revision 1.9  2006/06/13 21:25:41  jim
00632 Fixed bug in normalising the offsets
00633 
00634 Revision 1.8  2006/06/09 22:25:06  jim
00635 tidied up a few bugs
00636 
00637 Revision 1.7  2006/06/09 11:26:26  jim
00638 Small changes to keep lint happy
00639 
00640 Revision 1.6  2006/06/08 14:53:18  jim
00641 Modified a few things to keep lint happy
00642 
00643 Revision 1.5  2006/06/06 13:05:52  jim
00644 Adds VIR_TIME to primary header
00645 
00646 Revision 1.4  2006/05/26 15:03:32  jim
00647 Fixed bug where status variable address was being changed
00648 
00649 Revision 1.3  2006/05/18 09:48:16  jim
00650 fixed docs
00651 
00652 Revision 1.2  2006/05/17 12:07:12  jim
00653 Fixed error condition returns
00654 
00655 Revision 1.1  2006/05/15 13:14:45  jim
00656 new routine
00657 
00658 
00659 */

Generated on 5 Mar 2013 for VIRCAM Pipeline by  doxygen 1.6.1