contrib/mul/vil3d/algo/vil3d_max_product_filter.h
Go to the documentation of this file.
00001 #ifndef vil3d_max_product_filter_h_
00002 #define vil3d_max_product_filter_h_
00003 //:
00004 //  \file
00005 //  \brief Apply non-linear filter to a 3D image in raster order.
00006 //  \author Tim Cootes
00007 
00008 #include <vil3d/algo/vil3d_structuring_element.h>
00009 #include <vil3d/vil3d_image_view.h>
00010 #include <vcl_cassert.h>
00011 
00012 //: Return max(im[0],max_i (f[i]*im[offset[i]]))
00013 //  Thus compare current voxel with weighted versions of n offset,
00014 //  voxels, returning the largest value.
00015 //  Assumes bound checking has already been done
00016 template <class T>
00017 inline T vil3d_max_product_filter(const T* im,
00018                                   const vcl_ptrdiff_t* offset,
00019                                   const double* f, unsigned n)
00020 {
00021   T max_v = im[0];
00022   for (unsigned i=0;i<n;++i)
00023   {
00024     T v = T(f[i]*im[offset[i]]);
00025     if (v>max_v) max_v=v;
00026   }
00027   return max_v;
00028 }
00029 
00030 //: Compare voxel (i0,j0,k0) with weighted versions of offset voxels.
00031 // Return max(image(i0,i1,i2),max_i (f[i]*image(i0+p_i[i],j0+p_j[i],k0+p_k[i],plane)
00032 //  Performs bound checks to ensure voxels are valid
00033 template <class T>
00034 inline T vil3d_max_product_filter(const vil3d_image_view<T>& image,
00035                                   const vil3d_structuring_element& se,
00036                                   const vcl_vector<double>& f,
00037                                   int i0, int j0, int k0)
00038 {
00039   unsigned n = se.p_i().size();
00040   T max_v = image(i0,j0,k0);
00041 
00042   for (unsigned int a=0;a<n;++a)
00043   {
00044     // Note that -ives become huge positives and are thus ignored by the if
00045     unsigned int i = i0+se.p_i()[a];
00046     unsigned int j = j0+se.p_j()[a];
00047     unsigned int k = k0+se.p_k()[a];
00048     if (i<image.ni() && j<image.nj() && k<image.nk())
00049     {
00050       T v = T(f[a]*image(i,j,k));
00051       if (v>max_v) max_v=v;
00052     }
00053   }
00054   return max_v;
00055 }
00056 
00057 //: Performs raster scan through image, comparing each voxel with neighbours
00058 // Runs through every voxel in raster order.  Each voxel is compared
00059 // with weighted versions of offset voxels, and is replaced with the
00060 // maximum value.
00061 //
00062 // Replace each voxel with
00063 // max(im(i,j,k),max_a (f[a]*im(i+p_i[a],j+p_j[a],k+p_k[a],plane))
00064 //
00065 // If a suitable combination of se and f is chosen,
00066 // this performs half an 'exponential distance transform'.
00067 // For an example of use, see vil3d_exp_distance_transform.
00068 // \relatesalso vil3d_image_view
00069 // \relatesalso vil3d_structuring_element
00070 template<class T>
00071 void vil3d_max_product_filter(vil3d_image_view<T>& image,
00072                               const vil3d_structuring_element& se,
00073                               const vcl_vector<double>& f)
00074 {
00075   assert(image.nplanes()==1);  // Change this later
00076   unsigned ni = image.ni();
00077   unsigned nj = image.nj();
00078   unsigned nk = image.nk();
00079 
00080   vcl_ptrdiff_t istep = image.istep();
00081   vcl_ptrdiff_t jstep = image.jstep();
00082   vcl_ptrdiff_t kstep = image.kstep();
00083 
00084   vcl_vector<vcl_ptrdiff_t> offset;
00085   vil3d_compute_offsets(offset,se,istep,jstep,kstep);
00086   const vcl_ptrdiff_t *o_data = &offset[0];
00087   const double *f_data = &f[0];
00088   const unsigned n = f.size();
00089   assert(n==offset.size());
00090 
00091   // Define box in which all elements will be valid
00092   int ilo = -se.min_i();
00093   int ihi = ni-1-se.max_i();
00094   int jlo = -se.min_j();
00095   int jhi = nj-1-se.max_j();
00096   int klo = -se.min_k();
00097   int khi = nk-1-se.max_k();
00098 
00099   // Process first z slices using bound checking
00100   for (unsigned int k=0;int(k)<klo;++k)
00101   {
00102     for (unsigned int j=0;j<nj;++j)
00103       for (unsigned int i=0;i<ni;++i)
00104         image(i,j,k)=vil3d_max_product_filter(image,se,f,i,j,k);
00105   }
00106   // Process middle z slices (still require i, j checks)
00107   for (int k=klo;k<=khi;++k)
00108   {
00109     // First j require bound checks
00110     for (unsigned int j=0;int(j)<jlo;++j)
00111       for (unsigned int i=0;i<ni;++i)
00112         image(i,j,k)=vil3d_max_product_filter(image,se,f,i,j,k);
00113 
00114     for (int j=jlo;j<=jhi;++j)
00115     {
00116        // first i require bound checks
00117        for (unsigned int i=0;int(i)<ilo;++i)
00118          image(i,j,k)=vil3d_max_product_filter(image,se,f,i,j,k);
00119 
00120        T* im = &image(ilo,j,k);
00121 
00122        // Middle values of i require no bound checks
00123        for (int i=ilo;i<=ihi;++i,im+=istep)
00124          *im=vil3d_max_product_filter(im,o_data,f_data,n);
00125 
00126        // Last i require bound checks
00127        for (unsigned int i=ihi+1;i<ni;++i)
00128          image(i,j,k)=vil3d_max_product_filter(image,se,f,i,j,k);
00129     }
00130     // Last j require bound checks
00131     for (unsigned int j=jhi+1;j<nj;++j)
00132       for (unsigned int i=0;i<ni;++i)
00133         image(i,j,k)=vil3d_max_product_filter(image,se,f,i,j,k);
00134   }
00135   // process final z slices using bound checking
00136   for (unsigned int k=khi+1;k<nk;++k)
00137   {
00138     for (unsigned int j=0;j<nj;++j)
00139       for (unsigned int i=0;i<ni;++i)
00140         image(i,j,k)=vil3d_max_product_filter(image,se,f,i,j,k);
00141   }
00142 }
00143 
00144 
00145 #endif // vil3d_max_product_filter_h_