VIRCAM Pipeline  2.3.12
casu_filt.c
1 /* $Id: casu_filt.c,v 1.2 2015/08/07 13:06:54 jim Exp $
2  *
3  * This file is part of the CASU Pipeline utilities
4  * Copyright (C) 2015 European Southern Observatory
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: 2015/08/07 13:06:54 $
24  * $Revision: 1.2 $
25  * $Name: $
26  */
27 
28 /* Includes */
29 
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 #include <cpl.h>
35 #include <math.h>
36 #include <string.h>
37 
38 #include "catalogue/casu_utils.h"
39 #include "casu_filt.h"
40 
41 /* Structure for holding useful information for the stats routine */
42 
43 typedef struct {
44  float sum;
45  float sumw;
46  int naver;
47  float nextw;
48  float lastw;
49  float nextval;
50  float lastval;
51  short int nextc;
52  short int lastc;
53 } nextlast;
54 
55 static void docols(float *data, unsigned char *bpm, int nx, int ny,
56  int filter, int stat);
57 static void dorows(float *data, unsigned char *bpm, int nx, int ny,
58  int filter, int stat);
59 static void wraparound(float *data, unsigned char *bpm, int npts, int nfilt,
60  int whichstat, float **ybuf, unsigned char **ybbuf,
61  int *nbuf);
62 static void medavg(float *array, unsigned char *bpm, int *ipoint, int npix,
63  int whichstat, int newl, nextlast *nl, float *outval,
64  unsigned char *outbp);
65 static void quickie(float *array, unsigned char *iarray, int *iarray2,
66  int lll, int narray);
67 static void sortm(float *a1, unsigned char *a2, int *a3, int n);
68 static void plugholes(float *data, unsigned char *bpm, int nx);
69 
70 
73 /*---------------------------------------------------------------------------*/
112 /*---------------------------------------------------------------------------*/
113 
114 extern void casu_bfilt(float *data, unsigned char *bpm, int nx, int ny,
115  int filt, int stat, int axis) {
116 
117  /* Order the reset correction so that the first smoothing is done
118  across the axis of the anomaly */
119 
120  if (axis == 1) {
121  dorows(data,bpm,nx,ny,filt,stat);
122  docols(data,bpm,nx,ny,filt,stat);
123  } else {
124  docols(data,bpm,nx,ny,filt,stat);
125  dorows(data,bpm,nx,ny,filt,stat);
126  }
127 
128 }
129 
130 /*---------------------------------------------------------------------------*/
160 /*---------------------------------------------------------------------------*/
161 
162 static void docols(float *data, unsigned char *bpm, int nx, int ny,
163  int filter, int stat) {
164  int j,k,indx,nbuf;
165  unsigned char *goodval,*bbuf;
166  float *dbuf;
167 
168  /* Get out of here if you've asked for something stupid */
169 
170  if (filter <= 0)
171  return;
172 
173  /* Get some workspace */
174 
175  nbuf = max(nx,ny);
176  dbuf = cpl_malloc(nbuf*sizeof(*dbuf));
177  bbuf = cpl_malloc(nbuf*sizeof(*bbuf));
178  goodval = cpl_malloc(ny*sizeof(*goodval));
179 
180  /* Now loop for each column and load a column into the buffer */
181 
182  for (k = 0; k < nx; k++) {
183  memset((char *)goodval,0,ny);
184  for (j = 0; j < ny; j++) {
185  indx = j*nx + k;
186  dbuf[j] = data[indx];
187  bbuf[j] = bpm[indx];
188  }
189 
190  /* Do the smoothing and plug any holes where there are bad pixels */
191 
192  casu_dostat(dbuf,bbuf,goodval,ny,filter,stat);
193  plugholes(dbuf,goodval,ny);
194 
195  /* Transfer the data back */
196 
197  for (j = 0; j < ny; j++) {
198  indx = j*nx + k;
199  data[indx] = dbuf[j];
200  }
201  }
202 
203  /* Ditch workspace */
204 
205  freespace(dbuf);
206  freespace(bbuf);
207  freespace(goodval);
208 }
209 
210 /*---------------------------------------------------------------------------*/
240 /*---------------------------------------------------------------------------*/
241 
242 static void dorows(float *data, unsigned char *bpm, int nx, int ny,
243  int filter, int stat) {
244  int j,k,indx,nbuf;
245  unsigned char *goodval,*bbuf;
246  float *dbuf;
247 
248  /* Get out of here if you've asked for something stupid */
249 
250  if (filter <= 0)
251  return;
252 
253  /* Get some workspace */
254 
255  nbuf = max(nx,ny);
256  dbuf = cpl_malloc(nbuf*sizeof(*dbuf));
257  bbuf = cpl_malloc(nbuf*sizeof(*bbuf));
258  goodval = cpl_malloc(nx*sizeof(*goodval));
259 
260  /* Now loop for each row and load a row into the buffer */
261 
262  for (k = 0; k < ny; k++) {
263  memset((char *)goodval,0,nx);
264  for (j = 0; j < nx; j++) {
265  indx = k*nx + j;
266  dbuf[j] = data[indx];
267  bbuf[j] = bpm[indx];
268  }
269 
270  /* Do the smoothing and plug any holes where there are bad pixels */
271 
272  casu_dostat(dbuf,bbuf,goodval,nx,filter,stat);
273  plugholes(dbuf,goodval,nx);
274 
275  /* Transfer the data back */
276 
277  for (j = 0; j < nx; j++) {
278  indx = k*nx + j;
279  data[indx] = dbuf[j];
280  }
281  }
282 
283  /* Ditch workspace */
284 
285  freespace(dbuf);
286  freespace(bbuf);
287  freespace(goodval);
288 }
289 
290 /*---------------------------------------------------------------------------*/
320 /*---------------------------------------------------------------------------*/
321 
322 extern void casu_dostat(float *data, unsigned char *bpm,
323  unsigned char *goodval, int npts, int nfilt,
324  int whichstat) {
325  int nbuf,jl,jh,j,*ipoint,ifree,i;
326  unsigned char *ybbuf,*barray,bval;
327  float *ybuf,*darray,val;
328  nextlast nl;
329 
330  /* check to make sure the filter size is odd */
331 
332  if ((nfilt/2)*2 == nfilt)
333  nfilt++;
334 
335  /* Do the wrap around and load the data into an oversized array */
336 
337  wraparound(data,bpm,npts,nfilt,whichstat,&ybuf,&ybbuf,&nbuf);
338 
339  /* Get some data buffers and initialise them */
340 
341  darray = cpl_malloc(nfilt*sizeof(*darray));
342  barray = cpl_malloc(nfilt*sizeof(*barray));
343  ipoint = cpl_malloc(nfilt*sizeof(*ipoint));
344  memmove((char *)darray,(char *)ybuf,nfilt*sizeof(*ybuf));
345  memmove((char *)barray,(char *)ybbuf,nfilt*sizeof(*ybbuf));
346  for (j = 0; j < nfilt; j++)
347  ipoint[j] = j;
348 
349  /* Do the stat for the first point */
350 
351  ifree = 0;
352  medavg(darray,barray,ipoint,nfilt,whichstat,-1,&nl,&val,&bval);
353  if (! bval)
354  data[0] = val;
355  goodval[0] = bval;
356 
357  /* Now do the stats for all subsequent points. The oldest point in the
358  buffer is replaced by the next raw point */
359 
360  jl = nfilt;
361  jh = nfilt + npts - 2;
362  for (j = jl; j <= jh; j++) {
363  for (i = 0; i < nfilt; i++) {
364  if (ipoint[i] == 0) {
365  ifree = i;
366  ipoint[i] = nfilt - 1;
367  nl.lastval = darray[ifree];
368  nl.lastw = 0.0;
369  nl.lastc = 0;
370  if (barray[ifree] == 0) {
371  nl.lastw = 1.0;
372  nl.lastc = 1;
373  }
374  darray[ifree] = ybuf[j];
375  barray[ifree] = ybbuf[j];
376  nl.nextval = darray[ifree];
377  nl.nextw = 0.0;
378  nl.nextc = 0;
379  if (barray[ifree] == 0) {
380  nl.nextw = 1.0;
381  nl.nextc = 1;
382  }
383  } else
384  ipoint[i]--;
385  }
386  medavg(darray,barray,ipoint,nfilt,whichstat,ifree,&nl,&val,&bval);
387  if (! bval)
388  data[j-jl+1] = val;
389  goodval[j-jl+1] = bval;
390  }
391 
392  /* Ditch workspace */
393 
394  freespace(darray);
395  freespace(barray);
396  freespace(ipoint);
397  freespace(ybuf);
398  freespace(ybbuf);
399 }
400 
401 /*---------------------------------------------------------------------------*/
436 /*---------------------------------------------------------------------------*/
437 
438 static void wraparound(float *data, unsigned char *bpm, int npts, int nfilt,
439  int whichstat, float **ybuf, unsigned char **ybbuf, int *nbuf) {
440 
441  float *darray,xmns,xmnf;
442  int i1,ilow,i,*ipoint;
443  unsigned char *barray,bxmns,bxmnf;
444  nextlast nl;
445 
446  /* Do some padding at the edges */
447 
448  i1 = nfilt/2;
449  ilow = max(3,nfilt/4);
450  ilow = (ilow/2)*2 + 1;
451 
452  /* Get some workspace */
453 
454  darray = cpl_malloc(nfilt*sizeof(*darray));
455  barray = cpl_malloc(nfilt*sizeof(*barray));
456  ipoint = cpl_calloc(nfilt,sizeof(*ipoint));
457  *nbuf = npts + 2*i1;
458  *ybuf = cpl_malloc(*nbuf*sizeof(float));
459  *ybbuf = cpl_malloc(*nbuf*sizeof(unsigned char));
460 
461  /* Do the wrap around.*/
462 
463  memmove((char *)darray,(char *)data,ilow*sizeof(*data));
464  memmove((char *)barray,(char *)bpm,ilow*sizeof(*bpm));
465  medavg(darray,barray,ipoint,ilow,whichstat,-1,&nl,&xmns,&bxmns);
466  memmove((char *)darray,(char *)(data+npts-ilow),ilow*sizeof(*data));
467  memmove((char *)barray,(char *)(bpm+npts-ilow),ilow*sizeof(*bpm));
468  medavg(darray,barray,ipoint,ilow,whichstat,-1,&nl,&xmnf,&bxmnf);
469  for (i = 0; i < i1; i++) {
470  if (! bxmns) {
471  (*ybuf)[i] = 2.0*xmns - data[i1+ilow-i-1];
472  (*ybbuf)[i] = bpm[i1+ilow-i-1];
473  } else {
474  (*ybuf)[i] = data[i1+ilow-i-1];
475  (*ybbuf)[i] = 1;
476  }
477  if (! bxmnf) {
478  (*ybuf)[npts+i1+i] = 2.0*xmnf - data[npts-i-ilow-1];
479  (*ybbuf)[npts+i1+i] = bpm[npts-i-ilow-1];
480  } else {
481  (*ybuf)[npts+i1+i] = data[npts-i-ilow-1];
482  (*ybbuf)[npts+i1+i] = 1;
483  }
484  }
485 
486  /* Now place the full line into the buffer */
487 
488  memmove((char *)(*ybuf+i1),data,npts*sizeof(*data));
489  memmove((char *)(*ybbuf+i1),bpm,npts*sizeof(*bpm));
490 
491  /* Free workspace */
492 
493  freespace(darray);
494  freespace(barray);
495  freespace(ipoint);
496 }
497 
498 /*---------------------------------------------------------------------------*/
535 /*---------------------------------------------------------------------------*/
536 
537 static void medavg(float *array, unsigned char *bpm, int *ipoint, int npix,
538  int whichstat, int newl, nextlast *nl, float *outval,
539  unsigned char *outbp) {
540 
541  float *buf=NULL;
542  int m,i;
543 
544  /* Prepare for median. If there is no new element then do a proper
545  sort. Otherwise to a much quicker sort because the input array should
546  be almost sorted as it is. */
547 
548  m = 0;
549  if (whichstat == MEDIANCALC) {
550  if (newl == -1)
551  sortm(array,bpm,ipoint,npix);
552  else
553  quickie(array,bpm,ipoint,newl,npix);
554 
555  /* Get some workspace */
556 
557  buf = cpl_malloc(npix*sizeof(*buf));
558 
559  /* Now put everything that's good in the buffer */
560 
561  m = 0;
562  for (i = 0; i < npix; i++) {
563  if (bpm[i] == 0) {
564  buf[m] = array[i];
565  m++;
566  }
567  }
568 
569  /* Prepare for a mean. If there are no new values in the input arrays
570  then do the summations. If there is, then include it in the summations
571  from the previous calls and removed the oldest value from the
572  summations */
573 
574  } else if (whichstat == MEANCALC) {
575  if (newl == -1) {
576  nl->sum = 0.0;
577  nl->sumw = 0.0;
578  nl->naver = 0;
579  for (i = 0; i < npix; i++) {
580  if (bpm[i] == 0) {
581  nl->sum += array[i];
582  nl->sumw += 1.0;
583  nl->naver += 1;
584  }
585  }
586  m = nl->naver;
587  } else {
588  nl->sum += (nl->nextw*nl->nextval - nl->lastw*nl->lastval);
589  nl->sumw += (nl->nextw - nl->lastw);
590  nl->naver += (nl->nextc - nl->lastc);
591  m = nl->naver;
592  }
593  }
594 
595  /* If they were all bad, then send a null result back */
596 
597  if (m == 0) {
598  *outval = 0.0;
599  *outbp = 1;
600  if (whichstat == MEDIANCALC)
601  freespace(buf);
602 
603  /* Otherwise calculate the relevant stat */
604 
605  } else {
606  if (whichstat == MEDIANCALC) {
607  if (!(m & 1))
608  *outval = 0.5*(buf[(m/2)-1] + buf[m/2]);
609  else
610  *outval = buf[m/2];
611  freespace(buf);
612  } else if (whichstat == MEANCALC)
613  *outval = (nl->sum)/(nl->sumw);
614  *outbp = 0;
615  }
616 }
617 
618 /*---------------------------------------------------------------------------*/
642 /*---------------------------------------------------------------------------*/
643 
644 static void quickie(float *array, unsigned char *iarray, int *iarray2,
645  int testloc, int narray) {
646 
647  float test;
648  int i,j,npt,it2;
649  unsigned char it;
650 
651  test = array[testloc];
652  it = iarray[testloc];
653  it2 = iarray2[testloc];
654  j = -1;
655  for (i = 0; i < narray; i++) {
656  if (i != testloc && test <= array[i]) {
657  j = i;
658  break;
659  }
660  }
661  if (j == -1)
662  j = narray;
663  if (j - 1 == testloc)
664  return;
665 
666  if (j - testloc < 0) {
667  npt = testloc - j;
668  for (i = 0; i < npt; i++) {
669  array[testloc-i] = array[testloc-i-1];
670  iarray[testloc-i] = iarray[testloc-i-1];
671  iarray2[testloc-i] = iarray2[testloc-i-1];
672  }
673  array[j] = test;
674  iarray[j] = it;
675  iarray2[j] = it2;
676  } else {
677  j--;
678  npt = j - testloc;
679  if (npt != 0) {
680  for (i = 0; i < npt; i++) {
681  array[testloc+i] = array[testloc+i+1];
682  iarray[testloc+i] = iarray[testloc+i+1];
683  iarray2[testloc+i] = iarray2[testloc+i+1];
684  }
685  }
686  array[j] = test;
687  iarray[j] = it;
688  iarray2[j] = it2;
689  }
690 }
691 
692 /*---------------------------------------------------------------------------*/
714 /*---------------------------------------------------------------------------*/
715 
716 static void sortm(float *a1, unsigned char *a2, int *a3, int n) {
717  int iii,ii,i,ifin,j,b3;
718  unsigned char b2;
719  float b1;
720 
721  iii = 4;
722  while (iii < n)
723  iii *= 2;
724  iii = min(n,(3*iii)/4 - 1);
725 
726  while (iii > 1) {
727  iii /= 2;
728  ifin = n - iii;
729  for (ii = 0; ii < ifin; ii++) {
730  i = ii;
731  j = i + iii;
732  if (a1[i] > a1[j]) {
733  b1 = a1[j];
734  b2 = a2[j];
735  b3 = a3[j];
736  while (1) {
737  a1[j] = a1[i];
738  a2[j] = a2[i];
739  a3[j] = a3[i];
740  j = i;
741  i = i - iii;
742  if (i < 0 || a1[i] <= b1)
743  break;
744  }
745  a1[j] = b1;
746  a2[j] = b2;
747  a3[j] = b3;
748  }
749  }
750  }
751 }
752 
753 /*---------------------------------------------------------------------------*/
773 /*---------------------------------------------------------------------------*/
774 
775 static void plugholes(float *data, unsigned char *bpm, int nx) {
776  int i,ifirst,ilast,i1,i2,j;
777  float nc,d1,d2,t1,t2,slope;
778 
779  /* First of all, find the first good value in the array */
780 
781  i = 0;
782  while (i < nx && bpm[i] != 0)
783  i++;
784  ifirst = i;
785 
786  /* If all the values in the array are bad, then do nothing */
787 
788  if (ifirst == nx)
789  return;
790 
791  /* Find the last good value in the array */
792 
793  i = nx - 1;
794  while (i >= 0 && bpm[i] != 0)
795  i--;
796  ilast = i;
797 
798  /* Right, now start from the first good value and fill in any holes in the
799  middle part of the array */
800 
801  i = ifirst;
802  while (i <= ilast) {
803  if (bpm[i] == 0) {
804  i++;
805  continue;
806  }
807  i1 = i - 1;
808  while (bpm[i] != 0)
809  i++;
810  i2 = i;
811  nc = (float)(i2 - i1 + 1);
812  d1 = data[i1];
813  d2 = data[i2];
814  for (j = i1+1; j <= i2-1; j++) {
815  t1 = 1.0 - (float)(j - i1)/nc;
816  t2 = 1.0 - t1;
817  data[j] = t1*d1 + t2*d2;
818  }
819  }
820 
821  /* Now the left bit... */
822 
823  if (ifirst > 0) {
824  slope = data[ifirst+1] - data[ifirst];
825  for (j = 0; j < ifirst; j++)
826  data[j] = slope*(j - ifirst) + data[ifirst];
827  }
828 
829  /* Now the right bit... */
830 
831  if (ilast < nx - 1) {
832  slope = data[ilast] - data[ilast-1];
833  for (j = ilast; j < nx; j++)
834  data[j] = slope*(j - ilast) + data[ilast];
835  }
836 }
837 
841 /*
842 
843 $Log: casu_filt.c,v $
844 Revision 1.2 2015/08/07 13:06:54 jim
845 Fixed copyright to ESO
846 
847 Revision 1.1.1.1 2015/06/12 10:44:32 jim
848 Initial import
849 
850 Revision 1.5 2015/06/09 18:31:56 jim
851 Made casu_dostat external
852 
853 Revision 1.4 2015/01/29 11:46:18 jim
854 modified comments
855 
856 Revision 1.3 2014/03/26 15:35:26 jim
857 Modified to remove globals
858 
859 Revision 1.2 2013/11/21 09:38:13 jim
860 detabbed
861 
862 Revision 1.1.1.1 2013-08-27 12:07:48 jim
863 Imported
864 
865 
866 */