#include "ninox.h" // Keep a copy of the frames as they slide past static struct Image **history = NULL; static int Width = 0; static int Height = 0; static int Depth = 0; static int Replaced = 0; struct _minmax { int min; int max; int avg; }; static struct _minmax *Window = NULL; void init_streamfilter() { if (! StreamFilter) { Print("StreamFilter disabled\n"); return; } // Just throw them away, forget about the small leak if (history) {free(history); history = NULL;} if (Window) { free(Window); Window = NULL; } history = (struct Image **)ZeroMalloc(sizeof(struct Image *) * StreamFilter_History); if (! history) { Print("Error allocating memory for StreamFilter\n"); exit(1); } Width = Height = Depth = 0; return; } struct Image * CloneImage(struct Image *img) { struct Image *nImg = CreateImage(); struct fits_info *nfi = ZeroMalloc(sizeof(struct fits_info)); struct fits_info *fi = (struct fits_info *)img->info; int bytes; nImg->type= img->type; nImg->width = img->width; nImg->dst_width = img->dst_width; nImg->height = img->height; nImg->dst_height = img->dst_height; nImg->depth = img->depth; nfi->bzero = fi->bzero; nfi->bscale = fi->bscale; nfi->header = ZeroMalloc(2880); memcpy(nfi->header,fi->header,2880); nImg->info = nfi; bytes = img->width * img->height * img->depth/8; nImg->data = (unsigned char *)malloc(bytes); memcpy(nImg->data,img->data,bytes); nImg->src_fname = strdup(img->src_fname); nImg->dst_fname = strdup(img->dst_fname); nImg->cutout = img->cutout; nImg->m = img->m; return nImg; } static int fill_window(struct Image *img) { int i; if (! Window) { int npix = img->width * img->height; Window = (struct _minmax *)ZeroMalloc(sizeof(struct _minmax) * npix); if (! Window) { Print("StreamFilter: Error allocating %d pixels for minimax window\n",npix); exit(1); } } for(i=0; iwidth; Height = img->height; Depth = img->depth; } history[i] = CloneImage(img); return 1; } return 0; } static int recalculate_minmax() { int i,h,total; int npixels = Width * Height; for(i=0; i< npixels; ++i) { Window[i].min = 1000000; Window[i].max = -1; } switch(Depth) { case 8: for(i=0; idata[i]; if (v < Window[i].min) Window[i].min = v; if (v > Window[i].max) Window[i].max = v; total += v; } Window[i].avg = total/h; } break; case 16: for(i=0; idata); int v = uptr[i]; if (v < Window[i].min) Window[i].min = v; if (v > Window[i].max) Window[i].max = v; total += v; } Window[i].avg = total/h; } break; } return 1; } static unsigned short _pixel_pop(int o, int p) { int rval = p; if (p < Window[o].min || p > Window[o].max) { rval = (p + Window[o].avg)/2; ++Replaced; } // pixel (330,330) //if (o == 222090) //Print("%d <-> [ %d (%d) %d] = %d\n",p,Window[o].min,Window[o].avg,Window[o].max,rval); return rval; } // compare each pixel in this image to the pixels in the history // and if this image has the largest or smallest then replace it with the // average static int _filter_pop(struct Image *img) { unsigned char *ptr = (unsigned char *)img->data; unsigned short *uptr = (unsigned short *)img->data; int i,npixels = img->width * img->height; unsigned int threshhold = ThreshHold; threshhold=0; recalculate_minmax(); Replaced = 0; switch(img->depth) { case 8: for(i=0; ithreshhold) ptr[i] = _pixel_pop(i,(int)ptr[i]); break; case 16: threshhold <<= 8; for(i=0; ithreshhold) uptr[i] = _pixel_pop(i,(int)uptr[i]); break; } Print("Replaced %d/%d pixels\n",Replaced,npixels); return 1; } static int getpixel(struct Image *img, int x, int y) { int width = img->width; int height = img->height; int depth = img->depth; unsigned short *udata; switch(depth) { case 8: return img->data[y * width + x]; break; case 16: udata = (unsigned short *)img->data; return udata[y * width + x]; break; } return 0; } int do_StreamFilter(struct Image *img) { int i; struct Image *cp; if (history == NULL) init_streamfilter(); // If there is an empty slot in the window then add the current frame and // return. This is only relevant when starting out if (fill_window(img)) return(0); // must all be the same if (img->width != Width || img->height != Height || img->depth != Depth) { Print("cannot apply filter, images have different size or depth to reference %dx%dx%d\n",Width,Height,Depth); return 0; } cp = CloneImage(img); _filter_pop(img); // slide the window DestroyImage(history[0]); for(i=0; i