contrib/mul/vimt3d/vimt3d_resample_trilinear.h
Go to the documentation of this file.
00001 // This is mul/vimt3d/vimt3d_resample_trilinear.h
00002 #ifndef vimt3d_resample_trilinear_h_
00003 #define vimt3d_resample_trilinear_h_
00004 //:
00005 // \file
00006 // \brief Resample a 3D image by a different factor in each dimension
00007 // \author Kevin de Souza
00008 
00009 #include <vgl/vgl_point_3d.h>
00010 #include <vgl/vgl_vector_3d.h>
00011 #include <vil3d/vil3d_image_view.h>
00012 #include <vil3d/algo/vil3d_gauss_reduce.h>
00013 #include <vil3d/vil3d_resample_trilinear.h>
00014 #include <vimt3d/vimt3d_image_3d_of.h>
00015 
00016 //: Resample a 3D image by a factor of 2 in each dimension.
00017 // \p dst_image has size 2*src.image().n?()-1 in each direction.
00018 // Transform is modified by an appropriate scaling of 0.5
00019 // Interpolated values are truncated when the type T is smaller than double.
00020 // \sa vil3d_resample_trilinear_scale_2()
00021 template <class T>
00022 void vimt3d_resample_trilinear_scale_2(
00023   const vimt3d_image_3d_of<T>& src,
00024   vimt3d_image_3d_of<T>& dst)
00025 {
00026   vil3d_resample_trilinear_scale_2(src.image(), dst.image());
00027 
00028   vimt3d_transform_3d scaling;
00029   scaling.set_zoom_only(2.0, 2.0, 2.0, 0.0, 0.0, 0.0);
00030   dst.set_world2im(scaling * src.world2im());
00031 }
00032 
00033 
00034 //: Sample grid of points in one image and place in another, using trilinear interpolation.
00035 //  dest_image(i,j,k,p) is sampled from the src_image at p+i.u+j.v+k.w,
00036 //  where i=[0..n1-1], j=[0..n2-1], k=[0..n3-1] in world co-ordinates.
00037 //
00038 //  dest_image resized to (n1,n2,n3,src_image.nplanes())
00039 //
00040 //  dest_image.world2im() set up so that the world co-ordinates in src and dest match
00041 //
00042 //  Points outside image return zero or \a outval
00043 template <class sType, class dType>
00044 inline void vimt3d_resample_trilinear(
00045   const vimt3d_image_3d_of<sType>& src_image,
00046   vimt3d_image_3d_of<dType>& dest_image,
00047   const vgl_point_3d<double>& p,
00048   const vgl_vector_3d<double>& u,
00049   const vgl_vector_3d<double>& v,
00050   const vgl_vector_3d<double>& w,
00051   int n1, int n2, int n3,
00052   dType outval=0, double edge_tol=0)
00053 {
00054   const vimt3d_transform_3d& s_w2i = src_image.world2im();
00055   vgl_point_3d<double> im_p = s_w2i(p);
00056   vgl_vector_3d<double> im_u = s_w2i.delta(p, u);
00057   vgl_vector_3d<double> im_v = s_w2i.delta(p, v);
00058   vgl_vector_3d<double> im_w = s_w2i.delta(p, w);
00059 
00060   vil3d_resample_trilinear(src_image.image(),dest_image.image(),
00061                            im_p.x(), im_p.y(), im_p.z(),
00062                            im_u.x(), im_u.y(), im_u.z(),
00063                            im_v.x(), im_v.y(), im_v.z(),
00064                            im_w.x(), im_w.y(), im_w.z(),
00065                            n1, n2, n3,
00066                            outval, edge_tol);
00067 
00068   // Point (i,j,k) in dest corresponds to p+i.u+j.v+k.w,
00069   // an affine transformation for image to world
00070   vimt3d_transform_3d d_i2w;
00071   d_i2w.set_affine(p,u,v,w);
00072   d_i2w.simplify();
00073   dest_image.set_world2im(d_i2w.inverse());
00074 
00075 }
00076 
00077 
00078 //: Sample grid of points in one image and place in another, using trilinear interpolation.
00079 //  dest_image(i,j,k,p) is sampled from the src_image at
00080 //  p+i.u+j.v+k.w, where i=[0..nk-1], j=[0..nj-1], k=[0..nk-1] in world co-ordinates.
00081 //
00082 //  dest_image resized to (ni,nj,nk,src_image.nplanes())
00083 //
00084 //  dest_image.world2im() set up so that the world co-ordinates in src and dest match
00085 //
00086 //  Points outside image return the value of the nearest valid pixel.
00087 // \relatesalso vimt3d_image_3d_of
00088 template <class sType, class dType>
00089 inline void vimt3d_resample_trilin_edge_extend(
00090   const vimt3d_image_3d_of<sType>& src_image,
00091   vimt3d_image_3d_of<dType>& dest_image,
00092   const vgl_point_3d<double>& p,
00093   const vgl_vector_3d<double>& u,
00094   const vgl_vector_3d<double>& v,
00095   const vgl_vector_3d<double>& w,
00096   int ni, int nj, int nk)
00097 {
00098   const vimt3d_transform_3d& s_w2i = src_image.world2im();
00099   vgl_point_3d<double> im_p = s_w2i(p);
00100   vgl_vector_3d<double> im_u = s_w2i.delta(p, u);
00101   vgl_vector_3d<double> im_v = s_w2i.delta(p, v);
00102   vgl_vector_3d<double> im_w = s_w2i.delta(p, w);
00103 
00104   vil3d_resample_trilinear_edge_extend(src_image.image(),dest_image.image(),
00105     im_p.x(),im_p.y(),im_p.z(), im_u.x(),im_u.y(),im_u.z(),
00106     im_v.x(),im_v.y(),im_v.z(), im_w.x(),im_w.y(),im_w.z(), ni,nj,nk);
00107 
00108   // Point (i,j,k) in dest corresponds to p+i.u+j.v+k.w,
00109   // an affine transformation for image to world
00110   vimt3d_transform_3d d_i2w;
00111   d_i2w.set_affine(p,u,v,w);
00112   d_i2w.simplify();
00113   dest_image.set_world2im(d_i2w.inverse());
00114 }
00115 
00116 
00117 //: Resample an image using appropriate smoothing if the resolution changes significantly.
00118 //  dest_image(i,j,k,p) is sampled from the src_image at
00119 //  p+i.u+j.v+k.w, where i=[0..ni-1], j=[0..nj-1], k=[0..nk-1] in world co-ordinates.
00120 //
00121 //  dest_image resized to (ni,nj,nk,src_image.nplanes())
00122 //
00123 //  dest_image.world2im() set up so that the world co-ordinates in src and dest match
00124 //
00125 //  Points outside image return the value of the nearest valid pixel.
00126 // \relatesalso vimt3d_image_3d_of
00127 template <class sType, class dType>
00128 inline void vimt3d_resample_trilin_smoothing_edge_extend(
00129   const vimt3d_image_3d_of<sType>& src_image,
00130   vimt3d_image_3d_of<dType>& dest_image,
00131   const vgl_point_3d<double>& p,
00132   const vgl_vector_3d<double>& u,
00133   const vgl_vector_3d<double>& v,
00134   const vgl_vector_3d<double>& w,
00135   int ni, int nj, int nk)
00136 {
00137   vimt3d_transform_3d scaling;
00138   scaling.set_zoom_only(0.5,0,0,0);
00139 
00140   vimt3d_image_3d_of<sType> im = src_image;
00141   vgl_vector_3d<double> im_d = im.world2im().delta(p, u) + im.world2im().delta(p, v)
00142     + im.world2im().delta(p, w);
00143 
00144   // If step length (in pixels) >> 1, smooth and reduce image x2.
00145   // Don't use strict Nyqusit limit.
00146   // Since we are just using factor 2 smoothing and reduction,
00147   // we have to tradeoff aliasing with information loss.
00148   while (im_d.length() > 1.33*1.732 && im.image().ni() > 5 && im.image().nj() > 5 && im.image().nk() > 5)
00149   {
00150     vimt3d_image_3d_of<sType> dest;
00151     vil3d_image_view<sType> work1, work2;
00152     vil3d_gauss_reduce(im.image(), dest.image(), work1, work2);
00153 
00154     dest.set_world2im(scaling * im.world2im());
00155 
00156     // re-establish loop invariant
00157     im = dest;
00158     im_d = im.world2im().delta(p, u) + im.world2im().delta(p, v) + im.world2im().delta(p, w);
00159   }
00160 
00161   vimt3d_resample_trilin_edge_extend(im, dest_image, p, u, v, w, ni, nj, nk);
00162 }
00163 
00164 //: Resample src, using the grid defined by dest.
00165 //  Smooths appropriatly if the resolution changes significantly.
00166 //  dest(i,j,k,p) is sampled from src at the wc grid defined by 
00167 //  the world co-ords of the pixel centres in dest.
00168 //
00169 //  dest is not resized, nor has its world2im transform modified.
00170 //
00171 //  Points outside src return the value of the nearest valid pixel.
00172 // \relatesalso vimt3d_image_3d_of
00173 template <class sType, class dType>
00174 inline void vimt3d_resample_trilin_smoothing_edge_extend(
00175   const vimt3d_image_3d_of<sType>& src,
00176   vimt3d_image_3d_of<dType>& dest)
00177 {
00178   vimt3d_transform_3d orig_w2i = dest.world2im();
00179   vimt3d_transform_3d i2w = orig_w2i.inverse();
00180 
00181   vimt3d_resample_trilin_smoothing_edge_extend(
00182     src, dest,
00183     i2w.origin(),
00184     i2w.delta(vgl_point_3d<double>(0,0,0), vgl_vector_3d<double>(1,0,0)),
00185     i2w.delta(vgl_point_3d<double>(0,0,0), vgl_vector_3d<double>(0,1,0)),
00186     i2w.delta(vgl_point_3d<double>(0,0,0), vgl_vector_3d<double>(0,0,1)),
00187     dest.image().ni(), dest.image().nj(), dest.image().nk() );
00188 
00189   dest.world2im() = orig_w2i;
00190 }
00191 
00192 
00193 #endif // vimt3d_resample_trilinear_h_