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,int(KernelFactory::max_blur_type),
00025           "Type of blurring, smoothing, or (in general) convolution to use on the\n"
00026           "inputs to be presented, when layers_pereye>1.  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, the identity 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.\n\n"
00039 
00040           "Compatibility note: in previous versions, setting blur_radius to zero\n"
00041           "disabled retinal ganglion cell processing, while setting it to a nonzero\n"
00042           "value enabled it.  Such behavior is now controlled by the layers_pereye\n"
00043           "parameter instead, and no longer depends on blur_radius.");
00044   
00045   PARAM_LL(PARAM_DOUBLE,blur_radius_surround_multiplier,&blur_radius_surround_multiplier,0,
00046           "Ratio of surround radius to blur_radius.  Defaults to 1.6, which makes the\n"
00047           "DoG approximate the Laplacian derivative of a Gaussian (see Blur_LoG,\n"
00048           "\\cite{marr:prslb80,marr:vision}), albeit at a different spatial scale.");
00049   
00050   PARAM_LL(PARAM_DOUBLE,blur_range_multiplier,&blur_range_multiplier,0,
00051           "Each non-constant blur_type (i.e., those other than Blur_SquareAverage\n"
00052           "and Blur_CircularAverage) has a default maximum circular radius at which\n"
00053           "to evaluate the blurring function (i.e., clipping).  The default should\n"
00054           "usually be sufficient, but it can be increased for greater accuracy (or\n"
00055           "decreased for speed) by making this parameter higher or lower than 1.0,\n"
00056           "respectively.  Since clipping is done circularly, the shape of an isotropic\n"
00057           "kernel should remain approximately isotropic even when the multiplier is set\n"
00058           "far enough below 1.0 that heavy clipping occurs.");
00059   
00060   PARAM_LL(PARAM_DOUBLE,blur_scale,&blur_scale,0,
00061           "Intensity scale for the blurring kernel, if any.  This is primarily useful\n"
00062           "for blurring types which change the input strength dramatically, such as\n"
00063           "Blur_DoG or a Blur_Gaussian with a large radius.  This scaling factor is\n"
00064           "used only when layers_pereye>1, so it can help make the input strength\n"
00065           "independent of whether blurring is in use.  At present it is the\n"
00066           "equivalent of gammaaff for a FixedWtRegion, and should probably\n"
00067           "be phased out in favor of gammaaff for simplicity.");
00068   
00069   CONST_I(Blur_CircularAverage,int(Blur_CircularAverage),False,
00070           "Blur type (see command input_define_convolution) with parameters:\n"
00071           "  [<radius> [<scale>]]\n\n"
00072           
00073           "Replaces each input pixel with the given scale times the arithmetic mean\n"
00074           "of the pixels in the surrounding circular region with the specified radius.\n\n"
00075           
00076           "For a very small radius, the approximation to a circle is poor (e.g.,\n"
00077           "it is square when radius=1).  That property can make this otherwise\n"
00078           "isotropic filter anisotropic.  This type of blurring doesn't work\n"
00079           "particularly well with patterns that have sharp edges, since the\n"
00080           "blurring pattern also has a sharp edge.  However, this type of blurring\n"
00081           "is much faster than ones like Blur_Gaussian, since a smaller convolution\n"
00082           "kernel is needed, and a flat one can sometimes be simpler to reason about.");
00083 
00084   CONST_I(Blur_CircularRandom,int(Blur_CircularRandom),False,
00085           "Blur type (see command input_define_convolution) with parameters:\n"
00086           "  [<radius> [<scale>]]\n\n"
00087           
00088           "Replaces each input pixel with the convolution of a circular region (with\n"
00089           "the specified radius) of random values with the input image surrounding\n" 
00090           "that pixel.  The values are normalized to have a total sum of 1.0 by\n" 
00091           "default, but if a different scale is specified, the normalized sum\n"
00092           "is then multiplied by it.\n\n"
00093 
00094           "This type of blurring is a default against which some more effective\n"
00095           "variety may be compared.");
00096   
00097   CONST_I(Blur_SquareAverage,int(Blur_SquareAverage),False,
00098           "Blur type (see command input_define_convolution) with parameters:\n"
00099           "  [<radius> [<scale>]]\n\n"
00100 
00101           "Replaces each input pixel with the given scale times the arithmetic mean\n"
00102           "of the pixels in the surrounding square region with the specified integer\n"
00103           "radius.\n\n"
00104 
00105           "This type of blurring is not isotropic, i.e. it blurs differently\n"
00106           "for different directions, so it should usually be avoided.");
00107   
00108   CONST_I(Blur_SquareRandom,int(Blur_SquareRandom),False,
00109           "Blur type (see command input_define_convolution) with parameters:\n"
00110           "  [<radius> [<scale>]]\n\n"
00111           
00112           "Replaces each input pixel with the convolution of a square region (with\n"
00113           "the specified radius) of random values with the input image surrounding\n" 
00114           "that pixel.  The values are normalized to have a total sum of 1.0 by\n" 
00115           "default, but if a different scale is specified, the normalized sum\n"
00116           "is then multiplied by it.\n\n"
00117 
00118           "This type of blurring is a default against which some more effective\n"
00119           "variety may be compared.");
00120   
00121   CONST_I(Blur_Gaussian,int(Blur_Gaussian),False,
00122           "Blur type (see command input_define_convolution) with parameters:\n"
00123           "  [<radius> [<scale> [<radius_range_scale>]]]\n\n"
00124 
00125           "Replaces each input pixel with the convolution of a Gaussian (with the\n"
00126           "specified radius) with the input image surrounding that pixel.  The\n" 
00127           "Gaussian is normalized to have a total sum of 1.0 by default, but if a\n" 
00128           "different scale is specified, the normalized Gaussian is multiplied by\n"
00129           "it.\n\n"
00130 
00131           "The function is continuous but is only evaluated up to a finite distance from\n"
00132           "its center in all directions.  If desired, a scale for this maximum radius may\n"
00133           "be supplied, which is multiplied by the function's radius to get the actual\n"
00134           "range. By default, a range is used which ensures that the function is nearly\n"
00135           "zero without having a kernel that is too large, which would slow down the\n"
00136           "program.  The blur_range_multiplier can be used to increase or decrease this\n"
00137           "default automatically.\n\n"
00138           
00139           "This type of blurring is effective at removing detail at a spatial scale below\n"
00140           "the radius of the Gaussian, without introducing edge effects like\n"
00141           "Blur_CircularAverage.  (It is essentially a low-pass filter with a cutoff\n"
00142           "frequency determined by the blur_radius.)");
00143   
00144   CONST_I(Blur_LoG,int(Blur_LoG),False,
00145           "Blur type (see command input_define_convolution) with parameters:\n"
00146           "  [<radius> [<scale> [<radius_range_scale>]]]\n\n"
00147 
00148           "Replaces each input pixel with the convolution of the Laplacian derivative\n"
00149           "of a Gaussian (with radius blur_radius and height 1.0) with the input image\n"
00150           "surrounding that pixel.  The scale is currently arbitrary, but it can be\n" 
00151           "adjusted with the scale parameter.  See Blur_Gaussian for a description of\n"
00152           "the radius_range_scale parameter.\n\n"
00153 
00154           "This type of blurring is nearly identical in shape to a Blur_DoG, and\n"
00155           "\\cite{marr:vision} has proposed that a DoG is approximating this\n"
00156           "function.  However, the height and spatial scales differ substantially\n"
00157           "from a DoG, partially because the DoG can easily be normalized to\n"
00158           "sum to zero, so it may be difficult to use this blurring type (though\n"
00159           "no less computationally efficient).");
00160   
00161   
00162   CONST_I(Blur_DoG,int(Blur_DoG),False,
00163           "Blur type (see command input_define_convolution) with parameters:\n"
00164           "  [<radius> [<surround_radius> [<scale> [<surround_scale> [<radius_range_scale>]]]]\n\n"
00165           
00166           "Replaces each input pixel with the convolution of a Difference of Gaussians\n"
00167           "(a Mexican-hat whose center Gaussian sums to the given scale and has the given\n"
00168           "radius and whose surround (negative) Gaussian sums to the given surround_scale\n"
00169           "and has the given surround_radius) with the input image surrounding that pixel.\n"
00170           "The surround_radius defaults to be blur_radius*blur_radius_surround_multiplier.\n\n"
00171           
00172           "See Blur_Gaussian for a description of the radius_range_scale parameter; the\n"
00173           "surround radius is used as a base since it is presumably larger than the other.\n\n"
00174           
00175           "This type of blurring serves to detect edges and similar structures at a scale\n"
00176           "somewhat smaller than the radius of the center Gaussian, and resembles\n"
00177           "the processing done by a population of RF-size-matched retinal ganglion cells.\n"
00178           "(It is basically a band-pass spatial filter.)");
00179   
00180   CONST_I(Blur_GoD,int(Blur_GoD),False,
00181           "Blur type (see command input_define_convolution) with parameters:\n"
00182           "  [<radius> [<surround_radius> [<scale> [<surround_scale> [<radius_range_scale>]]]]\n\n"
00183           
00184           "This blur_type is the same as Blur_DoG except that the surround Gaussian\n"
00185           "is taken as positive while the center is negative (OFF-center).  Given that\n"
00186           "the retina itself is always positive, this filter serves to highlight changes\n"
00187           "of the opposite sign as Blur_DoG (e.g. a dark area surrounded by light).");
00188   
00189   CONST_I(Blur_DoGGoD,int(Blur_DoGGoD),False,
00190           "Blur type (see command input_define_convolution) with parameters:\n"
00191           "  [<radius> [<surround_radius> [<scale> [<surround_scale> [<radius_range_scale>]]]]\n\n"
00192           
00193           "When this blur_type is used, even-numbered eyes (starting at zero) use\n"
00194           "Blur_DoG while the rest use Blur_GoD.  Assuming every pair of eyes\n"
00195           "has identical input patterns, the pair thus approximates a full set of\n"
00196           "ON-center and OFF-center inputs.  Presumably, num_eyes should be 2 or 4\n"
00197           "for this blurring type to be meaningful.");
00198   
00199   CONST_I(Blur_PGM,int(Blur_PGM),False,
00200           "Blur type (see command input_define_convolution) with parameters:\n"
00201           "  [<filename> [<offset> [<scale> [<normalize>]]]]\n\n"
00202           
00203           "The given PGM image file (\"kernel.pgm\" by default) is read and\n"
00204           "used as a convolution kernel.  The value range specified in the file\n"
00205           "is scaled to a range from 0 to 1.0, then the offset (-0.5 by default)\n"
00206           "is added. Next, if normalization is enabled (on by default), the\n"
00207           "matrix is normalized to have a sum of the given scale; otherwise\n"
00208           "the matrix is simply multiplied by the given scale.");
00209 }
00210 
00211 
00212 
00234 KernelFactory::KernelMatrix KernelFactory::create( int index, double wss, StringArgs arglist )
00235 {
00236   KernelMatrix kernel;
00237   const int type = arglist.next(blur_type);
00238   string errors;
00239   
00240   /* Types are grouped into classes based on arguments accepted */
00241   switch (type) {
00242     
00243   case Blur_PGM: {
00244     const string filename  = arglist.next(string(default_kernel_filename));
00245     const double offset    = arglist.next(-0.5);
00246     const double scale     = arglist.next(blur_scale);
00247     const int    normalize = arglist.next(1);
00248     KernelMatrix new_kernel;
00249     
00250     if (!pgm_read(filename, new_kernel)) {
00251       ipc_notify(IPC_ONE,IPC_ERROR, "Can't read file: %s", filename.c_str());
00252       break;
00253     }
00254     
00255     if (new_kernel.ncols()%2 != 1 || new_kernel.nrows()%2 != 1){
00256       ipc_notify(IPC_ONE,IPC_ERROR,
00257                  "The convolution matrix must have an odd number of columns and rows (%d,%d)",
00258                  new_kernel.ncols(),new_kernel.nrows());
00259       break;
00260     }
00261     new_kernel += offset;
00262     
00263     if (!normalize)
00264       new_kernel *= scale;
00265     else {
00266       const double kernelsum = mat::sum(new_kernel);
00267       if (kernelsum==0)
00268         ipc_notify(IPC_ONE,IPC_ERROR,"Can't normalize blurring kernel since it sums to zero");
00269       else new_kernel *= fabs(scale/kernelsum);
00270     }
00271     
00272     kernel = new_kernel;
00273     break;
00274   }
00275   
00276   
00277   case Blur_SquareAverage: case Blur_CircularAverage: case Blur_Gaussian: case Blur_LoG: {
00278     
00279     const double rad   = arglist.next(blur_radius*wss);
00280     const double scale = arglist.next(blur_scale);
00281     
00282     switch (type) {
00283     case Blur_SquareAverage:   kernel = create(RadialFunction::Constant, rad,rad-0.5,errors,false); break;
00284     case Blur_CircularAverage: kernel = create(RadialFunction::Constant, rad,rad-0.5,errors); break;
00285     case Blur_Gaussian: {
00286       const double rscale = arglist.next(4.7*blur_range_multiplier);
00287       kernel = create(RadialFunction::Gaussian, rad, rad*rscale,errors); break;
00288     }
00289     case Blur_LoG: {
00290       const double rscale = arglist.next(3.2*blur_range_multiplier);
00291       kernel = create(RadialFunction::LoG, rad, rad*rscale,errors,true,false); break;
00292     }
00293     }
00294     kernel *= scale;
00295     break;
00296   }
00297   
00298   case Blur_DoG: case Blur_GoD: case Blur_DoGGoD: {
00299     /* Determine sign of kernel; DoGGoD uses 1 for even, -1 for odd */
00300     const double scalesign   = (  type == Blur_DoG    ?  1.0           :
00301                                 ( type == Blur_GoD    ? -1.0            :
00302                                  (type == Blur_DoGGoD ?  1.0-2*(index%2) :
00303                                   1.0)));
00304     
00305     const double rad         = arglist.next((blur_radius)*wss);
00306     
00307     const double srad        = arglist.next((blur_radius_surround_multiplier*rad/wss)*wss);
00308     const double scale       = arglist.next(blur_scale);
00309     const double sscale      = arglist.next(scale);
00310     const double range_scale = arglist.next(4.7*blur_range_multiplier);
00311     const double maxrad      = srad*range_scale;
00312     
00313 #ifdef USE_MTL_MATRIX   
00314     kernel  = create(RadialFunction::Gaussian,  rad, maxrad,errors);
00315     mtl::scale(kernel,scale*scalesign);
00316     mtl::add( mtl::scaled(create(RadialFunction::Gaussian, srad, maxrad,errors), -1*sscale*scalesign), kernel);
00317 #else
00318     kernel = create(RadialFunction::Gaussian, rad,  maxrad,errors) * scale*scalesign  -
00319              create(RadialFunction::Gaussian, srad, maxrad,errors) * sscale*scalesign;
00320 #endif
00321     break;
00322   }
00323 
00324   case Blur_CircularRandom: case Blur_SquareRandom: {
00325     const double rad   = arglist.next(blur_radius*wss);
00326     const double scale = arglist.next(blur_scale);
00327     
00328     switch (type) {
00329     case Blur_SquareRandom:   kernel = create(RadialFunction::Random, rad,rad-0.5,errors,false); break;
00330     case Blur_CircularRandom: kernel = create(RadialFunction::Random, rad,rad-0.5,errors); break;
00331     }
00332     kernel *= scale;
00333     break;
00334   }
00335     
00336   default: ipc_notify(IPC_ONE,IPC_ERROR,"Unknown blur_type %d",type); break;
00337   }
00338 
00339   if (errors!="")
00340     ipc_notify(IPC_ONE,IPC_ERROR,errors.c_str());
00341 
00342   return kernel;
00343 }
00344 

Generated on Mon Jan 20 02:35:44 2003 for RF-LISSOM by doxygen1.3-rc2