contrib/mul/vil3d/algo/vil3d_anisotropic_filter.h
Go to the documentation of this file.
00001 // This is mul/vil3d/algo/vil3d_anisotropic_filter.h
00002 #ifndef vil3d_anisotropic_filter_h_
00003 #define vil3d_anisotropic_filter_h_
00004 //:
00005 // \file
00006 // \brief Functions to apply anisotropic filters to 3D images.
00007 //
00008 // \author Kevin de Souza and Ian Scott
00009 
00010 #include <vil3d/vil3d_image_view.h>
00011 #include <vgl/vgl_vector_3d.h>
00012 #include <vil/algo/vil_gauss_filter.h>
00013 #include <vil3d/algo/vil3d_convolve_1d.h>
00014 #include <vnl/vnl_math.h>
00015 #include <vil3d/vil3d_switch_axes.h>
00016 #include <vil3d/vil3d_convert.h>
00017 #include <vil3d/vil3d_print.h>
00018 #include <vcl_iostream.h>
00019 
00020 
00021 //========================================================================
00022 //: Function to apply 3 different 1D filters to a 3D image.
00023 // \param src     The source image.
00024 // \retval dest   The destination image (of type <float>).
00025 // \param filter  The filter to apply in each direction.
00026 // \param c       The (absolute) index of the centre tap of each filter.
00027 // \param lo      The (relative) index of the lowest tap of each filter.
00028 // \param hi      The (relative) index of the highest tap of each filter.
00029 // \param cbo     The convolution boundary option to use with each filter.
00030 // \param work1   Workspace image (assumed to be correct size).
00031 // \param work2   Workspace image (assumed to be correct size).
00032 // \note The returned image <float> can be converted to the source type
00033 // by a subsequent call to vil3d_convert_round() or vil3d_convert-cast().
00034 //========================================================================
00035 template <class T>
00036 inline
00037 void vil3d_anisotropic_filter(const vil3d_image_view<T>& src,
00038                               vil3d_image_view<float>& dest,
00039                               const vgl_vector_3d<vcl_vector<double> >& filter,
00040                               const vgl_vector_3d<unsigned>& c,
00041                               const vgl_vector_3d<int>& lo,
00042                               const vgl_vector_3d<int>& hi,
00043                               const vgl_vector_3d<vil_convolve_boundary_option>& cbo,
00044                               vil3d_image_view<float>& work1,
00045                               vil3d_image_view<float>& work2)
00046 {
00047   vil3d_convolve_1d(src,  work1, &(filter.x()[c.x()]),
00048                     lo.x(), hi.x(), float(), cbo.x(), cbo.x());
00049 
00050   vil3d_image_view<float> work2_jki = vil3d_switch_axes_jki(work2);
00051 
00052   vil3d_convolve_1d(vil3d_switch_axes_jki(work1), work2_jki,
00053     &(filter.y()[c.y()]), lo.y(), hi.y(), float(), cbo.y(), cbo.y());
00054 
00055   vil3d_image_view<float> dest_kij = vil3d_switch_axes_kij(dest);
00056 
00057   vil3d_convolve_1d(vil3d_switch_axes_kij(work2), dest_kij,
00058     &(filter.z()[c.z()]), lo.z(), hi.z(), float(), cbo.z(), cbo.z());
00059 
00060 
00061   ////////////////////////////////////////////////////////////////////////
00062   //
00063   // Testing
00064   //
00065 #ifdef PERFORM_TESTING
00066   //
00067   vcl_cout << "Source image:\n";
00068   vil3d_print_all(vcl_cout, src);
00069 
00070   vcl_cout << "\n\nWork1 image:\n";
00071   vil3d_print_all(vcl_cout, work1);
00072   double sum1 = 0;
00073   vil3d_math_sum(sum1, work1, 0);
00074   vcl_cout << "\nSum1= " << sum1 << vcl_endl;
00075 
00076   vcl_cout << "\n\nWork2 image:\n";
00077   vil3d_print_all(vcl_cout, work2);
00078   double sum2 = 0;
00079   vil3d_math_sum(sum2, work2, 0);
00080   vcl_cout << "\nSum2= " << sum2 << vcl_endl;
00081 
00082   vcl_cout << "\n\nDest image:\n";
00083   vil3d_print_all(vcl_cout, dest);
00084   double sumd = 0;
00085   vil3d_math_sum(sumd, dest, 0);
00086   vcl_cout << "\nSumd= " << sumd << vcl_endl;
00087   //
00088 #endif // PERFORM_TESTING
00089   //
00090   ////////////////////////////////////////////////////////////////////////
00091 }
00092 
00093 
00094 //========================================================================
00095 //: Generates 3 Gaussian filters, 1 for each dimension.
00096 // \param sd      The width of the Gaussian (in voxel widths) for each dimension.
00097 // \retval filter The 3 filters.
00098 // \retval c      The (absolute) index of the centre tap of each filter.
00099 // \retval lo     The (relative) index of the lowest tap of each filter.
00100 // \retval hi     The (relative) index of the highest tap of each filter.
00101 //========================================================================
00102 inline
00103 void vil3d_generate_gaussian_filters(const vgl_vector_3d<double>& sd,
00104                                      vgl_vector_3d<vcl_vector<double> >& filter,
00105                                      vgl_vector_3d<unsigned>& c,
00106                                      vgl_vector_3d<int>& lo,
00107                                      vgl_vector_3d<int>& hi)
00108 {
00109   // Size of filters (number of "taps") - filter should be ~ 7*sd wide
00110   vgl_vector_3d<unsigned> nt;
00111   nt.x_ = vnl_math_rnd(7.0*sd.x());
00112   nt.y_ = vnl_math_rnd(7.0*sd.y());
00113   nt.z_ = vnl_math_rnd(7.0*sd.z());
00114 
00115   // Temporary fix - force filters to have odd number of taps.
00116   // Not sure why, but even-numbered filters cause strange errors.
00117   if (nt.x_%2==0) nt.x_++;
00118   if (nt.y_%2==0) nt.y_++;
00119   if (nt.z_%2==0) nt.z_++;
00120 
00121   // Is nt even?
00122   if (nt.x()%2==0 || nt.y()%2==0 || nt.z()%2==0)
00123   {
00124     vcl_cout << "------------------------------------------------------\n"
00125              << "Warning: filter size is even: this may cause problems.\n"
00126              << nt.x() << '\t' << nt.y()<< '\t'  << nt.z() << '\n'
00127              << "------------------------------------------------------\n"
00128              << vcl_endl;
00129   }
00130 
00131 
00132   // Centre (absolute) tap of filter (or just past centre if even length)
00133   c = nt/2;
00134 
00135   // Lowest (relative) tap of filter
00136   lo.x_ = -(int)c.x();
00137   lo.y_ = -(int)c.y();
00138   lo.z_ = -(int)c.z();
00139 
00140   // Highest (relative) tap of filter (depends whether filter length is odd)
00141   hi.x_ = c.x() +1 -(nt.x()%2);
00142   hi.y_ = c.y() +1 -(nt.y()%2);
00143   hi.z_ = c.z() +1 -(nt.z()%2);
00144 
00145   // Create a suitable 1D Gaussian filter for each dimension
00146   filter.x_.resize(nt.x());
00147   filter.y_.resize(nt.y());
00148   filter.z_.resize(nt.z());
00149   vil_gauss_filter_gen_ntap(sd.x(), 0, filter.x_);
00150   vil_gauss_filter_gen_ntap(sd.y(), 0, filter.y_);
00151   vil_gauss_filter_gen_ntap(sd.z(), 0, filter.z_);
00152 }
00153 
00154 
00155 //========================================================================
00156 //: A convenience function to generate and apply an anisotropic Gaussian filter to a 3D image.
00157 // \param src     The source image.
00158 // \retval dest   The destination (filtered) image.
00159 // \param sd      The width of the Gaussian (in voxel widths) for each dimension.
00160 // \param work1   Workspace image (assumed to be correct size).
00161 // \param work2   Workspace image (assumed to be correct size).
00162 // \param work3   Workspace image (assumed to be correct size).
00163 // \note          The filtering is done in floating-point arithmetic,
00164 //                and the destination image is rounded to the same pixel
00165 //                type as the source.
00166 // \sa            vil3d_generate_gaussian_filters()
00167 // \sa            vil3d_anisotropic_filter()
00168 //========================================================================
00169 template <class T>
00170 inline
00171 void vil3d_anisotropic_gaussian_filter(const vil3d_image_view<T>& src,
00172                                        vil3d_image_view<T>& dest,
00173                                        const vgl_vector_3d<double>& sd,
00174                                        vil3d_image_view<float>& work1,
00175                                        vil3d_image_view<float>& work2,
00176                                        vil3d_image_view<float>& work3)
00177 {
00178   // Generate Gaussian filters suitable for each dimension
00179   vgl_vector_3d<vcl_vector<double> > filter;
00180   vgl_vector_3d<unsigned> c;
00181   vgl_vector_3d<int> lo;
00182   vgl_vector_3d<int> hi;
00183   vil3d_generate_gaussian_filters(sd, filter, c, lo, hi);
00184 
00185   // Specify the convolution boundary option for each dimension
00186   vgl_vector_3d<vil_convolve_boundary_option> cbo(vil_convolve_trim,
00187                                                   vil_convolve_trim,
00188                                                   vil_convolve_trim);
00189 
00190   // Apply the filters
00191   vil3d_anisotropic_filter(src, work3, filter, c, lo, hi, cbo, work1, work2);
00192 
00193 
00194   // Convert the results to destination type
00195   vil3d_convert_round(work3, dest);
00196 
00197 
00198   ////////////////////////////////////////////////////////////////////////
00199   //
00200   // Testing
00201   //
00202 #ifdef PERFORM_TESTING
00203   //
00204   vcl_cout << "Source image:\n";
00205   vil3d_print_all(vcl_cout, src);
00206 
00207   vcl_cout << "\n\nWork3 image:\n";
00208   vil3d_print_all(vcl_cout, work3);
00209   double sum3 = 0;
00210   vil3d_math_sum(sum3, work3, 0);
00211   vcl_cout << "\nSum3= " << sum3 << vcl_endl;
00212 
00213   vcl_cout << "\n\nDest image:\n";
00214   vil3d_print_all(vcl_cout, dest);
00215   double sumd = 0;
00216   vil3d_math_sum(sumd, dest, 0);
00217   vcl_cout << "\nSumd= " << sumd << vcl_endl;
00218   //
00219 #endif // PERFORM_TESTING
00220   //
00221   //////////////////////////////////////////////////////////////////////////
00222 }
00223 
00224 
00225 #endif // vil3d_anisotropic_filter_h_