contrib/mul/vil3d/algo/vil3d_suppress_non_max_edges.txx
Go to the documentation of this file.
00001 // This is mul/vil3d/algo/vil3d_suppress_non_max_edges.txx
00002 #ifndef vil3d_suppress_non_max_edges_txx_
00003 #define vil3d_suppress_non_max_edges_txx_
00004 //:
00005 // \file
00006 // \brief Given gradient image, compute magnitude and zero any non-maximal values
00007 // \author Tim Cootes
00008 
00009 #include "vil3d_suppress_non_max_edges.h"
00010 #include <vil3d/algo/vil3d_fill_border.h>
00011 #include <vil3d/vil3d_trilin_interp.h>
00012 #include <vcl_cmath.h>
00013 #include <vcl_cassert.h>
00014 
00015 
00016 //: Given gradient images, computes magnitude image containing maximal edges
00017 //  Points with magnitude above a threshold are tested against gradient
00018 //  along normal to the edge and retained only if they are higher than
00019 //  their neighbours.
00020 //
00021 //  Gradient images are assumed to be in units of (intensity change) per world unit.
00022 //  (ie the output of vil3d_world_gradients)
00023 //
00024 //  Note: Currently assumes single plane only.
00025 //  2 pixel border around output set to zero.
00026 //  If two neighbouring edges have exactly the same strength, it retains
00027 //  both (ie an edge is eliminated if it is strictly lower than a neighbour,
00028 //  but not if it is the same as two neighbours).
00029 //
00030 // \relatesalso vil3d_image_view
00031 template<class srcT>
00032 void vil3d_suppress_non_max_edges(const vil3d_image_view<srcT>& world_grad,
00033                                   const vil3d_image_view<srcT>& grad_mag,
00034                                   double voxel_width_i,
00035                                   double voxel_width_j,
00036                                   double voxel_width_k,
00037                                   srcT grad_mag_threshold,
00038                                   vil3d_image_view<srcT>& max_grad_mag)
00039 {
00040   assert(world_grad.nplanes()==3);
00041   assert(grad_mag.nplanes()==1);
00042   unsigned ni = world_grad.ni(), nj = world_grad.nj(), nk = world_grad.nk();
00043   assert(ni>2 && nj>2 && nk>2);
00044   assert(grad_mag.ni()==ni && grad_mag.nj()==nj && grad_mag.nk()==nk);
00045   max_grad_mag.set_size(ni,nj,nk,1);
00046 
00047   // Fill 2 voxel border with zero
00048   vil3d_fill_border(max_grad_mag,2,2,2,srcT(0));
00049 
00050   const vcl_ptrdiff_t g_istep = world_grad.istep(), g_jstep = world_grad.jstep(),
00051                       g_kstep = world_grad.kstep();
00052   const vcl_ptrdiff_t gm_istep = grad_mag.istep(), gm_jstep = grad_mag.jstep(),
00053                       gm_kstep = grad_mag.kstep();
00054   const vcl_ptrdiff_t d_istep = max_grad_mag.istep(), d_jstep = max_grad_mag.jstep(),
00055                       d_kstep = max_grad_mag.kstep();
00056   const vcl_ptrdiff_t pstep = world_grad.planestep();
00057   const vcl_ptrdiff_t pstep2 = 2*pstep;
00058 
00059   unsigned ihi=ni-3;
00060   unsigned jhi=nj-3;
00061   unsigned khi=nk-3;
00062 
00063   double step_size = vcl_sqrt((voxel_width_i*voxel_width_i +
00064                                voxel_width_j*voxel_width_j +
00065                                voxel_width_k*voxel_width_k   )/3.0);
00066 
00067   const srcT * gm_data = &grad_mag(0,0,0);
00068   const srcT * wg_slice = &world_grad(2,2,2);
00069   const srcT * gm_slice = &grad_mag(2,2,2);
00070   srcT * d_slice = &max_grad_mag(2,2,2);
00071 
00072   for (unsigned k=2; k<=khi; ++k, wg_slice+=g_kstep, gm_slice+=gm_kstep,
00073                                   d_slice+=d_kstep)
00074   {
00075     const srcT* wg_row = wg_slice;
00076     const srcT* gm_row = gm_slice;
00077     srcT *d_row = d_slice;
00078 
00079     for (unsigned j=2; j<=jhi; ++j, wg_row+=g_jstep, gm_row+=gm_jstep,
00080                                     d_row+=d_jstep)
00081     {
00082       const srcT* vg = wg_row;
00083       const srcT* vgm = gm_row;
00084       srcT *v_new_gm = d_row;
00085       for (unsigned i=2; i<=ihi; ++i, vg+=g_istep, vgm+=gm_istep,
00086                                       v_new_gm+=d_istep)
00087       {
00088         srcT gmag=*vgm;
00089         if (gmag<grad_mag_threshold)
00090         {
00091           *v_new_gm = 0; continue;
00092         }
00093         // Unit vector in world co-ords would be pgi/(gmag)
00094         // Multiply by step_size
00095         // Divide by voxel width to get back to pixel co-ords
00096         double dx=step_size*vg[0]/(gmag*voxel_width_i);
00097         double dy=step_size*vg[pstep]/(gmag*voxel_width_j);
00098         double dz=step_size*vg[pstep2]/(gmag*voxel_width_k);
00099 
00100         // Check that step isn't larger than 1 pixel in any direction
00101         double a= vcl_fabs(dx); if (a>=1.0) { dx/=a; dy/=a; dz/=a; }
00102         a= vcl_fabs(dy); if (a>=1.0) { dx/=a; dy/=a; dz/=a; }
00103         a= vcl_fabs(dz); if (a>=1.0) { dx/=a; dy/=a; dz/=a; }
00104 
00105         // Evaluate gradient at point (i+dx,j+dy,k+dz)
00106         double gm1=vil3d_trilin_interp_raw(i+dx,j+dy,k+dz,gm_data,gm_istep,gm_jstep,gm_kstep);
00107         if (gm1>gmag) { *v_new_gm=0; continue; }
00108         double gm2=vil3d_trilin_interp_raw(i-dx,j-dy,k-dz,gm_data,gm_istep,gm_jstep,gm_kstep);
00109         if (gm2>gmag) *v_new_gm=0;
00110         else          *v_new_gm=gmag;
00111       }
00112     }
00113   }
00114 }
00115 
00116 #undef VIL3D_SUPPRESS_NON_MAX_EDGES_INSTANTIATE
00117 #define VIL3D_SUPPRESS_NON_MAX_EDGES_INSTANTIATE(srcT) \
00118 template void vil3d_suppress_non_max_edges(const vil3d_image_view<srcT >& world_grad,\
00119                                            const vil3d_image_view<srcT >& grad_mag,\
00120                                            double voxel_width_i,\
00121                                            double voxel_width_j,\
00122                                            double voxel_width_k,\
00123                                            srcT grad_mag_threshold,\
00124                                            vil3d_image_view<srcT >& max_grad_mag)
00125 
00126 #endif // vil3d_suppress_non_max_edges_txx_