contrib/brl/bseg/sdet/sdet_denoise_mrf.cxx
Go to the documentation of this file.
00001 // This is brl/bseg/sdet/sdet_denoise_mrf.cxx
00002 #include "sdet_denoise_mrf.h"
00003 #include <vcl_cstdlib.h>
00004 #include <vnl/vnl_math.h>
00005 #include <vil/vil_new.h>
00006 #include <vnl/vnl_numeric_traits.h>
00007 #include <vnl/algo/vnl_sparse_lu.h>
00008 #include <vul/vul_timer.h>
00009 #include <brip/brip_vil_float_ops.h>
00010 #include <brip/brip_line_generator.h>
00011 
00012 //---------------------------------------------------------------
00013 // Constructors
00014 //----------------------------------------------------------------
00015 
00016 // constructor from a parameter block (the only way)
00017 sdet_denoise_mrf::sdet_denoise_mrf(sdet_denoise_mrf_params& dmp)
00018   : sdet_denoise_mrf_params(dmp), output_valid_(false), in_resc_(0),
00019     var_resc_(0), out_resc_(0)
00020 {
00021   sigma_sq_inv_ = radius_/1.978; //so that exp(radius^2/sigma_^2) = 0.02
00022   sigma_sq_inv_ *= sigma_sq_inv_;
00023   sigma_sq_inv_ = 1.0/sigma_sq_inv_;
00024 }
00025 
00026 // Default Destructor
00027 sdet_denoise_mrf::~sdet_denoise_mrf()
00028 {
00029 }
00030 
00031 double sdet_denoise_mrf::weight(unsigned i0, unsigned j0,
00032                                 unsigned i1, unsigned j1,
00033                                 vil_image_view<float> const& inv,
00034                                 vil_image_view<float> const& varv)
00035 {
00036   int ni = inv.ni(), nj = inv.nj();
00037   //first consider a max radius
00038   //weight due to inter-pixel distance
00039   double dsq = (i1-i0)*(i1-i0) + (j1-j0)*(j1-j0);
00040   double d = vcl_sqrt(dsq);
00041   if (d>(vnl_math::sqrt2*radius_)) return 0.0;
00042   //compute the minimum variance along the path between pix0 and pix1
00043   bool init = true;
00044   float xs = static_cast<float>(i0), ys = static_cast<float>(j0);
00045   float xe = static_cast<float>(i1), ye = static_cast<float>(j1);
00046   float x=xs, y=ys;
00047   double min_var = vnl_numeric_traits<double>::maxval;
00048   //generate the path between two pixels
00049   while (brip_line_generator::generate(init, xs, ys, xe, ye, x, y))
00050   {
00051     unsigned i = static_cast<unsigned>(x), j = static_cast<unsigned>(y);
00052     double v = varv(i, j);
00053     if (v<min_var)
00054       min_var = v;
00055   }
00056   //compute the average depth difference a window of size radius_
00057   // compute the average depths
00058   double sum0=0.0, sum1=0.0;
00059   double n0 = 0.0, n1 = 0.0;
00060   int r = static_cast<int>(radius_);
00061   for (int kj = -r; kj<=r; ++kj) {
00062     int j0k = j0+kj, j1k = j1+kj;
00063     if (j0k<0||j0k>=nj||j1k<0||j1k>=nj) continue;
00064     for (int ki = -r; ki<=r; ++ki) {
00065       int i0k = i0+ki, i1k = i1+ki;
00066       if (i0k<0||i0k>=ni||i1k<0||i1k>=ni) continue;
00067       sum0 += inv(i0k, j0k);
00068       sum1 += inv(i1k, j1k);
00069       n0+=1.0;
00070       n1+=1.0;
00071     }
00072   }
00073   double v_avg0=0.0, v_avg1=0.0;
00074   if (n0>0.0)
00075     v_avg0 = sum0/n0;
00076   if (n1>0.0)
00077     v_avg1 = sum1/n1;
00078   //the difference between depth values averaged over the neighbrd
00079   double Delta = (v_avg1-v_avg0)*(v_avg1-v_avg0);
00080   double w = vcl_exp(-dsq/sigma_sq_inv_ +
00081                      kappa_*min_var -
00082                      beta_*Delta);
00083   return w;
00084 }
00085 
00086 void sdet_denoise_mrf::compute_incidence_matrix()
00087 {
00088   int ni = in_resc_->ni(), nj = in_resc_->nj();
00089   int npix = ni*nj;
00090   W_mat_.resize(npix, npix);
00091   D_mat_.set_size(npix, npix);
00092   D_inv_sqrt_.set_size(npix, npix);
00093   vil_image_view<float> inv = brip_vil_float_ops::convert_to_float(in_resc_);
00094   vil_image_view<float> varv = brip_vil_float_ops::convert_to_float(var_resc_);
00095   int r = static_cast<int>(radius_);
00096   for (int j = 0; j<nj; ++j) {
00097     for (int i = 0; i<ni; ++i) {
00098       double D = 0.0;
00099       unsigned indx = i + ni*j;
00100       // index over the neighborhood
00101       for ( int kj = -r; kj<=r; ++kj) {
00102         int joff = j+kj;
00103         if (joff<0||joff>=nj)
00104           continue;
00105         for ( int ki = -r; ki<=r; ++ki) {
00106           int ioff = i+ki;
00107           if (ioff<0||ioff>=ni)
00108             continue;
00109           int indx_nbr = (ioff) + ni*(joff);
00110           if (indx_nbr<0||indx_nbr>=npix)
00111             continue;
00112           if ((unsigned int)indx_nbr!=indx) {
00113             double w = weight(i, j, i+ki, j+kj, inv, varv);
00114             if (w>0.0) {
00115               W_mat_.put(indx, indx_nbr, w);
00116               D += w;
00117             }
00118           }
00119           else {
00120             W_mat_.put(indx, indx_nbr, 1.0);
00121             D += 1.0;
00122           }
00123         }
00124       }
00125       D_mat_.put(indx,indx, D) ;
00126       D_inv_sqrt_.put(indx,indx,1.0/vcl_sqrt(D));
00127     }
00128   }
00129 }
00130 
00131 vil_image_resource_sptr sdet_denoise_mrf::Dimgr()
00132 {
00133   unsigned nr = D_mat_.rows();
00134   if (!nr||!in_resc_) return 0;
00135   unsigned ni = in_resc_->ni(), nj = in_resc_->nj();
00136   if (nr!=ni*nj) return 0;
00137   vil_image_view<float> out(ni, nj);
00138   for (unsigned j = 0; j<nj; ++j)
00139     for (unsigned i = 0; i<ni; ++i) {
00140       unsigned indx = i + ni*j;
00141       out(i,j)=static_cast<float>(D_mat_(indx,indx));
00142     }
00143   return vil_new_image_resource_of_view(out);
00144 }
00145 
00146 void sdet_denoise_mrf::compute_laplacian_matrix()
00147 {
00148   L_mat_ = D_mat_-W_mat_;
00149   L_mat_ = D_inv_sqrt_*L_mat_*D_inv_sqrt_;
00150 }
00151 
00152 void sdet_denoise_mrf::compute_F()
00153 {
00154   vil_image_view<float> in_view = in_resc_->get_view();
00155   unsigned ni = in_view.ni(), nj = in_view.nj();
00156   // form the LU "b" matrix
00157   vnl_vector<double> b(W_mat_.rows());
00158   for (unsigned j = 0; j<nj; ++j)
00159     for (unsigned i = 0; i<ni; ++i) {
00160       unsigned indx = i + j*ni;
00161       double dinsq = D_inv_sqrt_(indx, indx);
00162       b[indx]=dinsq*in_view(i,j);
00163     }
00164   //Form the LU input matrix
00165   // D^-1
00166   W_mat_ = D_inv_sqrt_*D_inv_sqrt_;
00167   // (D^-1 + 2*L)
00168   W_mat_ += 2.0*L_mat_;
00169   vnl_sparse_lu lu(W_mat_, vnl_sparse_lu::estimate_condition);
00170   vnl_vector<double> R = lu.solve(b);
00171   F_.set_size(W_mat_.rows());
00172   for (unsigned r = 0; r<W_mat_.rows(); ++r)
00173     F_[r] = D_inv_sqrt_(r,r)*R[r];
00174 }
00175 
00176 bool sdet_denoise_mrf::denoise()
00177 {
00178   if (!in_resc_) return false;
00179   if (!var_resc_) return false;
00180   unsigned area = in_resc_->ni()*in_resc_->nj();
00181   vcl_cout << " constructing mrf on " << area << " x " << area
00182            << " incidence matrix\n";
00183   vul_timer t;
00184   this->compute_incidence_matrix();
00185   this->compute_laplacian_matrix();
00186   vcl_cout << "formed incidence and auxiliary matrices in "
00187            << t.real()/1000.0 << " seconds\n";
00188   t.mark();
00189   this->compute_F();
00190   vcl_cout << "solved LU decomposition and back substitution in "
00191            << t.real()/1000.0 << " seconds\n";
00192   int ni = in_resc_->ni(), nj = in_resc_->nj();
00193   vil_image_view<float> out_view(ni, nj);
00194   out_view.fill(0.0f);
00195   for (int j = 0; j<nj; ++j)
00196     for (int i = 0; i<ni; ++i) {
00197       unsigned indx = i + ni*j;
00198       out_view(i,j) = static_cast<float>(F_[indx]);
00199     }
00200   out_resc_ = vil_new_image_resource_of_view(out_view);
00201   output_valid_ = true;
00202   return true;
00203 }
00204