Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

kernelfactory.c

Go to the documentation of this file.
00001 
00008 #include "kernelfactory.h"
00009 #include "cmdparam.h"
00010 
00011 
00012 /* Static variables in KernelFactory */
00013 double KernelFactory::blur_radius=0;
00014 double KernelFactory::blur_radius_surround_multiplier=1.6;
00015 double KernelFactory::blur_scale=1.0;
00016 double KernelFactory::blur_range_multiplier=1.0;
00017 int    KernelFactory::blur_type=Blur_CircularAverage;
00018 char   KernelFactory::default_kernel_filename[CMD_MAX_LINE_LENGTH] = "kernel.pgm";
00019 
00020 
00021 
00022 void  KernelFactory::register_params_and_commands( void )
00023 {
00024   PARAM_II(PARAM_INT,   blur_type,&blur_type,0,KernelFactory::max_blur_type,
00025           "Type of blurring, smoothing, or (in general) convolution to use on the\n"
00026           "inputs to be presented, when blur_radius>0.  Available types include\n"
00027           "the following (prefixed with 'Blur_'):\n"
00028           "  CircularAverage,SquareAverage,Gaussian,DoG,LoG,GoD,DoGGoD");
00029   params_define_default_expr("blur_type","Blur_CircularAverage");
00030   
00031   PARAM_LL(PARAM_DOUBLE,blur_radius,&blur_radius,0,
00032           "Default blurring or smoothing radius for the input, in retinal receptors.\n"
00033           "If zero, no blurring function is applied.  This parameter determines the\n"
00034           "nominal radius, but the various blur_type options each produce a function\n"
00035           "with a different actual width.  For instance, a Gaussian with sigma blur_radius\n"
00036           "is much narrower than a uniform circle of radius blur_radius, yet wider\n"
00037           "than the Laplacian of a Gaussian.  See also blur_type and\n"
00038           "blur_range_multiplier.");
00039   
00040   PARAM_LL(PARAM_DOUBLE,blur_radius_surround_multiplier,&blur_radius_surround_multiplier,0,
00041           "Ratio of surround radius to blur_radius.  Defaults to 1.6, which makes the\n"
00042           "DoG approximate the Laplacian derivative of a Gaussian (see Blur_LoG,\n"
00043           "\\cite{marr:prslb80,marr:vision}), albeit at a different spatial scale.");
00044   
00045   PARAM_LL(PARAM_DOUBLE,blur_range_multiplier,&blur_range_multiplier,0,
00046           "Each non-constant blur_type (i.e., those other than Blur_SquareAverage\n"
00047           "and Blur_CircularAverage) has a default maximum circular radius at which\n"
00048           "to evaluate the blurring function (i.e., clipping).  The default should\n"
00049           "usually be sufficient, but it can be increased for greater accuracy (or\n"
00050           "decreased for speed) by making this parameter higher or lower than 1.0,\n"
00051           "respectively.  Since clipping is done circularly, the shape of an isotropic\n"
00052           "kernel should remain approximately isotropic even when the multiplier is set\n"
00053           "far enough below 1.0 that heavy clipping occurs.");
00054   
00055   PARAM_LL(PARAM_DOUBLE,blur_scale,&blur_scale,0,
00056           "Intensity scale for the blurring kernel, if any.  This is primarily useful\n"
00057           "for blurring types which change the input strength dramatically, such as\n"
00058           "Blur_DoG or a Blur_Gaussian with a large radius.  This scaling factor is\n"
00059           "used only when blur_radius>0, so it can help make the input strength\n"
00060           "independent of whether blurring is in use.");
00061   
00062   CONST_I(Blur_CircularAverage,Blur_CircularAverage,False,
00063            "Blur type (see command input_define_convolution) with parameters:\n"
00064            "  [<radius> [<scale>]]\n\n"
00065 
00066            "Replaces each input pixel with the given scale times the arithmetic mean\n"
00067            "of the pixels in the surrounding circular region with the specified radius.\n\n"
00068 
00069            "For a very small radius, the approximation to a circle is poor (e.g.,\n"
00070            "it is square when radius=1).  That property can make this otherwise\n"
00071            "isotropic filter anisotropic.  This type of blurring doesn't work\n"
00072            "particularly well with patterns that have sharp edges, since the\n"
00073            "blurring pattern also has a sharp edge.  However, this type of blurring\n"
00074            "is much faster than ones like Blur_Gaussian, since a smaller convolution\n"
00075            "kernel is needed, and a flat one can sometimes be simpler to reason about.");
00076 
00077   CONST_I(Blur_SquareAverage,Blur_SquareAverage,False,
00078           "Blur type (see command input_define_convolution) with parameters:\n"
00079           "  [<radius> [<scale>]]\n\n"
00080 
00081           "Replaces each input pixel with the given scale times the arithmetic mean\n"
00082           "of the pixels in the surrounding square region with the specified integer\n"
00083           "radius.\n\n"
00084 
00085           "This type of blurring is not isotropic, i.e. it blurs differently\n"
00086           "for different directions, so it should usually be avoided.");
00087   
00088   CONST_I(Blur_Gaussian,Blur_Gaussian,False,
00089           "Blur type (see command input_define_convolution) with parameters:\n"
00090           "  [<radius> [<scale> [<radius_range_scale>]]]\n\n"
00091 
00092           "Replaces each input pixel with the convolution of a Gaussian (with the\n"
00093           "specified radius) with the input image surrounding that pixel.  The\n" 
00094           "Gaussian is normalized to have a total sum of 1.0 by default, but if a\n" 
00095           "different scale is specified, the normalized Gaussian is multiplied by\n"
00096           "it.\n\n"
00097 
00098           "The function is continuous but is only evaluated up to a finite distance from\n"
00099           "its center in all directions.  If desired, a scale for this maximum radius may\n"
00100           "be supplied, which is multiplied by the function's radius to get the actual\n"
00101           "range. By default, a range is used which ensures that the function is nearly\n"
00102           "zero without having a kernel that is too large, which would slow down the\n"
00103           "program.  The blur_range_multiplier can be used to increase or decrease this\n"
00104           "default automatically.\n\n"
00105           
00106           "This type of blurring is effective at removing detail at a spatial scale below\n"
00107           "the radius of the Gaussian, without introducing edge effects like\n"
00108           "Blur_CircularAverage.  (It is essentially a low-pass filter with a cutoff\n"
00109           "frequency determined by the blur_radius.)");
00110   
00111   CONST_I(Blur_LoG,Blur_LoG,False,
00112           "Blur type (see command input_define_convolution) with parameters:\n"
00113           "  [<radius> [<scale> [<radius_range_scale>]]]\n\n"
00114 
00115           "Replaces each input pixel with the convolution of the Laplacian derivative\n"
00116           "of a Gaussian (with radius blur_radius and height 1.0) with the input image\n"
00117           "surrounding that pixel.  The scale is currently arbitrary, but it can be\n" 
00118           "adjusted with the scale parameter.  See Blur_Gaussian for a description of\n"
00119           "the radius_range_scale parameter.\n\n"
00120 
00121           "This type of blurring is nearly identical in shape to a Blur_DoG, and\n"
00122           "\\cite{marr:vision} has proposed that a DoG is approximating this\n"
00123           "function.  However, the height and spatial scales differ substantially\n"
00124           "from a DoG, partially because the DoG can easily be normalized to\n"
00125           "sum to zero, so it may be difficult to use this blurring type (though\n"
00126           "no less computationally efficient).");
00127   
00128   
00129   CONST_I(Blur_DoG,Blur_DoG,False,
00130           "Blur type (see command input_define_convolution) with parameters:\n"
00131           "  [<radius> [<surround_radius> [<scale> [<surround_scale> [<radius_range_scale>]]]]\n\n"
00132           
00133           "Replaces each input pixel with the convolution of a Difference of Gaussians\n"
00134           "(a Mexican-hat whose center Gaussian sums to the given scale and has the given\n"
00135           "radius and whose surround (negative) Gaussian sums to the given surround_scale\n"
00136           "and has the given surround_radius) with the input image surrounding that pixel.\n"
00137           "The surround_radius defaults to be blur_radius*blur_radius_surround_multiplier.\n\n"
00138           
00139           "See Blur_Gaussian for a description of the radius_range_scale parameter; the\n"
00140           "surround radius is used as a base since it is presumably larger than the other.\n\n"
00141           
00142           "This type of blurring serves to detect edges and similar structures at a scale\n"
00143           "somewhat smaller than the radius of the center Gaussian, and resembles\n"
00144           "the processing done by a population of RF-size-matched retinal ganglion cells.\n"
00145           "(It is basically a band-pass spatial filter.)");
00146   
00147   CONST_I(Blur_GoD,Blur_GoD,False,
00148           "Blur type (see command input_define_convolution) with parameters:\n"
00149           "  [<radius> [<surround_radius> [<scale> [<surround_scale> [<radius_range_scale>]]]]\n\n"
00150           
00151           "This blur_type is the same as Blur_DoG except that the surround Gaussian\n"
00152           "is taken as positive while the center is negative (OFF-center).  Given that\n"
00153           "the retina itself is always positive, this filter serves to highlight changes\n"
00154           "of the opposite sign as Blur_DoG (e.g. a dark area surrounded by light).");
00155   
00156   CONST_I(Blur_DoGGoD,Blur_DoGGoD,False,
00157           "Blur type (see command input_define_convolution) with parameters:\n"
00158           "  [<radius> [<surround_radius> [<scale> [<surround_scale> [<radius_range_scale>]]]]\n\n"
00159           
00160           "When this blur_type is used, even-numbered eyes (starting at zero) use\n"
00161           "Blur_DoG while the rest use Blur_GoD.  Assuming every pair of eyes\n"
00162           "has identical input patterns, the pair thus approximates a full set of\n"
00163           "ON-center and OFF-center inputs.  Presumably, num_eyes should be 2 or 4\n"
00164           "for this blurring type to be meaningful.");
00165   
00166   
00167   CONST_I(Blur_PGM,Blur_PGM,False,
00168           "Blur type (see command input_define_convolution) with parameters:\n"
00169           "  [<filename> [<offset> [<scale> [<normalize>]]]]\n\n"
00170           
00171           "The given PGM image file (\"kernel.pgm\" by default) is read and\n"
00172           "used as a convolution kernel.  The value range specified in the file\n"
00173           "is scaled to a range from 0 to 1.0, then the offset (-0.5 by default)\n"
00174           "is added. Next, if normalization is enabled (on by default), the\n"
00175           "matrix is normalized to have a sum of the given scale; otherwise\n"
00176           "the matrix is simply multiplied by the given scale.");
00177 }
00178 
00179 
00180 
00201 KernelFactory::KernelMatrix KernelFactory::create( int index, double wss, StringArgs arglist )
00202 {
00203   KernelMatrix kernel;
00204   const int type = arglist.next(blur_type);
00205   string errors;
00206   
00207   /* Types are grouped into classes based on arguments accepted */
00208   switch (type) {
00209     
00210   case Blur_PGM: {
00211     const string filename  = arglist.next(string(default_kernel_filename));
00212     const double offset    = arglist.next(-0.5);
00213     const double scale     = arglist.next(blur_scale);
00214     const int    normalize = arglist.next(1);
00215     KernelMatrix new_kernel;
00216     
00217     if (!pgm_read(filename, new_kernel)) {
00218       ipc_notify(IPC_ONE,IPC_ERROR, "Can't read file: %s", filename.c_str());
00219       break;
00220     }
00221     
00222     if (new_kernel.ncols()%2 != 1 || new_kernel.nrows()%2 != 1){
00223       ipc_notify(IPC_ONE,IPC_ERROR,
00224                  "The convolution matrix must have an odd number of columns and rows (%d,%d)",
00225                  new_kernel.ncols(),new_kernel.nrows());
00226       break;
00227     }
00228     new_kernel += offset;
00229     
00230     if (!normalize)
00231       new_kernel *= scale;
00232     else {
00233       const double kernelsum = mat::sum(new_kernel);
00234       if (kernelsum==0)
00235         ipc_notify(IPC_ONE,IPC_ERROR,"Can't normalize blurring kernel since it sums to zero");
00236       else new_kernel *= fabs(scale/kernelsum);
00237     }
00238     
00239     kernel = new_kernel;
00240     break;
00241   }
00242   
00243   
00244   case Blur_SquareAverage: case Blur_CircularAverage: case Blur_Gaussian: case Blur_LoG: {
00245     
00246     const double rad   = arglist.next(blur_radius*wss);
00247     if (rad==0) break;
00248     const double scale = arglist.next(blur_scale);
00249     
00250     switch (type) {
00251     case Blur_SquareAverage:   kernel = create(RadialFunction::Constant, rad,(int)rad,errors,false); break;
00252     case Blur_CircularAverage: kernel = create(RadialFunction::Constant, rad,(int)rad,errors); break;
00253     case Blur_Gaussian: {
00254       const double rscale = arglist.next(4.7*blur_range_multiplier);
00255       kernel = create(RadialFunction::Gaussian, rad, (int)ROUND(rad*rscale),errors); break;
00256     }
00257     case Blur_LoG: {
00258       const double rscale = arglist.next(3.2*blur_range_multiplier);
00259       kernel = create(RadialFunction::LoG, rad, (int)ROUND(rad*rscale),errors,true,false); break;
00260     }
00261     }
00262     kernel *= scale;
00263     break;
00264   }
00265   
00266   case Blur_DoG: case Blur_GoD: case Blur_DoGGoD: {
00267     /* Determine sign of kernel; DoGGoD uses 1 for even, -1 for odd */
00268     const double scalesign   = (  type == Blur_DoG    ?  1.0           :
00269                                 ( type == Blur_GoD    ? -1.0            :
00270                                  (type == Blur_DoGGoD ?  1.0-2*(index%2) :
00271                                   1.0)));
00272     
00273     const double rad         = arglist.next((blur_radius)*wss);
00274     if (rad==0) break;
00275     
00276     const double srad        = arglist.next((blur_radius_surround_multiplier*rad/wss)*wss);
00277     const double scale       = arglist.next(blur_scale);
00278     const double sscale      = arglist.next(scale);
00279     const double range_scale = arglist.next(4.7*blur_range_multiplier);
00280     const int    maxrad      = int(ROUND(srad*range_scale));
00281     
00282 #ifdef USE_MTL_MATRIX   
00283     kernel  = create(RadialFunction::Gaussian,  rad, maxrad,errors);
00284     mtl::scale(kernel,scale*scalesign);
00285     mtl::add( mtl::scaled(create(RadialFunction::Gaussian, srad, maxrad,errors), -1*sscale*scalesign), kernel);
00286 #else
00287     kernel = create(RadialFunction::Gaussian, rad,  maxrad,errors) * scale*scalesign  -
00288              create(RadialFunction::Gaussian, srad, maxrad,errors) * sscale*scalesign;
00289 #endif
00290     break;
00291   }
00292   
00293   default: ipc_notify(IPC_ONE,IPC_ERROR,"Unknown blur_type %d",type); break;
00294   }
00295 
00296   if (errors!="")
00297     ipc_notify(IPC_ONE,IPC_ERROR,errors.c_str());
00298 
00299   return kernel;
00300 }
00301 

Generated at Mon Aug 21 00:30:54 2000 for RF-LISSOM by doxygen1.2.1 written by Dimitri van Heesch, © 1997-2000