contrib/brl/bseg/brip/brip_filter_bank.cxx
Go to the documentation of this file.
00001 #include "brip_filter_bank.h"
00002 //
00003 #include <brip/brip_vil_float_ops.h>
00004 #include <brip/brip_vil_ops.h>
00005 #include <vil/vil_resample_bicub.h>
00006 #include <vil/vil_save.h>
00007 #include <vcl_cmath.h>
00008 #include <vcl_cassert.h>
00009 #include <vcl_sstream.h>
00010 #include <vul/vul_file.h>
00011 
00012 // cutoff ratio determines Gaussian values that are assumed negligible
00013 static int gauss_radius(float sigma, float cutoff_ratio)
00014 {
00015   double sigma_sq_inv = 1/(sigma*sigma);
00016   return static_cast<int>(vcl_sqrt((-2.0*vcl_log(cutoff_ratio))/sigma_sq_inv)+0.5);
00017 }
00018 
00019 brip_filter_bank::brip_filter_bank(unsigned n_levels,
00020                                    double scale_range, float lambda0,
00021                                    float lambda1, float theta_interval,
00022                                    float cutoff_ratio)
00023 : ni_(0), nj_(0),n_levels_(n_levels), lambda0_(lambda0), lambda1_(lambda1),
00024   theta_interval_(theta_interval), cutoff_ratio_(cutoff_ratio)
00025 {
00026   assert(n_levels_);
00027   if (n_levels == 1) {// only one level in the pyramid
00028     scale_ratio_ = 1.0;//actually meaningless
00029   }
00030   else {
00031     double ninv = 1.0/(n_levels-1);
00032     scale_ratio_ = vcl_pow(scale_range, ninv);
00033   }
00034 }
00035 
00036 brip_filter_bank::brip_filter_bank(unsigned n_levels,
00037                                    double scale_range, float lambda0,
00038                                    float lambda1, float theta_interval,
00039                                    float cutoff_ratio,
00040                                    vil_image_view<float> const& image):
00041   n_levels_(n_levels), lambda0_(lambda0), lambda1_(lambda1),
00042   theta_interval_(theta_interval), cutoff_ratio_(cutoff_ratio)
00043 {
00044   assert(n_levels_);
00045   ni_ = image.ni();   nj_ = image.nj();
00046   scale_pyramid_ = vil_pyramid_image_view<float>(image);
00047   if (n_levels == 1) { // only one level in the pyramid
00048     scale_ratio_ = 1.0;//actually meaningless
00049   }
00050   else {
00051     double ninv = 1.0/(n_levels-1);
00052     scale_ratio_ = vcl_pow(scale_range, ninv);
00053     this->construct_scale_pyramid();
00054   }
00055   this->compute_filter_responses();
00056 }
00057 
00058 void brip_filter_bank::set_image(vil_image_view<float> const& image)
00059 {
00060   ni_ = image.ni();   nj_ = image.nj();
00061   scale_pyramid_ = vil_pyramid_image_view<float>(image);
00062   if (scale_ratio_ != 1.0) this->construct_scale_pyramid();
00063   this->compute_filter_responses();
00064 }
00065 
00066 void brip_filter_bank::construct_scale_pyramid()
00067 {
00068   //smooth with Gaussian sigma given by the scale ratio and downsample
00069   unsigned radius =
00070     static_cast<unsigned>(gauss_radius(static_cast<float>(scale_ratio_), cutoff_ratio_));
00071   unsigned int n_samples = 2*radius +1;
00072   for (unsigned level = 1; level<n_levels_; ++level) {
00073     vil_image_view<float> smooth;
00074     double scale_m1;
00075     //image from previous level
00076     vil_image_view<float> level_m1_view = scale_pyramid_.get_view(level-1,
00077                                                                   scale_m1);
00078     //smooth image
00079     brip_gauss_filter(level_m1_view, smooth, scale_ratio_, n_samples,
00080                       vil_convolve_no_extend);
00081     // downsample image
00082     double dni = level_m1_view.ni(), dnj = level_m1_view.nj();
00083     // image dimensions for next level
00084     dni /= scale_ratio_;     dnj /= scale_ratio_;
00085     double scale = scale_m1 / scale_ratio_;
00086     unsigned sni = static_cast<unsigned>(dni+0.5);
00087     unsigned snj = static_cast<unsigned>(dnj+0.5);
00088     vil_image_view<float>* lview = new vil_image_view<float>();
00089     vil_image_view_base_sptr lview_ptr = lview;
00090     vil_resample_bicub(smooth, *lview, sni, snj);
00091     scale_pyramid_.add_view(lview_ptr, scale);
00092   }
00093 }
00094 
00095 void brip_filter_bank::compute_filter_responses()
00096 {
00097   filter_responses_.clear();
00098   filter_responses_.resize(n_levels_);
00099   vcl_cout << '(' << lambda0_ << ' ' << lambda1_ << ")\n";
00100   for (unsigned level = 0; level<n_levels_; ++level) {
00101     vil_image_view<float>& level_view = scale_pyramid_(level);
00102 
00103     vil_image_view<float> resp =
00104       brip_vil_float_ops::fast_extrema_rotational(level_view,
00105                                                   lambda0_,
00106                                                   lambda1_,
00107                                                   theta_interval_,
00108                                                   false,/*bright*/
00109                                                   false,/*mag*/
00110                                                   true,/*signed*/
00111                                                   true,/*scale invariant*/
00112                                                   false,/*non_max_suppress*/
00113                                                   cutoff_ratio_);
00114     //upsample the response to original size
00115     vil_image_view<float> upsamp_response;
00116     vil_resample_bicub(resp, upsamp_response, ni_, nj_);
00117     filter_responses_[level] = upsamp_response;
00118     vcl_cout << 1.0/scale_pyramid_.scale(level) << ' ' << vcl_flush;
00119   }
00120   vcl_cout << '\n' << vcl_flush;
00121 }
00122 
00123 unsigned brip_filter_bank::invalid_border() const
00124 {
00125   // the radius due to Gauss smoothing
00126   double g_rad = gauss_radius(static_cast<float>(scale_ratio_), cutoff_ratio_);
00127   // the radius due to the anisotropic filter
00128   double f_rad = gauss_radius(lambda0_, cutoff_ratio_);
00129   double r = 0.42*vcl_sqrt(g_rad*g_rad + f_rad*f_rad);//fudge factor
00130   double scale_int = vcl_pow(scale_ratio_, double(n_levels_-1));
00131   r *= scale_int;
00132   return static_cast<unsigned>(r+0.5);
00133 }
00134 
00135 bool brip_filter_bank::save_filter_responses(vcl_string const& dir) const
00136 {
00137   if (!vul_file::is_directory(dir)) {
00138     vcl_cout << "filepath is not a directory in brip_filter_bank::save_filter_responses(.)\n";
00139     return false;
00140   }
00141   for (unsigned level = 0; level<n_levels_; ++level) {
00142     vcl_stringstream str;
00143     str << "/filter_response_" << level << ".tiff" << vcl_ends;
00144     vcl_string path = dir + str.str();
00145     vil_save(filter_responses_[level], path.c_str());
00146   }
00147   return true;
00148 }
00149 
00150 vcl_ostream&  operator<<(vcl_ostream& s, brip_filter_bank const& r)
00151 {
00152   s << "size:(" << r.ni() << ' ' << r.nj() << ") n_levels:" << r.n_levels()
00153     << " scale ratio:" << r.scale_ratio() << '\n'
00154     << "lambda0:" << r.lambda0() << " lambda1:" << r.lambda1()
00155     << " theta_interval:" << r.theta_interval() << '\n';
00156   return s;
00157 }