contrib/mul/vil3d/algo/vil3d_locally_z_normalise.h
Go to the documentation of this file.
00001 #ifndef vil3d_locally_z_normalise_h_
00002 #define vil3d_locally_z_normalise_h_
00003 //:
00004 //  \file
00005 //  \brief Locally apply z-normalisation to images
00006 //  \author Tim Cootes
00007 
00008 #include <vil/vil_convert.h>
00009 #include <vil3d/vil3d_image_view.h>
00010 #include <vil3d/vil3d_math.h>
00011 #include <vil3d/algo/vil3d_exp_filter.h>
00012 #include <vcl_cassert.h>
00013 
00014 //: Locally apply z-normalisation to images
00015 // The mean and standard deviation over a window around each voxel.
00016 // The voxel_value is modified v_new = (v_old - mean)/max(min_var, stdev)
00017 // For integer types min_var is 1. For floating point min_var is the larger of
00018 // 0.001 of the image wide stdev, or sqrt_eps.
00019 template <class T>
00020 inline void vil3d_locally_z_normalise(const vil3d_image_view<T>& input,
00021                                       double half_width_i,
00022                                       double half_width_j,
00023                                       double half_width_k,
00024                                       vil3d_image_view<T>& output)
00025 {
00026   assert(input.nplanes()==1);
00027 
00028   unsigned ni=input.ni();
00029   unsigned nj=input.nj();
00030   unsigned nk=input.nk();
00031   output.set_size(ni,nj,nk);
00032 
00033   if (ni*nj*nk == 0)
00034     return;
00035 
00036   //: Workspace
00037   vil3d_image_view<float> smth_im, sqr_im, smth_sqr_im;
00038 
00039   // k^half_width = 0.5
00040   // So k=exp(log(0.5)/half_width)
00041   double ki = vcl_exp(vcl_log(0.5)/half_width_i);
00042   double kj = vcl_exp(vcl_log(0.5)/half_width_j);
00043   double kk = vcl_exp(vcl_log(0.5)/half_width_k);
00044 
00045   vil3d_exp_filter(input,smth_im,ki,kj,kk);
00046   vil3d_math_image_product(input,input,sqr_im);
00047   vil3d_exp_filter(input,smth_sqr_im,ki,kj,kk);
00048 
00049   double min_var=1.0;
00050   if (!vcl_numeric_limits<T>::is_integer)
00051   {
00052     double sum=0, sum_sq=0;
00053     vil3d_math_sum(sum, input, 0);
00054     vil3d_math_sum(sum_sq, sqr_im, 0);
00055     double mean = sum/input.size();
00056     min_var = vcl_max( sum_sq/(input.size()) - mean*mean,
00057       static_cast<double>(vcl_sqrt(vcl_numeric_limits<T>::epsilon())) );
00058   }
00059 
00060   vil_convert_round_pixel<double, T> round;
00061 
00062   for (unsigned k=0;k<nk;++k)
00063    for (unsigned j=0;j<nj;++j)
00064     for (unsigned i=0;i<ni;++i)
00065     {
00066       double mean = smth_im(i,j,k);
00067       double var = smth_sqr_im(i,j,k)-mean*mean;
00068       double sd = vcl_sqrt(vcl_max(min_var,var));
00069       double v = (input(i,j,k)-mean)/sd;
00070 
00071       round(v, output(i,j,k));
00072     }
00073 }
00074 
00075 #endif // vil3d_locally_z_normalise_h_