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