VIRCAM Pipeline  1.3.4
vircam/vircam_imcombine.c
1 /* $Id: vircam_imcombine.c,v 1.31 2013-10-15 16:40:57 jim Exp $
2  *
3  * This file is part of the VIRCAM Pipeline
4  * Copyright (C) 2005 Cambridge Astronomy Survey Unit
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: jim $
23  * $Date: 2013-10-15 16:40:57 $
24  * $Revision: 1.31 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 /* Includes */
29 
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 #include <math.h>
35 #include <cpl.h>
36 
37 #include "vircam_utils.h"
38 #include "vircam_pfits.h"
39 #include "vircam_stats.h"
40 #include "vircam_fits.h"
41 #include "vircam_mods.h"
42 
43 /* Macro definitions */
44 
45 #define FATAL_ERR(_f,_a) {cpl_msg_error(_f,"%s",_a); tidy(); *status = VIR_FATAL; return(*status);}
46 #define WARN_ERR(_f,_a) {cpl_msg_error(_f,"%s",_a); tidy(); *status = VIR_WARN; return(VIR_WARN);}
47 #define INFO_ERR(_f,_a) {cpl_msg_info(_f,"%s",_a);}
48 #define MEDIANCALC 1
49 #define MEANCALC 2
50 #define SZBUF 1024
51 
52 /* Definition of litestruct which is used to hold useful information about
53  each of the input frames and their associated images */
54 
55 typedef struct {
56  vir_fits *frame;
57  float exptime;
58  float expfudge;
59  float skylevel;
60  float skynoise;
61  float skyfudge;
62  float skyrenorm;
63 } litestruct;
64 
65 /* Static Global variables */
66 
67 static litestruct *fileptrs = NULL;
68 static float **datas = NULL;
69 static cpl_binary **masks = NULL;
70 static float *odata;
71 static cpl_binary *omask;
72 static long npts;
73 static int nf;
74 static float oskylevel;
75 static long nx;
76 static long ny;
77 static unsigned char *rmask = NULL;
78 static unsigned char *rplus = NULL;
79 
80 /* Static subroutine prototypes */
81 
82 static void skyest(float *data, cpl_binary *bpm, float thresh, float *skymed,
83  float *skynoise);
84 static void medcalc(float, float, int);
85 static void meancalc(float, float, int);
86 static void xclip_med(float thresh, int scaletype);
87 static void xclip_mean(float thresh, int scaletype);
88 
89 static void tidy(void);
90 
93 /*---------------------------------------------------------------------------*/
153 /*---------------------------------------------------------------------------*/
154 
155 extern int vircam_imcombine(vir_fits **fset, int nfits, int combtype,
156  int scaletype, int xrej, float thresh,
157  cpl_image **outimage, unsigned char **rejmask,
158  unsigned char **rejplus, cpl_propertylist **drs,
159  int *status) {
160  int i,k,j;
161  const char *ic_fctid = "vircam_imcombine";
162  char msg[SZBUF];
163  float sumsky,sumsig,texp1,texp2,expfudge,skylevel,skynoise,oskynoise;
164  float *dat,*work;
165  litestruct *ff;
166  cpl_image *im;
167  cpl_propertylist *plist_p;
168 
169  /* Inherited status */
170 
171  *rejmask = NULL;
172  *rejplus = NULL;
173  *drs = NULL;
174  *outimage = NULL;
175  if (*status != VIR_OK)
176  return(*status);
177 
178  /* Check that there are any files in the first place...*/
179 
180  nf = nfits;
181  if (nf == 0)
182  WARN_ERR(ic_fctid,"No files to combine")
183 
184  /* Get some file structures */
185 
186  fileptrs = cpl_calloc(nf,sizeof(litestruct));
187 
188  /* Get workspace for convenience arrays */
189 
190  datas = cpl_malloc(nf*sizeof(float *));
191  npts = vircam_getnpts(vircam_fits_get_image(fset[0]));
192  for (k = 0; k < nf; k++)
193  datas[k] = cpl_malloc(npts*sizeof(float));
194  masks = cpl_malloc(nf*sizeof(cpl_binary *));
195 
196  /* Get pointers to the data arrays */
197 
198  for (k = 0; k < nf; k++) {
199  im = vircam_fits_get_image(fset[k]);
200  dat = cpl_image_get_data_float(im);
201  if (dat == NULL) {
202  snprintf(msg,SZBUF,"Failed to load data from extension %d in %s",
203  vircam_fits_get_nexten(fset[k]),
204  vircam_fits_get_filename(fset[k]));
205  FATAL_ERR(ic_fctid,msg)
206  }
207  for (i = 0; i < npts; i++)
208  datas[k][i] = dat[i];
209  masks[k] = cpl_mask_get_data(cpl_image_get_bpm(im));
210  }
211 
212  /* Open each file in turn and fill in the necessary information. Start with
213  the file name...*/
214 
215  for (i = 0; i < nf; i++) {
216  ff = fileptrs + i;
217  ff->frame = fset[i];
218 
219  /* If this is the first frame, then keep the size of the data
220  array for future reference */
221 
222  if (i == 0) {
223  nx = (long)cpl_image_get_size_x(vircam_fits_get_image(fset[0]));
224  ny = (long)cpl_image_get_size_y(vircam_fits_get_image(fset[0]));
225  npts = nx*ny;
226  }
227 
228  /* Get the header and the exposure time */
229 
230  plist_p = vircam_fits_get_phu(ff->frame);
231  if (plist_p == NULL) {
232  snprintf(msg,SZBUF,"Failed to load primary property list %s",
233  vircam_fits_get_filename(ff->frame));
234  INFO_ERR(ic_fctid,msg)
235  texp2 = 1.0;
236  } else {
237  if (vircam_pfits_get_exptime(plist_p,&texp2) != VIR_OK) {
238  texp2 = 1.0;
239  snprintf(msg,SZBUF,"Failed to get exposure time from %s",
240  vircam_fits_get_filename(ff->frame));
241  INFO_ERR(ic_fctid,msg)
242  }
243  }
244 
245  /* Set a few properties */
246 
247  ff->exptime = texp2;
248  texp1 = fileptrs->exptime;
249  expfudge = texp1/texp2;
250  ff->expfudge = expfudge;
251 
252  /* If scaling by relative exposure time, then do it now. NB: This
253  isn't necessary for the first file as all the others are scaled
254  relative to it */
255 
256  if (scaletype == 3 && i > 0) {
257  for (j = 0; j < npts; j++)
258  datas[i][j] *= ff->expfudge;
259  }
260 
261  /* Get the background estimate and noise */
262 
263  skyest(datas[i],masks[i],thresh,&skylevel,&skynoise);
264  ff->skylevel = skylevel;
265  ff->skynoise = skynoise;
266  }
267 
268  /* Work out average background and noise. Then create background zeropoint
269  or scale factor, depending upon which was requested in the call */
270 
271  work = cpl_malloc(nf*sizeof(float));
272  for (i = 0; i < nf; i++)
273  work[i] = (fileptrs+i)->skylevel;
274  sumsky = vircam_med(work,NULL,(long)nf);
275  for (i = 0; i < nf; i++)
276  work[i] = (fileptrs+i)->skynoise;
277  sumsig = vircam_med(work,NULL,(long)nf);
278  cpl_free(work);
279  switch (scaletype) {
280  case 1:
281  for (i = 0; i < nf; i++)
282  (fileptrs+i)->skyfudge = sumsky - (fileptrs+i)->skylevel;
283  break;
284  case 2:
285  for (i = 0; i < nf; i++)
286  (fileptrs+i)->skyfudge = sumsky/(fileptrs+i)->skylevel;
287  break;
288  case 3:
289  for (i = 0; i < nf; i++)
290  (fileptrs+i)->skyfudge = sumsky - (fileptrs+i)->skylevel;
291  break;
292  default:
293  for (i = 0; i < nf; i++)
294  (fileptrs+i)->skyfudge = 0.0;
295  break;
296  }
297 
298  /* Open an output image based on the first frame in the frameset */
299 
300  *outimage = cpl_image_new((cpl_size)nx,(cpl_size)ny,CPL_TYPE_FLOAT);
301  odata = cpl_image_get_data_float(*outimage);
302  omask = cpl_mask_get_data(cpl_image_get_bpm(*outimage));
303  if (*outimage == NULL || odata == NULL)
304  FATAL_ERR(ic_fctid,"Couldn't create output image")
305  *rejmask = cpl_calloc(npts,sizeof(*rejmask));
306  rmask = *rejmask;
307  *rejplus = cpl_calloc(npts,sizeof(*rejplus));
308  rplus = *rejplus;
309 
310  /* Now do the averaging/medianing */
311 
312  switch (combtype) {
313  case MEDIANCALC:
314  medcalc(thresh,sumsig,scaletype);
315  break;
316  case MEANCALC:
317  meancalc(thresh,sumsig,scaletype);
318  break;
319  }
320 
321  /* Do the extra clipping here if you want it */
322 
323  if (xrej) {
324 
325  /* First get sky background and sigma from output data */
326 
327  skyest(odata,omask,thresh,&oskylevel,&oskynoise);
328 
329  /* Now loop for all the files subtract off the mean frame (suitably
330  scaled and zero pointed depending on what was done in the first
331  place) */
332 
333  for (i = 0; i < nf; i++) {
334  ff = fileptrs + i;
335  ff->skyrenorm = ff->skylevel/oskylevel;
336  switch (scaletype) {
337  case 1:
338  for (k = 0; k < npts; k++)
339  datas[i][k] -= (odata[k] - oskylevel);
340  break;
341  case 2:
342  for (k = 0; k < npts; k++)
343  datas[i][k] -= (odata[k] - oskylevel)*ff->skyrenorm;
344  break;
345  case 3:
346  for (k = 0; k < npts; k++)
347  datas[i][k] -= (odata[k] - oskylevel);
348  break;
349  case 0:
350  for (k = 0; k < npts; k++)
351  datas[i][k] -= (odata[k] - oskylevel);
352  break;
353  }
354 
355  /* Re-estimate the noise for this image */
356 
357  skyest(datas[i],masks[i],thresh,&skylevel,&skynoise);
358  ff->skynoise = skynoise;
359  }
360 
361  /* Now do the extra clip... */
362 
363  switch (combtype) {
364  case MEDIANCALC:
365  xclip_med(thresh,scaletype);
366  break;
367  case MEANCALC:
368  xclip_mean(thresh,scaletype);
369  break;
370  }
371  }
372 
373  /* Write provenance keywords */
374 
375  *drs = cpl_propertylist_new();
376  vircam_prov(*drs,fset,nfits);
377 
378  /* Right, tidy and get out of here */
379 
380  tidy();
381  return(VIR_OK);
382 }
383 
384 /*---------------------------------------------------------------------------*/
406 /*---------------------------------------------------------------------------*/
407 
408 static void xclip_med(float thresh, int scaletype) {
409  int nf1,nf2,nfm,nrejmax,is_even,k,is_even2,nrej,nremain,nm,nmm,nplus;
410  int nminus,nn,j;
411  float **work,*dork,value,cliplev;
412  long i;
413  litestruct *ff;
414 
415  /* Get some workspace */
416 
417  work = cpl_malloc(3*sizeof(float *));
418  for (i = 0; i < 3; i++)
419  work[i] = cpl_malloc(nf*sizeof(float));
420  dork = cpl_malloc(nf*sizeof(float));
421 
422  /* Loop for each input pixel now... */
423 
424  for (i = 0; i < npts; i++) {
425  if (omask[i])
426  continue;
427 
428  /* Scale or shift data */
429 
430  nn = 0;
431  switch (scaletype) {
432  case 0:
433  for (k = 0; k < nf; k++) {
434  if (masks[k][i])
435  continue;
436  ff = fileptrs + k;
437  work[0][nn] = datas[k][i];
438  work[1][nn] = ff->skynoise;
439  work[2][nn++] = datas[k][i] + odata[i] - oskylevel;
440  }
441  break;
442  case 1:
443  for (k = 0; k < nf; k++) {
444  if (masks[k][i])
445  continue;
446  ff = fileptrs + k;
447  work[0][nn] = datas[k][i] + ff->skyfudge;
448  work[1][nn] = ff->skynoise;
449  work[2][nn++] = datas[k][i] + odata[i] - oskylevel +
450  ff->skyfudge;
451  }
452  break;
453  case 2:
454  for (k = 0; k < nf; k++) {
455  if (masks[k][i])
456  continue;
457  ff = fileptrs + k;
458  work[0][nn] = datas[k][i]*ff->skyfudge;
459  work[1][nn] = ff->skynoise*ff->skyfudge;
460  work[2][nn++] = (datas[k][i] + odata[i]*ff->skyrenorm -
461  ff->skylevel)*ff->skyfudge;
462  }
463  break;
464  case 3:
465  for (k = 0; k < nf; k++) {
466  if (masks[k][i])
467  continue;
468  ff = fileptrs + k;
469  work[0][nn] = datas[k][i] + ff->skyfudge;
470  work[1][nn] = ff->skynoise;
471  work[2][nn++] = datas[k][i] + odata[i] - oskylevel +
472  ff->skyfudge;
473  }
474  break;
475  }
476 
477  /* Set up a few useful variables */
478 
479  nf1 = nn/2 - 1;
480  nf2 = nf1 + 1;
481  nfm = (nn + 1)/2 - 1;
482  nrejmax = nn/2;
483  is_even = !(nn & 1);
484 
485  /* Sort and get a first pass median */
486 
487  vircam_sort(work,nn,3);
488  if (is_even)
489  value = 0.5*(work[0][nf1] + work[0][nf2]);
490  else
491  if (nn < 5)
492  value = work[0][nfm];
493  else
494  value = 0.25*(work[0][nfm-1] + work[0][nfm+1]) + 0.5*work[0][nfm];
495 
496  /* Do clipping */
497 
498  nplus = 0;
499  cliplev = value + thresh*work[1][nn-1];
500  while (nplus < nrejmax && work[0][nn-nplus-1] > cliplev)
501  nplus++;
502  nminus = 0;
503  cliplev = value - thresh*work[1][nn-1];
504  while ((nplus+nminus) < nrejmax && work[0][nminus] < cliplev)
505  nminus++;
506  nrej = nplus + nminus;
507 
508  /* If there were any clipped out, the re-estimate the value */
509 
510  if (nrej > 0) {
511  nremain = nn - nrej;
512  if (nremain != 0) {
513  nm = nremain/2 - 1;
514  for (j = 0; j < nremain; j++)
515  dork[j] = work[2][j+nminus];
516  nmm = (nremain + 1)/2 - 1;
517  is_even2 = !(nremain & 1);
518  vircam_sort(&dork,nm,1);
519  if (is_even2)
520  value = 0.5*(dork[nm] + dork[nm+1]);
521  else
522  if (nremain < 3)
523  value = dork[nmm];
524  else
525  value = 0.5*dork[nmm] + 0.25*(dork[nmm-1] + dork[nmm+1]);
526  }
527 
528  /* Store the result away */
529 
530  odata[i] = value;
531  rmask[i] = min(255,nrej);
532  rplus[i] = min(255,nplus);
533  } else {
534  rmask[i] = 0;
535  rplus[i] = 0;
536  }
537  }
538 
539  /* Ditch workspace and get out of here */
540 
541  for (i = 0; i < 3; i++)
542  cpl_free(work[i]);
543  cpl_free(work);
544  cpl_free(dork);
545 }
546 
547 /*---------------------------------------------------------------------------*/
569 /*---------------------------------------------------------------------------*/
570 
571 static void xclip_mean(float thresh, int scaletype) {
572  int k,nf2,nrej,nplus,kk,krem;
573  float *work[3],value,value2,nrejmax,resid,maxresid;
574  long i,nn;
575  litestruct *ff;
576  unsigned char *iflag;
577 
578  /* Get some workspace */
579 
580  for (i = 0; i < 3; i++)
581  work[i] = cpl_malloc(nf*sizeof(float));
582  iflag = cpl_malloc(nf*sizeof(unsigned char));
583 
584  /* Loop for each input pixel now... */
585 
586  nrejmax = nf/2;
587  for (i = 0; i < npts; i++) {
588  if (omask[i])
589  continue;
590 
591  /* Scale or shift data */
592 
593  nn = 0;
594  switch (scaletype) {
595  case 0:
596  for (k = 0; k < nf; k++) {
597  if (masks[k][i])
598  continue;
599  ff = fileptrs + k;
600  work[0][nn] = datas[k][i];
601  work[1][nn] = ff->skynoise;
602  work[2][nn] = datas[k][i] + odata[i] - oskylevel;
603  iflag[nn++] = 0;
604  }
605  break;
606  case 1:
607  for (k = 0; k < nf; k++) {
608  if (masks[k][i])
609  continue;
610  ff = fileptrs + k;
611  work[0][nn] = datas[k][i] + ff->skyfudge;
612  work[1][nn] = ff->skynoise;
613  work[2][nn] = datas[k][i] + odata[i] - oskylevel + ff->skyfudge;
614  iflag[nn++] = 0;
615  }
616  break;
617  case 2:
618  for (k = 0; k < nf; k++) {
619  if (masks[k][i])
620  continue;
621  ff = fileptrs + k;
622  work[0][nn] = datas[k][i]*ff->skyfudge;
623  work[1][nn] = ff->skynoise*ff->skyfudge;
624  work[2][nn] = (datas[k][i] + odata[i]*ff->skyrenorm -
625  ff->skylevel)*ff->skyfudge;
626  iflag[nn++] = 0;
627  }
628  break;
629  case 3:
630  for (k = 0; k < nf; k++) {
631  if (masks[k][i])
632  continue;
633  ff = fileptrs + k;
634  work[0][nn] = datas[k][i] + ff->skyfudge;
635  work[1][nn] = ff->skynoise;
636  work[2][nn] = datas[k][i] + odata[i] - oskylevel + ff->skyfudge;
637  iflag[nn++] = 0;
638  }
639  break;
640  }
641 
642  /* Get a first pass mean */
643 
644  value = 0.0;
645  for (k = 0; k < nn; k++)
646  value += work[0][k];
647  value /= (float)nn;
648 
649  /* Enter a rejection loop. Reject pixels one at a time */
650 
651  nplus = 0;
652  nrej = 0;
653  for (kk = 0; kk < nrejmax; kk++) {
654  maxresid = -1.0e30;
655  krem = -1;
656  for (k = 0; k < nn; k++) {
657  if (iflag[k] == 1)
658  continue;
659  resid = fabs(work[0][k] - value);
660  if (resid > thresh*work[1][k]) {
661  if (nf <= 2)
662  resid = work[0][k] - value;
663  if (resid > maxresid) {
664  krem = k;
665  maxresid = resid;
666  }
667  }
668  }
669 
670  /* No further rejections */
671 
672  if (krem == -1)
673  break;
674 
675  /* Another pixel is rejected. If it's positive count it */
676 
677  iflag[krem] = 1;
678  if ((work[0][krem] - value) > 0.0)
679  nplus++;
680  nrej++;
681 
682  /* Re-evaluate the mean */
683 
684  nf2 = 0;
685  value2 = 0;
686  for (k = 0; k < nn; k++) {
687  if (iflag[k] == 0) {
688  value2 += work[0][k];
689  nf2++;
690  }
691  }
692  if (nf2 != 0)
693  value = value2/(float)nf2;
694  else
695  break;
696  }
697 
698  /* If there were any clipped out store the new value */
699 
700  if (nrej > 0)
701  odata[i] = value;
702  rmask[i] = min(255,nrej);
703  rplus[i] = min(255,nplus);
704  }
705 
706  /* Ditch workspace and get out of here */
707 
708  for (k = 0; k < 3; k++)
709  cpl_free(work[k]);
710  cpl_free(iflag);
711 }
712 
713 
714 /*---------------------------------------------------------------------------*/
737 /*---------------------------------------------------------------------------*/
738 
739 static void medcalc(float thresh, float avskynoise, int scaletype) {
740  int nf1,nf2,nfm,nrejmax,is_even,nrej,nremain,nm,nmm,is_even2,k,nminus;
741  int nplus,nn;
742  long i;
743  float value,cliplev,*work;
744 
745  /* Get a workspace */
746 
747  work = cpl_malloc(nf*sizeof(*work));
748 
749  /* Ok, loop for each pixel... */
750 
751  for (i = 0; i < npts; i++) {
752 
753  /* Scale or shift data */
754 
755  nn = 0;
756  switch (scaletype) {
757  case 0:
758  for (k = 0; k < nf; k++) {
759  if (masks[k][i])
760  continue;
761  work[nn++] = datas[k][i];
762  }
763  break;
764  case 1:
765  for (k = 0; k < nf; k++) {
766  if (masks[k][i])
767  continue;
768  work[nn++] = datas[k][i] + (fileptrs+k)->skyfudge;
769  }
770  break;
771  case 2:
772  for (k = 0; k < nf; k++) {
773  if (masks[k][i])
774  continue;
775  work[nn++] = datas[k][i]*(fileptrs+k)->skyfudge;
776  }
777  break;
778  case 3:
779  for (k = 0; k < nf; k++) {
780  if (masks[k][i])
781  continue;
782  work[nn++] = datas[k][i] + (fileptrs+k)->skyfudge;
783  }
784  break;
785  }
786 
787  /* If nothing is available, then flag the output pixel */
788 
789  if (nn == 0) {
790  odata[i] = 0;
791  omask[i] = 1;
792  rmask[i] = 0;
793  rplus[i] = 0;
794  continue;
795  }
796 
797  /* Set up a few useful variables */
798 
799  nf1 = nn/2 - 1;
800  nf2 = nf1 + 1;
801  nfm = (nn + 1)/2 - 1;
802  nrejmax = nn/2;
803  is_even = !(nn & 1);
804 
805  /* Sort data and get the median */
806 
807  vircam_sort(&work,nn,1);
808  if (is_even)
809  value = 0.5*(work[nf1] + work[nf2]);
810  else
811  if (nn < 5)
812  value = work[nfm];
813  else
814  value = 0.25*(work[nfm-1] + work[nfm+1]) + 0.5*work[nfm];
815 
816  /* Enter a rejection loop */
817 
818  nplus = 0;
819  cliplev = value + thresh*avskynoise;
820  while (nplus < nrejmax && work[nn-nplus-1] > cliplev)
821  nplus++;
822  nminus = 0;
823  cliplev = value - thresh*avskynoise;
824  while ((nplus+nminus) < nrejmax && work[nminus] < cliplev)
825  nminus++;
826  nrej = nplus + nminus;
827 
828  /* If you've clipped any, then recalculate the median...*/
829 
830  if (nrej > 0) {
831  nremain = nn - nrej;
832  nm = nremain/2 - 1 + nminus;
833  nmm = (nremain + 1)/2 - 1 + nminus;
834  is_even2 = !(nremain & 1);
835  if (is_even2)
836  value = 0.5*(work[nm] + work[nm+1]);
837  else
838  if (nremain < 3)
839  value = work[nmm];
840  else
841  value = 0.5*work[nmm] + 0.25*(work[nmm-1] + work[nmm+1]);
842  }
843 
844  /* Store the result away */
845 
846  odata[i] = value;
847  omask[i] = 0;
848  rmask[i] = min(255,nrej);
849  rplus[i] = min(255,nplus);
850  }
851 
852  /* Get rid of workspace */
853 
854  cpl_free(work);
855 }
856 
857 /*---------------------------------------------------------------------------*/
880 /*---------------------------------------------------------------------------*/
881 
882 static void meancalc(float thresh, float avskynoise, int scaletype) {
883  int nf2,k,nrej,nplus,nrejmax,kk,krem;
884  long i,nn;
885  float *work,value,value2,maxresid,resid,fresid,cliplev;
886  unsigned char *iflag;
887 
888  /* Get vectors for workspace */
889 
890  work = cpl_malloc(nf*sizeof(*work));
891  iflag = cpl_malloc(nf*sizeof(unsigned char));
892 
893  /* Ok, loop for each pixel... */
894 
895  cliplev = thresh*avskynoise;
896  for (i = 0; i < npts; i++) {
897 
898  /* Scale or shift data */
899 
900  nn = 0;
901  switch (scaletype) {
902  case 0:
903  for (k = 0; k < nf; k++) {
904  if (masks[k][i])
905  continue;
906  work[nn++] = datas[k][i];
907  }
908  break;
909  case 1:
910  for (k = 0; k < nf; k++) {
911  if (masks[k][i])
912  continue;
913  work[nn++] = datas[k][i] + (fileptrs+k)->skyfudge;
914  }
915  break;
916  case 2:
917  for (k = 0; k < nf; k++) {
918  if (masks[k][i])
919  continue;
920  work[nn++] = datas[k][i]*(fileptrs+k)->skyfudge;
921  }
922  break;
923  case 3:
924  for (k = 0; k < nf; k++) {
925  if (masks[k][i])
926  continue;
927  work[nn++] = datas[k][i] + (fileptrs+k)->skyfudge;
928  }
929  break;
930  }
931 
932  /* If nothing is available, then flag the output pixel */
933 
934  if (nn == 0) {
935  odata[i] = 0;
936  omask[i] = 1;
937  rmask[i] = 0;
938  rplus[i] = 0;
939  continue;
940  }
941 
942  /* Get the mean */
943 
944  value = 0.0;
945  for (k = 0; k < nn; k++) {
946  value += work[k];
947  iflag[k] = 0;
948  }
949  value /= (float)nn;
950 
951  /* Enter a rejection loop */
952 
953  nrejmax = nn - 1;
954  nplus = 0;
955  nf2 = 0;
956  for (kk = 0; kk < nrejmax; kk++) {
957  maxresid = -1.0e30;
958  krem = -1;
959  for (k = 0; k < nn; k++) {
960  if (iflag[k] == 1)
961  continue;
962  resid = work[k] - value;
963  fresid = (float)fabs((double)resid);
964  if (fresid > cliplev) {
965  if (nn <= 2)
966  fresid = work[k] - value;
967  if (fresid > maxresid) {
968  krem = k;
969  maxresid = fresid;
970  }
971  }
972  }
973  if (krem == -1)
974  break;
975  if ((work[krem] - value) > 0.0)
976  nplus++;
977  value2 = 0.0;
978  iflag[krem] = 1;
979  nf2 = 0;
980  for (k = 0; k < nn; k++) {
981  if (iflag[k] == 0) {
982  value2 += work[k];
983  nf2 += 1;
984  }
985  }
986  value = value2/(float)nf2;
987  }
988 
989  /* If you've clipped any, then recalculate the mean...*/
990 
991  nrej = nn - nf2;
992 
993  /* Store the result away */
994 
995  odata[i] = value;
996  omask[i] = 0;
997  rmask[i] = min(255,nrej);
998  rplus[i] = min(255,nplus);
999  }
1000 
1001  /* Get rid of workspace */
1002 
1003  cpl_free(work);
1004  cpl_free(iflag);
1005 }
1006 
1007 /*---------------------------------------------------------------------------*/
1032 /*---------------------------------------------------------------------------*/
1033 
1034 static void skyest(float *data, cpl_binary *mask, float thresh, float *skymed,
1035  float *skynoise) {
1036  unsigned char *bpm;
1037 
1038  /* Set up the bad pixel mask */
1039 
1040  bpm = (unsigned char *)mask;
1041 
1042  /* Get the stats */
1043 
1044  vircam_qmedsig(data,bpm,npts,thresh,3,-65535.0,65535.0,skymed,
1045  skynoise);
1046 
1047 }
1048 
1049 /*---------------------------------------------------------------------------*/
1053 /*---------------------------------------------------------------------------*/
1054 
1055 static void tidy(void) {
1056  int i;
1057 
1058  /* Free up work space associated with file structures */
1059 
1060  freespace(fileptrs);
1061  for (i = 0; i < nf; i++)
1062  freespace(datas[i]);
1063  freespace(datas);
1064  freespace(masks);
1065 }
1066 
1070 /*
1071 
1072 $Log: not supported by cvs2svn $
1073 Revision 1.30 2012/01/27 12:25:10 jim
1074 Fixed some casts
1075 
1076 Revision 1.29 2012/01/15 17:40:09 jim
1077 Minor modifications to take into accout the changes in cpl API for v6
1078 
1079 Revision 1.28 2010/07/13 11:16:50 jim
1080 A few changes to deal with compiler whinges
1081 
1082 Revision 1.27 2010/06/03 12:15:31 jim
1083 A few mods to get rid of compiler warnings
1084 
1085 Revision 1.26 2008/10/13 08:14:23 jim
1086 Will now take object masks into account
1087 
1088 Revision 1.25 2008/09/29 11:27:53 jim
1089 Fixed bug in median clipping algorithm. Also fixed a bug that stopped the
1090 scaling from working in some cases
1091 
1092 Revision 1.24 2007/05/14 15:26:03 jim
1093 Fixed bug in multiplicative scaling
1094 
1095 Revision 1.23 2007/03/29 12:19:39 jim
1096 Little changes to improve documentation
1097 
1098 Revision 1.22 2007/03/01 12:42:41 jim
1099 Modified slightly after code checking
1100 
1101 Revision 1.21 2006/10/02 13:47:33 jim
1102 Added missing .h file to include list
1103 
1104 Revision 1.20 2006/09/08 09:21:37 jim
1105 Fixed bug in median routine
1106 
1107 Revision 1.19 2006/08/21 09:08:10 jim
1108 Fixed a few subtle bugs in the median routines
1109 
1110 Revision 1.18 2006/07/04 09:19:05 jim
1111 replaced all sprintf statements with snprintf
1112 
1113 Revision 1.17 2006/05/08 10:56:14 jim
1114 Fixed bug where exposure time scaling was not happening to the data copy
1115 
1116 Revision 1.16 2006/04/20 11:26:45 jim
1117 Fixed so that original data isn't modified in the input vir_fits list.
1118 
1119 Revision 1.15 2006/03/23 21:18:48 jim
1120 Minor changes mainly to comment headers
1121 
1122 Revision 1.14 2006/03/22 13:58:31 jim
1123 Cosmetic fixes to keep lint happy
1124 
1125 Revision 1.13 2006/03/08 14:32:21 jim
1126 Lots of little modifications
1127 
1128 Revision 1.12 2006/03/03 14:29:46 jim
1129 Modified definition of vir_fits and channel table
1130 
1131 Revision 1.11 2006/03/01 10:31:28 jim
1132 Now uses new vir_fits objects
1133 
1134 Revision 1.10 2006/02/22 10:09:09 jim
1135 Added status variable to call
1136 
1137 Revision 1.9 2006/01/23 10:30:49 jim
1138 Mainly documentation mods
1139 
1140 Revision 1.8 2005/12/14 22:17:33 jim
1141 Updated docs
1142 
1143 Revision 1.7 2005/11/29 11:54:19 jim
1144 Modified call in skyest to allow for larger negative numbers as it is
1145 likely that the reset frames will be negative.
1146 
1147 Revision 1.6 2005/11/25 09:56:15 jim
1148 Tidied up some more documentation
1149 
1150 Revision 1.5 2005/11/08 12:47:44 jim
1151 Made garbage collection a little better
1152 
1153 Revision 1.4 2005/11/07 13:15:16 jim
1154 Fixed lots of bugs and added some error checking
1155 
1156 Revision 1.3 2005/11/03 13:28:49 jim
1157 All sorts of changes to tighten up error handling
1158 
1159 Revision 1.2 2005/10/14 13:17:54 jim
1160 Now spews out a mask of rejected pixels and rejected positive pixels
1161 (indicative of cosmic ray hits)
1162 
1163 Revision 1.1.1.1 2005/08/05 08:29:09 jim
1164 Initial import
1165 
1166 
1167 */
1168 
char * vircam_fits_get_filename(vir_fits *p)
Definition: vircam_fits.c:526
void vircam_qmedsig(float *data, unsigned char *bpm, long npts, float thresh, int niter, float lowv, float highv, float *median, float *sigma)
Definition: vircam_stats.c:542
int vircam_pfits_get_exptime(const cpl_propertylist *plist, float *exptime)
Get the value of exposure time.
Definition: vircam_pfits.c:245
void vircam_sort(float **a, int n, int m)
int vircam_fits_get_nexten(vir_fits *p)
Definition: vircam_fits.c:382
cpl_image * vircam_fits_get_image(vir_fits *p)
Definition: vircam_fits.c:349
float vircam_med(float *data, unsigned char *bpm, long npts)
Definition: vircam_stats.c:89
cpl_propertylist * vircam_fits_get_phu(vir_fits *p)
Definition: vircam_fits.c:416
int vircam_imcombine(vir_fits **fset, int nfits, int combtype, int scaletype, int xrej, float thresh, cpl_image **outimage, unsigned char **rejmask, unsigned char **rejplus, cpl_propertylist **drs, int *status)
Stack images into a mean or median image with rejection.
long vircam_getnpts(cpl_image *in)
void vircam_prov(cpl_propertylist *p, vir_fits **inlist, int n)