matlab/strred/matlabPyrTools/MEX/convolve.c (244 lines of code) (raw):

/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; File: convolve.c ;;; Author: Eero Simoncelli ;;; Description: General convolution code for 2D images ;;; Creation Date: Spring, 1987. ;;; MODIFICATIONS: ;;; 10/89: approximately optimized the choice of register vars on SPARCS. ;;; 6/96: Switched array types to double float. ;;; 2/97: made more robust and readable. Added STOP arguments. ;;; 8/97: Bug: when calling internal_reduce with edges in {reflect1,repeat, ;;; extend} and an even filter dimension. Solution: embed the filter ;;; in the upper-left corner of a filter with odd Y and X dimensions. ;;; ---------------------------------------------------------------- ;;; Object-Based Vision and Image Understanding System (OBVIUS), ;;; Copyright 1988, Vision Science Group, Media Laboratory, ;;; Massachusetts Institute of Technology. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */ #include <stdio.h> #include <math.h> #include "convolve.h" /* -------------------------------------------------------------------- Correlate FILT with IMAGE, subsampling according to START, STEP, and STOP parameters, with values placed into RESULT array. RESULT dimensions should be ceil((stop-start)/step). TEMP should be a pointer to a temporary double array the size of the filter. EDGES is a string specifying how to handle boundaries -- see edges.c. The convolution is done in 9 sections, where the border sections use specially computed edge-handling filters (see edges.c). The origin of the filter is assumed to be (floor(x_fdim/2), floor(y_fdim/2)). ------------------------------------------------------------------------ */ /* abstract out the inner product computation */ #define INPROD(XCNR,YCNR) \ { \ sum=0.0; \ for (im_pos=YCNR*x_dim+XCNR, filt_pos=0, x_filt_stop=x_fdim; \ x_filt_stop<=filt_size; \ im_pos+=(x_dim-x_fdim), x_filt_stop+=x_fdim) \ for (; \ filt_pos<x_filt_stop; \ filt_pos++, im_pos++) \ sum+= image[im_pos]*temp[filt_pos]; \ result[res_pos] = sum; \ } int internal_reduce(image, x_dim, y_dim, filt, temp, x_fdim, y_fdim, x_start, x_step, x_stop, y_start, y_step, y_stop, result, edges) register image_type *image, *temp; register int x_fdim, x_dim; register image_type *result; register int x_step, y_step; int x_start, y_start; int x_stop, y_stop; image_type *filt; int y_dim, y_fdim; char *edges; { register double sum; register int filt_pos, im_pos, x_filt_stop; register int x_pos, filt_size = x_fdim*y_fdim; register int y_pos, res_pos; register int y_ctr_stop = y_dim - ((y_fdim==1)?0:y_fdim); register int x_ctr_stop = x_dim - ((x_fdim==1)?0:x_fdim); register int x_res_dim = (x_stop-x_start+x_step-1)/x_step; int x_ctr_start = ((x_fdim==1)?0:1); int y_ctr_start = ((y_fdim==1)?0:1); int x_fmid = x_fdim/2; int y_fmid = y_fdim/2; int base_res_pos; fptr reflect = edge_function(edges); /* look up edge-handling function */ if (!reflect) return(-1); /* shift start/stop coords to filter upper left hand corner */ x_start -= x_fmid; y_start -= y_fmid; x_stop -= x_fmid; y_stop -= y_fmid; if (x_stop < x_ctr_stop) x_ctr_stop = x_stop; if (y_stop < y_ctr_stop) y_ctr_stop = y_stop; for (res_pos=0, y_pos=y_start; /* TOP ROWS */ y_pos<y_ctr_start; y_pos+=y_step) { for (x_pos=x_start; /* TOP-LEFT CORNER */ x_pos<x_ctr_start; x_pos+=x_step, res_pos++) { (*reflect)(filt,x_fdim,y_fdim,x_pos-1,y_pos-1,temp,REDUCE); INPROD(0,0) } (*reflect)(filt,x_fdim,y_fdim,0,y_pos-1,temp,REDUCE); for (; /* TOP EDGE */ x_pos<x_ctr_stop; x_pos+=x_step, res_pos++) INPROD(x_pos,0) for (; /* TOP-RIGHT CORNER */ x_pos<x_stop; x_pos+=x_step, res_pos++) { (*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,y_pos-1,temp,REDUCE); INPROD(x_ctr_stop,0) } } /* end TOP ROWS */ y_ctr_start = y_pos; /* hold location of top */ for (base_res_pos=res_pos, x_pos=x_start; /* LEFT EDGE */ x_pos<x_ctr_start; x_pos+=x_step, base_res_pos++) { (*reflect)(filt,x_fdim,y_fdim,x_pos-1,0,temp,REDUCE); for (y_pos=y_ctr_start, res_pos=base_res_pos; y_pos<y_ctr_stop; y_pos+=y_step, res_pos+=x_res_dim) INPROD(0,y_pos) } (*reflect)(filt,x_fdim,y_fdim,0,0,temp,REDUCE); for (; /* CENTER */ x_pos<x_ctr_stop; x_pos+=x_step, base_res_pos++) for (y_pos=y_ctr_start, res_pos=base_res_pos; y_pos<y_ctr_stop; y_pos+=y_step, res_pos+=x_res_dim) INPROD(x_pos,y_pos) for (; /* RIGHT EDGE */ x_pos<x_stop; x_pos+=x_step, base_res_pos++) { (*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,0,temp,REDUCE); for (y_pos=y_ctr_start, res_pos=base_res_pos; y_pos<y_ctr_stop; y_pos+=y_step, res_pos+=x_res_dim) INPROD(x_ctr_stop,y_pos) } for (res_pos-=(x_res_dim-1); y_pos<y_stop; /* BOTTOM ROWS */ y_pos+=y_step) { for (x_pos=x_start; /* BOTTOM-LEFT CORNER */ x_pos<x_ctr_start; x_pos+=x_step, res_pos++) { (*reflect)(filt,x_fdim,y_fdim,x_pos-1,y_pos-y_ctr_stop+1,temp,REDUCE); INPROD(0,y_ctr_stop) } (*reflect)(filt,x_fdim,y_fdim,0,y_pos-y_ctr_stop+1,temp,REDUCE); for (; /* BOTTOM EDGE */ x_pos<x_ctr_stop; x_pos+=x_step, res_pos++) INPROD(x_pos,y_ctr_stop) for (; /* BOTTOM-RIGHT CORNER */ x_pos<x_stop; x_pos+=x_step, res_pos++) { (*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,y_pos-y_ctr_stop+1,temp,REDUCE); INPROD(x_ctr_stop,y_ctr_stop) } } /* end BOTTOM */ return(0); } /* end of internal_reduce */ /* -------------------------------------------------------------------- Upsample IMAGE according to START,STEP, and STOP parameters and then convolve with FILT, adding values into RESULT array. IMAGE dimensions should be ceil((stop-start)/step). See description of internal_reduce (above). WARNING: this subroutine destructively modifies the RESULT array! ------------------------------------------------------------------------ */ /* abstract out the inner product computation */ #define INPROD2(XCNR,YCNR) \ { \ val = image[im_pos]; \ for (res_pos=YCNR*x_dim+XCNR, filt_pos=0, x_filt_stop=x_fdim; \ x_filt_stop<=filt_size; \ res_pos+=(x_dim-x_fdim), x_filt_stop+=x_fdim) \ for (; \ filt_pos<x_filt_stop; \ filt_pos++, res_pos++) \ result[res_pos] += val*temp[filt_pos]; \ } int internal_expand(image,filt,temp,x_fdim,y_fdim, x_start,x_step,x_stop,y_start,y_step,y_stop, result,x_dim,y_dim,edges) register image_type *result, *temp; register int x_fdim, x_dim; register int x_step, y_step; register image_type *image; int x_start, y_start; image_type *filt; int y_fdim, y_dim; char *edges; { register double val; register int filt_pos, res_pos, x_filt_stop; register int x_pos, filt_size = x_fdim*y_fdim; register int y_pos, im_pos; register int x_ctr_stop = x_dim - ((x_fdim==1)?0:x_fdim); int y_ctr_stop = (y_dim - ((y_fdim==1)?0:y_fdim)); int x_ctr_start = ((x_fdim==1)?0:1); int y_ctr_start = ((y_fdim==1)?0:1); int x_fmid = x_fdim/2; int y_fmid = y_fdim/2; int base_im_pos, x_im_dim = (x_stop-x_start+x_step-1)/x_step; fptr reflect = edge_function(edges); /* look up edge-handling function */ if (!reflect) return(-1); /* shift start/stop coords to filter upper left hand corner */ x_start -= x_fmid; y_start -= y_fmid; x_stop -= x_fmid; y_stop -= y_fmid; if (x_stop < x_ctr_stop) x_ctr_stop = x_stop; if (y_stop < y_ctr_stop) y_ctr_stop = y_stop; for (im_pos=0, y_pos=y_start; /* TOP ROWS */ y_pos<y_ctr_start; y_pos+=y_step) { for (x_pos=x_start; /* TOP-LEFT CORNER */ x_pos<x_ctr_start; x_pos+=x_step, im_pos++) { (*reflect)(filt,x_fdim,y_fdim,x_pos-1,y_pos-1,temp,EXPAND); INPROD2(0,0) } (*reflect)(filt,x_fdim,y_fdim,0,y_pos-1,temp,EXPAND); for (; /* TOP EDGE */ x_pos<x_ctr_stop; x_pos+=x_step, im_pos++) INPROD2(x_pos,0) for (; /* TOP-RIGHT CORNER */ x_pos<x_stop; x_pos+=x_step, im_pos++) { (*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,y_pos-1,temp,EXPAND); INPROD2(x_ctr_stop,0) } } /* end TOP ROWS */ y_ctr_start = y_pos; /* hold location of top */ for (base_im_pos=im_pos, x_pos=x_start; /* LEFT EDGE */ x_pos<x_ctr_start; x_pos+=x_step, base_im_pos++) { (*reflect)(filt,x_fdim,y_fdim,x_pos-1,0,temp,EXPAND); for (y_pos=y_ctr_start, im_pos=base_im_pos; y_pos<y_ctr_stop; y_pos+=y_step, im_pos+=x_im_dim) INPROD2(0,y_pos) } (*reflect)(filt,x_fdim,y_fdim,0,0,temp,EXPAND); for (; /* CENTER */ x_pos<x_ctr_stop; x_pos+=x_step, base_im_pos++) for (y_pos=y_ctr_start, im_pos=base_im_pos; y_pos<y_ctr_stop; y_pos+=y_step, im_pos+=x_im_dim) INPROD2(x_pos,y_pos) for (; /* RIGHT EDGE */ x_pos<x_stop; x_pos+=x_step, base_im_pos++) { (*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,0,temp,EXPAND); for (y_pos=y_ctr_start, im_pos=base_im_pos; y_pos<y_ctr_stop; y_pos+=y_step, im_pos+=x_im_dim) INPROD2(x_ctr_stop,y_pos) } for (im_pos-=(x_im_dim-1); y_pos<y_stop; /* BOTTOM ROWS */ y_pos+=y_step) { for (x_pos=x_start; /* BOTTOM-LEFT CORNER */ x_pos<x_ctr_start; x_pos+=x_step, im_pos++) { (*reflect)(filt,x_fdim,y_fdim,x_pos-1,y_pos-y_ctr_stop+1,temp,EXPAND); INPROD2(0,y_ctr_stop) } (*reflect)(filt,x_fdim,y_fdim,0,y_pos-y_ctr_stop+1,temp,EXPAND); for (; /* BOTTOM EDGE */ x_pos<x_ctr_stop; x_pos+=x_step, im_pos++) INPROD2(x_pos,y_ctr_stop) for (; /* BOTTOM-RIGHT CORNER */ x_pos<x_stop; x_pos+=x_step, im_pos++) { (*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,y_pos-y_ctr_stop+1,temp,EXPAND); INPROD2(x_ctr_stop,y_ctr_stop) } } /* end BOTTOM */ return(0); } /* end of internal_expand */ /* Local Variables: */ /* buffer-read-only: t */ /* End: */