/* @(#) Typical filter function * @(#) va_list is flag, filter parameters * @(#) * @(#) The following masks are implemented in this file * @(#) flag, filter shape, parameters * @(#) band pass ring reject filters * @(#) 12 -\> idealbpf, parameters: frequency cutoff, width * @(#) 13 -\> idealbrf, parameters: frequency cutoff, width * @(#) 14 -\> butbpf, parameters: order, freq cutoff, width, ampl cutoff * @(#) 15 -\> butbrf, parameters: order, freq cutoff, width, ampl cutoff * @(#) 16 -\> gaussianbpf, parameters: frequency cutoff, width, ampl cutoff * @(#) 17 -\> gaussianbrf, parameters: frequency cutoff, width, ampl cutoff * @(#) * @(#) The whole mask is created at once and written into the image file * @(#) * @(#) The following functions are contained within this file: * @(#) Details are preceding the source code of each function * @(#) * @(#) int im__fmaskcir( out, flag, ap) * @(#) IMAGE *out; * @(#) enum mask_type flag; * @(#) va_list ap; * @(#) * * Copyright: N. Dessipris, 1991 * Written on: Nov 1991 * Updated on: Dec 1991 * 20/9/95 JC * - modernised */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #ifdef WITH_DMALLOC #include #endif /*WITH_DMALLOC*/ /************************************************************************ * malloc space and create normalised coefficients accross * the x (horizontal) and y (vertical) direction. * xs, ys are the image sizes * xd and yd are the scrambled distributions of x and y in the rotated * Fourier transform * xplusd is the non scrambled distribution of (x+x0)*(x+x0) centred at 0 * xminus is the non scrambled distribution of (x-x0)*(x-x0) centred at 0 * similar for yplusd and yminusd ************************************************************************/ static int alloc( IMAGE *out, int xs, int ys, int **xd, int **yd, int **xplusd, int **xminusd, int **yplusd, int **yminusd, int x0, int y0, float **line ) { int i; int *x, *y, *xp, *xm, *yp, *ym; int *pp, *pm; float *l; x = IM_ARRAY( out, xs, int ); y = IM_ARRAY( out, ys, int ); xp = IM_ARRAY( out, xs, int ); xm = IM_ARRAY( out, xs, int ); yp = IM_ARRAY( out, ys, int ); ym = IM_ARRAY( out, ys, int ); l = IM_ARRAY( out, xs, float ); if( !x || !y || !xp || !xm || !yp || !ym || !l ) return( -1 ); /* if ys = 8 then y = {0,1,2,3,-4,-3,-2,-1}. */ for( i = 0; i < ys/2; i++ ) { y[i] = i; y[i+ys/2] = -ys/2 + i; } for( i = 0; i < xs/2; i++ ) { x[i] = i; x[i+xs/2] = -xs/2 + i; } *xd = x; *yd = y; pp = yp + ys/2; pm = ym + ys/2; for( i = -ys/2; i < ys/2; i++ ) { pp[i] = (i + y0)*(i + y0); pm[i] = (i - y0)*(i - y0); } *yplusd = yp + ys/2; *yminusd = ym + ys/2; pp = xp + xs/2; pm = xm + xs/2; for( i = -xs/2; i < xs/2; i++ ) { pp[i] = (i+x0)*(i+x0); pm[i] = (i-x0)*(i-x0); } *xplusd = xp + xs/2; *xminusd = xm + xs/2; *line = l; return( 0 ); } /************************************************************************/ /* FLAG = 12 */ /* Creates an ideal band pass filter mask */ /* The band is two CIRCLEs of radius r centred */ /* at (fcx, fcy) and (-fcx, -fcy) */ /************************************************************************/ static int ideal_bpf( IMAGE *out, double fcx, double fcy, double r ) { int x, y; int xs = out->Xsize; int ys = out->Ysize; float *line, *cpline; int *xd, *yd, *xplusx0d, *xminusx0d, *yplusy0d, *yminusy0d; int x0, y0, d1_2, d2_2, r2; int y2plus, y2minus; if( xs != ys ) { im_errormsg( "ideal_bpf: bad sizes" ); return( -1 ); } if( fabs(fcx) <= 1.0 && fabs(fcy) < 1.0 && r > 0.0 && r < 1.0 ) { x0 = fcx*xs / 2.0; y0 = fcy*ys / 2.0; r2 = r*r*xs / 4.0; } else if( fabs(fcx) < xs/2 && fabs(fcy) < ys/2 && r >= 1.0 ) { x0 = fcx; y0 = fcy; r2 = r*r; } else { im_errormsg( "ideal_bpf: bad args" ); return( -1 ); } if( alloc( out, xs, ys, &xd, &yd, &xplusx0d, &xminusx0d, &yplusy0d, &yminusy0d, x0, y0, &line ) ) return( -1 ); for( y = 0; y < ys; y++ ) { cpline = line; y2plus = yplusy0d[yd[y]]; y2minus = yminusy0d[yd[y]]; for( x = 0; x < xs; x++ ) { d1_2 = xminusx0d[xd[x]] + y2minus; d2_2 = xplusx0d[xd[x]] + y2plus; if( d1_2 <= r2 ) *cpline = 1.0; else if( d2_2 <= r2 ) *cpline = 1.0; else *cpline = 0.0; if( x == 0 && y == 0 ) *cpline = 1.0; /* allow the dc component */ cpline++; } if( im_writeline( y, out, (PEL *) line ) ) return( -1 ); } return( 0 ); } /************************************************************************/ /* FLAG = 13 */ /* Creates an ideal band reject filter mask */ /* The band is a CIRCLE of internal radius fc-df and external radius fc+df*/ /************************************************************************/ static int ideal_brf( IMAGE *out, double fcx, double fcy, double r ) { int x, y; int xs = out->Xsize; int ys = out->Ysize; float *line, *cpline; int *xd, *yd, *xplusx0d, *xminusx0d, *yplusy0d, *yminusy0d; int x0, y0, d1_2, d2_2, r2; int y2plus, y2minus; if( xs != ys ) { im_errormsg( "ideal_brf: bad args" ); return( -1 ); } if( fabs(fcx) <= 1.0 && fabs(fcy) <= 1.0 && r > 0.0 && r < 1.0 ) { x0 = fcx*xs / 2.0; y0 = fcy*ys / 2.0; r2 = r*r*xs / 4.0; } else if( fabs(fcx) < xs/2 && fabs(fcy) < ys/2 && r >= 1.0 ) { x0 = fcx; y0 = fcy; r2 = r*r; } else { im_errormsg( "ideal_brf: bad args" ); return( -1 ); } if( alloc( out, xs, ys, &xd, &yd, &xplusx0d, &xminusx0d, &yplusy0d, &yminusy0d, x0, y0, &line ) ) return( -1 ); for( y = 0; y < ys; y++ ) { cpline = line; y2plus = yplusy0d[yd[y]]; y2minus = yminusy0d[yd[y]]; for( x = 0; x < xs; x++ ) { d1_2 = xminusx0d[xd[x]] + y2minus; d2_2 = xplusx0d[xd[x]] + y2plus; if( d1_2 <= r2 ) *cpline = 0.0; else if( d2_2 <= r2 ) *cpline = 0.0; else *cpline = 1.0; if( x == 0 && y == 0 ) *cpline = 1.0; cpline++; } if( im_writeline( y, out, (PEL *) line ) ) return( -1 ); } return( 0 ); } /************************************************************************/ /* FLAG = 14 */ /* Creates a butterworth band pass filter mask */ /* The band is two CIRCLES centred at (fcx, fcy) and (-fcx, -fcy) */ /* The program assummes that the peaks of the 2d mask are at the */ /* centres above and are set to 1.0. The amplitude of both circle mask */ /* are added and the cuttof frequency is calculated on the plane */ /* which passes though the centre of the circles and the 0 point */ /************************************************************************/ static int butterworth_bpf( IMAGE *out, double order, double fcx, double fcy, double r, double ac ) { int x, y; int xs = out->Xsize; int ys = out->Ysize; float *line, *cpline; int *xd, *yd, *xplusx0d, *xminusx0d, *yplusy0d, *yminusy0d; int x0, y0; double cnst, cnsta, d1_2, d2_2, nr2; /* nr2 is new r squared */ int y2plus, y2minus; if( xs != ys || order < 1.0 ) { im_errormsg( "butterworth_bpf: bad sizes" ); return( -1 ); } if( fabs(fcx) <= 1.0 && fabs(fcy) <= 1.0 && r > 0.0 && r < 1.0 ) { x0 = fcx*xs / 2.0; y0 = fcy*ys / 2.0; nr2 = r*r*xs*xs / 4.0; } else if( fabs(fcx) < xs/2 && fabs(fcy) < ys/2 && r >= 1.0 ) { x0 = fcx; y0 = fcy; nr2 = r*r; } else { im_errormsg( "butterworth_bpf: bad args" ); return( -1 ); } if( ac >= 1.0 || ac < 0.0) { im_errormsg( "butterworth_bpf: bad args" ); return( -1 ); } if( alloc( out, xs, ys, &xd, &yd, &xplusx0d, &xminusx0d, &yplusy0d, &yminusy0d, x0, y0, &line ) ) return( -1 ); /* Filter shape: radius d0, centres at (x0, y0), (-x0,-y0) * H(d) = H1(d) + H2(d) * H(d) = cnst1/(1 + cnst2 * pow((d-d0)/d0, 2*order)) + * cnst1/(1 + cnst2 * pow((d+d0)/d0, 2*order)); * for d=+d0 H(+d0) = 1.0; for d=-d0 H(-d0) = 1.0; * for d=+da H(+da) = ampl_cutof; for d=-da H1(-da) = ampl_cutof; * da = (xa, ya) * xa = x0*(1 - radius/sqrt(x0*x0+y0*y0)) * ya = y0*(1 - radius/sqrt(x0*x0+y0*y0)) */ cnst = (1.0/ac) - 1.0; /* normalise the amplitude at (x0,y0) to 1.0 */ cnsta = 1.0 / (1.0 + 1.0 / (1.0 + cnst*pow( 4.0*(x0*x0 + y0*y0)/nr2, order ))); for( y = 0; y < ys; y++ ) { cpline = line; y2plus = yplusy0d[yd[y]]; y2minus = yminusy0d[yd[y]]; for( x = 0; x < xs; x++ ) { d1_2 = xminusx0d[xd[x]] + y2minus; d2_2 = xplusx0d[xd[x]] + y2plus; *cpline = cnsta * ( 1.0 / (1.0 + cnst * pow( d1_2/nr2, order )) + 1.0 / (1.0 + cnst * pow( d2_2/nr2, order )) ); if( x == 0 && y == 0 ) *cpline = 1.0; cpline++; } if( im_writeline( y, out, (PEL *) line ) ) return( -1 ); } return( 0 ); } /************************************************************************/ /* FLAG = 15 */ /* Creates a butterworth band pass filter mask */ /* The band is a the 1-H(f) of above */ /************************************************************************/ static int butterworth_brf( IMAGE *out, double order, double fcx, double fcy, double r, double ac ) { int x, y; int xs = out->Xsize; int ys = out->Ysize; float *line, *cpline; int *xd, *yd, *xplusx0d, *xminusx0d, *yplusy0d, *yminusy0d; int x0, y0; double cnst, cnsta, d1_2, d2_2, nr2; /* nr2 is new r squared */ int y2plus, y2minus; if( xs != ys || order < 1.0 ) { im_errormsg( "butterworth_brf: bad sizes" ); return( -1 ); } if( fabs(fcx) <= 1.0 && fabs(fcy) <= 1.0 && r > 0.0 && r < 1.0 ) { x0 = fcx * xs / 2.0; y0 = fcy * ys / 2.0; nr2 = r*r*xs*xs / 4.0; } else if( fabs(fcx) < xs/2 && fabs(fcy) < ys/2 && r >= 1.0 ) { x0 = fcx; y0 = fcy; nr2 = r*r; } else { im_errormsg( "butterworth_brf: bad args" ); return( -1 ); } if( ac >= 1.0 || ac < 0.0) { im_errormsg( "butterworth_brf: bad args" ); return( -1 ); } if( alloc( out, xs, ys, &xd, &yd, &xplusx0d, &xminusx0d, &yplusy0d, &yminusy0d, x0, y0, &line ) ) return( -1 ); cnst = (1.0/ac) - 1.0; /* normalise the amplitude at (x0,y0) to 1.0 */ cnsta = 1.0 / (1.0 + 1.0 / (1.0 + cnst * pow( 4.0*(x0*x0 + y0*y0)/nr2, order ))); for( y = 0; y < ys; y++ ) { cpline = line; y2plus = yplusy0d[yd[y]]; y2minus = yminusy0d[yd[y]]; for( x = 0; x < xs; x++ ) { d1_2 = xminusx0d[xd[x]] + y2minus; d2_2 = xplusx0d[xd[x]] + y2plus; if( d1_2 == 0.0 || d2_2 == 0.0 ) *cpline = 0; else *cpline = 1.0 - cnsta * ( 1.0/(1.0 + cnst*pow( d1_2/nr2, order )) + 1.0/(1.0 + cnst*pow( d2_2/nr2, order )) ); if( x == 0 && y == 0 ) *cpline = 1.0; cpline++; } if( im_writeline( y, out, (PEL *) line ) ) return( -1 ); } return( 0 ); } /************************************************************************/ /* FLAG = 16 */ /* Creates a gaussian band pass filter mask */ /* The band is a RING of internal radius fc-df and external radius fc+df*/ /************************************************************************/ static int gaussian_bpf( IMAGE *out, double fcx, double fcy, double r, double ac ) { int x, y; int xs = out->Xsize; int ys = out->Ysize; float *line, *cpline; int *xd, *yd, *xplusx0d, *xminusx0d, *yplusy0d, *yminusy0d; int x0, y0; double cnst, cnsta, d1_2, d2_2, nr2; /* nr2 is new r squared */ int y2plus, y2minus; if( xs != ys ) { im_errormsg( "gauss_bpf: bad sizes" ); return( -1 ); } if( fabs(fcx) <= 1.0 && fabs(fcy) <= 1.0 && r > 0.0 && r < 1.0 ) { x0 = fcx*xs / 2.0; y0 = fcy*ys / 2.0; nr2 = r*r*xs*xs / 4.0; } else if( fabs(fcx) < xs/2 && fabs(fcy) < ys/2 && r >= 1.0 ) { x0 = fcx; y0 = fcy; nr2 = r*r; } else { im_errormsg( "gauss_bpf: bad args (f)" ); return( -1 ); } if( ac >= 1.0 || ac < 0.0 ) { im_errormsg( "gauss_bpf: bad args (ac)" ); return( -1 ); } if( alloc( out, xs, ys, &xd, &yd, &xplusx0d, &xminusx0d, &yplusy0d, &yminusy0d, x0, y0, &line ) ) return( -1 ); cnst = -log( ac ); /* normalise the amplitude at (x0,y0) to 1.0 */ cnsta = 1.0/(1.0 + exp( - cnst * 4.0 * (x0*x0+y0*y0) / nr2 )); for( y = 0; y < ys; y++ ) { cpline = line; y2plus = yplusy0d[yd[y]]; y2minus = yminusy0d[yd[y]]; for( x = 0; x < xs; x++ ) { d1_2 = xminusx0d[xd[x]] + y2minus; d2_2 = xplusx0d[xd[x]] + y2plus; *cpline = cnsta * (exp( -cnst * d1_2/nr2 ) + exp( -cnst * d2_2/nr2 )); if( x == 0 && y == 0 ) *cpline = 1.0; cpline++; } if( im_writeline( y, out, (PEL *) line ) ) return( -1 ); } return( 0 ); } /************************************************************************/ /* FLAG = 17 */ /* Creates a gaussian band reject filter mask */ /* The band is a RING of internal radius fc-df and external radius fc+df*/ /************************************************************************/ static int gaussian_brf( IMAGE *out, double fcx, double fcy, double r, double ac ) { int x, y; int xs = out->Xsize; int ys = out->Ysize; float *line, *cpline; int *xd, *yd, *xplusx0d, *xminusx0d, *yplusy0d, *yminusy0d; int x0, y0; double cnst, cnsta, d1_2, d2_2, nr2; /* nr2 is new r squared */ int y2plus, y2minus; if( xs != ys ) { im_errormsg( "gauss_brf: bad sizes" ); return( -1 ); } if( fabs(fcx) <= 1.0 && fabs(fcy) <= 1.0 && r > 0.0 && r < 1.0 ) { x0 = fcx*xs / 2.0; y0 = fcy*ys / 2.0; nr2 = r*r*xs*xs / 4.0; } else if( fabs(fcx) < xs/2 && fabs(fcy) < ys/2 && r >= 1.0 ) { x0 = fcx; y0 = fcy; nr2 = r * r; } else { im_errormsg( "gauss_brf: bad args" ); return( -1 ); } if( ac >= 1.0 || ac < 0.0 ) { im_errormsg( "gauss_brf: bad args" ); return( -1 ); } if( alloc( out, xs, ys, &xd, &yd, &xplusx0d, &xminusx0d, &yplusy0d, &yminusy0d, x0, y0, &line ) ) return( -1 ); cnst = -log( ac ); /* normalise the amplitude at (x0,y0) to 1.0 */ cnsta = 1.0/(1.0 + exp( - cnst * 4.0 * (x0*x0+y0*y0) / nr2 )); for( y = 0; y < ys; y++ ) { cpline = line; y2plus = yplusy0d[yd[y]]; y2minus = yminusy0d[yd[y]]; for( x = 0; x < xs; x++ ) { d1_2 = xminusx0d[xd[x]] + y2minus; d2_2 = xplusx0d[xd[x]] + y2plus; *cpline = 1.0 - cnsta * (exp( -cnst * d1_2/nr2 ) + exp( -cnst * d2_2/nr2 )); if( x == 0 && y == 0 ) *cpline = 1.0; cpline++; } if( im_writeline( y, out, (PEL *) line ) ) return( -1 ); } return( 0 ); } /* Creates bandpass filter masks * All arithmetic internally has been carried out in double precision; * however all masks are written as floats with maximum value normalised to 1.0 */ int im__fmaskcir( IMAGE *out, MaskType flag, va_list ap ) { /* May be fewer than 5 args ... but extract them all anyway. Should be * safe. */ double p0 = va_arg( ap, double ); double p1 = va_arg( ap, double ); double p2 = va_arg( ap, double ); double p3 = va_arg( ap, double ); double p4 = va_arg( ap, double ); switch( flag ) { /* Band pass - band reject. */ case MASK_IDEAL_BANDPASS: return( ideal_bpf( out, p0, p1, p2 ) ); case MASK_IDEAL_BANDREJECT: return( ideal_brf( out, p0, p1, p2 ) ); case MASK_BUTTERWORTH_BANDPASS: return( butterworth_bpf( out, p0, p1, p2, p3, p4 ) ); case MASK_BUTTERWORTH_BANDREJECT: return( butterworth_brf( out, p0, p1, p2, p3, p4 ) ); case MASK_GAUSS_BANDPASS: return( gaussian_bpf( out, p0, p1, p2, p3 ) ); case MASK_GAUSS_BANDREJECT: return( gaussian_brf( out, p0, p1, p2, p3 ) ); default: im_errormsg( "im__fmaskcir: unimplemented mask" ); return( -1 ); } /*NOTREACHED*/ }