1 // This is mul/vimt3d/vimt3d_sample_grid_trilin.hxx
2 #ifndef vimt3d_sample_grid_trilin_hxx_
3 #define vimt3d_sample_grid_trilin_hxx_
4 //:
5 // \file
6 // \brief Profile sampling functions for 3D images
7 // \author Graham Vincent
8 
9 #include "vimt3d_sample_grid_trilin.h"
10 #include <vil3d/vil3d_trilin_interp.h>
11 #include <vnl/vnl_vector.h>
12 #include <vgl/vgl_point_3d.h>
13 #include <vgl/vgl_vector_3d.h>
14 
15 //: True if p clearly inside the image
16 template<class T>
17 inline bool
vimt3d_trilin_point_in_image(const vgl_point_3d<double> & p,const vil3d_image_view<T> & image)18 vimt3d_trilin_point_in_image(const vgl_point_3d<double>& p, const vil3d_image_view<T>& image)
19 {
20   if (p.x()<1) return false;
21   if (p.y()<1) return false;
22   if (p.z()<1) return false;
23   if (p.x()+2>image.ni()) return false;
24   if (p.y()+2>image.nj()) return false;
25   if (p.z()+2>image.nk()) return false;
26   return true;
27 }
28 
29 //: True if grid of size nu * nv * nw (in steps of u,v,w) is entirely in the image.
30 //  p defines centre of one size.
31 template<class T>
vimt3d_grid_in_image_ic(const vgl_point_3d<double> & im_p,const vgl_vector_3d<double> & im_u,const vgl_vector_3d<double> & im_v,const vgl_vector_3d<double> & im_w,unsigned nu,unsigned nv,unsigned nw,const vil3d_image_view<T> & image)32 inline bool vimt3d_grid_in_image_ic(const vgl_point_3d<double>& im_p,
33                                     const vgl_vector_3d<double>& im_u,
34                                     const vgl_vector_3d<double>& im_v,
35                                     const vgl_vector_3d<double>& im_w,
36                                     unsigned nu, unsigned nv, unsigned nw,
37                                     const vil3d_image_view<T>& image)
38 {
39   vgl_vector_3d<double> u1=(nu-1)*im_u;
40   vgl_vector_3d<double> v1=(nv-1)*im_v;
41   vgl_vector_3d<double> w1=(nw-1)*im_w;
42   if (!vimt3d_trilin_point_in_image(im_p,image)) return false;
43   if (!vimt3d_trilin_point_in_image(im_p+u1,image)) return false;
44   if (!vimt3d_trilin_point_in_image(im_p+v1,image)) return false;
45   if (!vimt3d_trilin_point_in_image(im_p+w1,image)) return false;
46   if (!vimt3d_trilin_point_in_image(im_p+u1+v1,image)) return false;
47   if (!vimt3d_trilin_point_in_image(im_p+u1+w1,image)) return false;
48   if (!vimt3d_trilin_point_in_image(im_p+v1+w1,image)) return false;
49   if (!vimt3d_trilin_point_in_image(im_p+u1+v1+w1,image)) return false;
50 
51   return true;
52 }
53 
54 
55 //: Sample grid p+i.u+j.v+k.w using trilinear interpolation in world coordinates.
56 //  Profile points are p+i.u+j.v+k.w, where i=[0..nu-1],j=[0..nv-1], k=[0..nw-1]
57 //  Vector v is resized to nu*nv*nw*np elements, where np=image.n_planes().
58 //  v[0]..v[np-1] are the values from point p.
59 //  Samples are taken along direction w first. Samples
60 //  outside the image are set to 0.
61 template <class imType, class vecType>
vimt3d_sample_grid_trilin(vnl_vector<vecType> & vec,const vimt3d_image_3d_of<imType> & image,const vgl_point_3d<double> & p,const vgl_vector_3d<double> & u,const vgl_vector_3d<double> & v,const vgl_vector_3d<double> & w,unsigned nu,unsigned nv,unsigned nw)62 void vimt3d_sample_grid_trilin(vnl_vector<vecType>& vec,
63                                const vimt3d_image_3d_of<imType>& image,
64                                const vgl_point_3d<double>& p,
65                                const vgl_vector_3d<double>& u,
66                                const vgl_vector_3d<double>& v,
67                                const vgl_vector_3d<double>& w,
68                                unsigned nu, unsigned nv, unsigned nw)
69 {
70   // convert to image coordinates
71   vgl_point_3d<double> im_p0 = image.world2im()(p);
72   vgl_vector_3d<double> im_u = image.world2im()(p+u)-im_p0;
73   vgl_vector_3d<double> im_v = image.world2im()(p+v)-im_p0;
74   vgl_vector_3d<double> im_w = image.world2im()(p+w)-im_p0;
75 
76   // call image coordinate version of grid sampler
77   vimt3d_sample_grid_trilin_ic(vec,image.image(),im_p0,im_u,im_v,im_w,nu,nv,nw);
78 
79   return;
80 }
81 
82 
83 //: Sample grid p+i.u+j.v+k.w in image coordinates using trilinear interpolation with NO CHECKS.
84 //  Profile points are p+i.u+j.v+k.w, where i=[0..nu-1],j=[0..nv-1], k=[0..nw-1]
85 //  Vector v is resized to nu*nv*nw*np elements, where np=image.n_planes().
86 //  v[0]..v[np-1] are the values from point p
87 //  Samples are taken along each image plane first, then direction w, then v, and u.
88 //  Points outside image return zero.
89 template <class imType, class vecType>
vimt3d_sample_grid_trilin_ic_no_checks(vnl_vector<vecType> & vec,const vil3d_image_view<imType> & image,const vgl_point_3d<double> & p0,const vgl_vector_3d<double> & u,const vgl_vector_3d<double> & v,const vgl_vector_3d<double> & w,unsigned nu,unsigned nv,unsigned nw)90 inline void vimt3d_sample_grid_trilin_ic_no_checks(
91   vnl_vector<vecType>& vec,
92   const vil3d_image_view<imType>& image,
93   const vgl_point_3d<double>& p0,
94   const vgl_vector_3d<double>& u,
95   const vgl_vector_3d<double>& v,
96   const vgl_vector_3d<double>& w,
97   unsigned nu, unsigned nv, unsigned nw)
98 {
99   unsigned np = image.nplanes();
100   std::ptrdiff_t istep = image.istep();
101   std::ptrdiff_t jstep = image.jstep();
102   std::ptrdiff_t kstep = image.kstep();
103   std::ptrdiff_t pstep = image.planestep();
104 
105   vec.set_size(nu*nv*nw*np);
106   vecType* vc = vec.begin();
107 
108   vgl_point_3d<double> p1 = p0;
109 
110   if (np==1)
111   {
112     const imType* plane0 = image.origin_ptr();
113     for (unsigned i=0;i<nu;++i,p1+=u)
114     {
115       vgl_point_3d<double> p2 = p1;
116       for (unsigned j=0;j<nv;++j,p2+=v)
117       {
118         vgl_point_3d<double> p = p2;
119         // Sample each row (along w)
120         for (unsigned k=0;k<nw;++k,p+=w,++vc)
121           *vc = vil3d_trilin_interp_raw(p.x(),p.y(),p.z(),
122                                         plane0,istep,jstep,kstep);
123       }
124     }
125   }
126   else
127   {
128     for (unsigned i=0;i<nu;++i,p1+=u)
129     {
130       vgl_point_3d<double> p2 = p1;
131       for (unsigned j=0;j<nv;++j,p2+=v)
132       {
133         vgl_point_3d<double> p = p2;
134         // Sample each row (along w)
135         for (unsigned l=0;l<nw;++l,p+=w)
136           for (unsigned k=0;k<np;++k,++vc)
137             *vc = vil3d_trilin_interp_raw(p.x(),p.y(),p.z(),
138                                           image.origin_ptr()+k*pstep,istep,jstep,kstep);
139       }
140     }
141   }
142 }
143 
144 //: Sample grid p+i.u+j.v+k.w safely in image coordinates using trilinear interpolation.
145 //  Profile points are p+i.u+j.v+k.w, where i=[0..nu-1],j=[0..nv-1], k=[0..nw-1]
146 //  Vector v is resized to nu*nv*nw*np elements, where np=image.n_planes().
147 //  v[0]..v[np-1] are the values from point p
148 //  Samples are taken along direction w first
149 //  Points outside image return zero.
150 template <class imType, class vecType>
vimt3d_sample_grid_trilin_ic_safe(vnl_vector<vecType> & vec,const vil3d_image_view<imType> & image,const vgl_point_3d<double> & p0,const vgl_vector_3d<double> & u,const vgl_vector_3d<double> & v,const vgl_vector_3d<double> & w,unsigned nu,unsigned nv,unsigned nw)151 inline void vimt3d_sample_grid_trilin_ic_safe(
152   vnl_vector<vecType>& vec,
153   const vil3d_image_view<imType>& image,
154   const vgl_point_3d<double>& p0,
155   const vgl_vector_3d<double>& u,
156   const vgl_vector_3d<double>& v,
157   const vgl_vector_3d<double>& w,
158   unsigned nu, unsigned nv, unsigned nw)
159 {
160   unsigned np = image.nplanes();
161   unsigned ni = image.ni();
162   unsigned nj = image.nj();
163   unsigned nk = image.nk();
164   std::ptrdiff_t istep = image.istep();
165   std::ptrdiff_t jstep = image.jstep();
166   std::ptrdiff_t kstep = image.kstep();
167   std::ptrdiff_t pstep = image.planestep();
168 
169   vec.set_size(nu*nv*nw*np);
170   vecType* vc = vec.begin();
171 
172   vgl_point_3d<double> p1 = p0;
173 
174   if (np==1)
175   {
176     const imType* plane0 = image.origin_ptr();
177     for (unsigned i=0;i<nu;++i,p1+=u)
178     {
179       vgl_point_3d<double> p2 = p1;
180       for (unsigned j=0;j<nv;++j,p2+=v)
181       {
182         vgl_point_3d<double> p = p2;
183         // Sample each row (along w)
184         for (unsigned k=0;k<nw;++k,p+=w,++vc)
185           *vc = vil3d_trilin_interp_safe(p.x(),p.y(),p.z(),plane0,ni,nj,nk,istep,jstep,kstep);
186       }
187     }
188   }
189   else
190   {
191     for (unsigned i=0;i<nu;++i,p1+=u)
192     {
193       vgl_point_3d<double> p2 = p1;
194       for (unsigned j=0;j<nv;++j,p2+=v)
195       {
196         vgl_point_3d<double> p = p2;
197         // Sample each row (along w)
198         for (unsigned l=0;l<nw;++l,p+=w)
199           for (unsigned k=0;k<np;++k,++vc)
200             *vc = vil3d_trilin_interp_safe(p.x(),p.y(),p.z(),
201                                            image.origin_ptr()+k*pstep,ni,nj,nk,istep,jstep,kstep);
202       }
203     }
204   }
205 }
206 
207 //: Sample grid p+i.u+j.v+k.w safely in image coordinates using trilinear interpolation.
208 //  Profile points are p+i.u+j.v+k.w, where i=[0..nu-1],j=[0..nv-1], k=[0..nw-1]
209 //  Vector v is resized to nu*nv*nw*np elements, where np=image.n_planes().
210 //  v[0]..v[np-1] are the values from point p
211 //  Samples are taken along direction w first
212 //  Points outside image are set to the nearest voxel's value.
213 template <class imType, class vecType>
vimt3d_sample_grid_trilin_ic_extend(vnl_vector<vecType> & vec,const vil3d_image_view<imType> & image,const vgl_point_3d<double> & p0,const vgl_vector_3d<double> & u,const vgl_vector_3d<double> & v,const vgl_vector_3d<double> & w,unsigned nu,unsigned nv,unsigned nw)214 inline void vimt3d_sample_grid_trilin_ic_extend(
215   vnl_vector<vecType>& vec,
216   const vil3d_image_view<imType>& image,
217   const vgl_point_3d<double>& p0,
218   const vgl_vector_3d<double>& u,
219   const vgl_vector_3d<double>& v,
220   const vgl_vector_3d<double>& w,
221   unsigned nu, unsigned nv, unsigned nw)
222 {
223   unsigned np = image.nplanes();
224   unsigned ni = image.ni();
225   unsigned nj = image.nj();
226   unsigned nk = image.nk();
227   std::ptrdiff_t istep = image.istep();
228   std::ptrdiff_t jstep = image.jstep();
229   std::ptrdiff_t kstep = image.kstep();
230   std::ptrdiff_t pstep = image.planestep();
231 
232   vec.set_size(nu*nv*nw*np);
233   vecType* vc = vec.begin();
234 
235   vgl_point_3d<double> p1 = p0;
236 
237   if (np==1)
238   {
239     const imType* plane0 = image.origin_ptr();
240     for (unsigned i=0;i<nu;++i,p1+=u)
241     {
242       vgl_point_3d<double> p2 = p1;
243       for (unsigned j=0;j<nv;++j,p2+=v)
244       {
245         vgl_point_3d<double> p = p2;
246         // Sample each row (along w)
247         for (unsigned k=0;k<nw;++k,p+=w,++vc)
248           *vc = vil3d_trilin_interp_safe_extend(p.x(),p.y(),p.z(),
249                                                 plane0,ni,nj,nk,istep,jstep,kstep);
250       }
251     }
252   }
253   else
254   {
255     for (unsigned i=0;i<nu;++i,p1+=u)
256     {
257       vgl_point_3d<double> p2 = p1;
258       for (unsigned j=0;j<nv;++j,p2+=v)
259       {
260         vgl_point_3d<double> p = p2;
261         // Sample each row (along w)
262         for (unsigned l=0;l<nw;++l,p+=w)
263           for (unsigned k=0;k<np;++k,++vc)
264             *vc = vil3d_trilin_interp_safe_extend(p.x(),p.y(),p.z(),
265                                                   image.origin_ptr()+k*pstep,ni,nj,nk,istep,jstep,kstep);
266       }
267     }
268   }
269 }
270 
271 //: Sample grid p+i.u+j.v+k.w safely in image coordinates using trilinear interpolation.
272 //  Profile points are p+i.u+j.v+k.w, where i=[0..nu-1],j=[0..nv-1], k=[0..nw-1]
273 //  Vector v is resized to nu*nv*nw*np elements, where np=image.n_planes().
274 //  v[0]..v[np-1] are the values from point p
275 //  Samples are taken along direction w first
276 //  Points outside image are set to the nearest voxel's value.
277 template <class imType, class vecType>
vimt3d_sample_grid_trilin_ic_edgena(vnl_vector<vecType> & vec,const vil3d_image_view<imType> & image,const vgl_point_3d<double> & p0,const vgl_vector_3d<double> & u,const vgl_vector_3d<double> & v,const vgl_vector_3d<double> & w,unsigned nu,unsigned nv,unsigned nw)278 inline void vimt3d_sample_grid_trilin_ic_edgena(
279   vnl_vector<vecType>& vec,
280   const vil3d_image_view<imType>& image,
281   const vgl_point_3d<double>& p0,
282   const vgl_vector_3d<double>& u,
283   const vgl_vector_3d<double>& v,
284   const vgl_vector_3d<double>& w,
285   unsigned nu, unsigned nv, unsigned nw)
286 {
287   unsigned np = image.nplanes();
288   unsigned ni = image.ni();
289   unsigned nj = image.nj();
290   unsigned nk = image.nk();
291   std::ptrdiff_t istep = image.istep();
292   std::ptrdiff_t jstep = image.jstep();
293   std::ptrdiff_t kstep = image.kstep();
294   std::ptrdiff_t pstep = image.planestep();
295 
296   vec.set_size(nu*nv*nw*np);
297   vecType* vc = vec.begin();
298 
299   vgl_point_3d<double> p1 = p0;
300 
301   if (np==1)
302   {
303     const imType* plane0 = image.origin_ptr();
304     for (unsigned i=0;i<nu;++i,p1+=u)
305     {
306       vgl_point_3d<double> p2 = p1;
307       for (unsigned j=0;j<nv;++j,p2+=v)
308       {
309         vgl_point_3d<double> p = p2;
310         // Sample each row (along w)
311         for (unsigned k=0;k<nw;++k,p+=w,++vc)
312           *vc = vil3d_trilin_interp_safe_edgena(p.x(),p.y(),p.z(),
313                                                 plane0,ni,nj,nk,istep,jstep,kstep);
314       }
315     }
316   }
317   else
318   {
319     for (unsigned i=0;i<nu;++i,p1+=u)
320     {
321       vgl_point_3d<double> p2 = p1;
322       for (unsigned j=0;j<nv;++j,p2+=v)
323       {
324         vgl_point_3d<double> p = p2;
325         // Sample each row (along w)
326         for (unsigned l=0;l<nw;++l,p+=w)
327           for (unsigned k=0;k<np;++k,++vc)
328             *vc = vil3d_trilin_interp_safe_edgena(p.x(),p.y(),p.z(),
329                                                   image.origin_ptr()+k*pstep,ni,nj,nk,istep,jstep,kstep);
330       }
331     }
332   }
333 }
334 
335 //: Sample grid p+i.u+j.v+k.w using trilinear interpolation in world coordinates.
336 //  Profile points are p+i.u+j.v+k.w, where i=[0..nu-1],j=[0..nv-1], k=[0..nw-1]
337 //  Vector v is resized to nu*nv*nw*np elements, where np=image.n_planes().
338 //  v[0]..v[np-1] are the values from point p.
339 //  Samples are taken along direction w first. Samples
340 //  outside the image are set to the value of the nearest voxel's value.
341 template <class imType, class vecType>
vimt3d_sample_grid_trilin_extend(vnl_vector<vecType> & vec,const vimt3d_image_3d_of<imType> & image,const vgl_point_3d<double> & p,const vgl_vector_3d<double> & u,const vgl_vector_3d<double> & v,const vgl_vector_3d<double> & w,unsigned nu,unsigned nv,unsigned nw)342 void vimt3d_sample_grid_trilin_extend(
343   vnl_vector<vecType>& vec,
344   const vimt3d_image_3d_of<imType>& image,
345   const vgl_point_3d<double>& p,
346   const vgl_vector_3d<double>& u,
347   const vgl_vector_3d<double>& v,
348   const vgl_vector_3d<double>& w,
349   unsigned nu, unsigned nv, unsigned nw)
350 {
351   // convert to image coordinates
352   vgl_point_3d<double> im_p0 = image.world2im()(p);
353   vgl_vector_3d<double> im_u = image.world2im()(p+u)-im_p0;
354   vgl_vector_3d<double> im_v = image.world2im()(p+v)-im_p0;
355   vgl_vector_3d<double> im_w = image.world2im()(p+w)-im_p0;
356 
357   // call image coordinate version of grid sampler
358   if (vimt3d_grid_in_image_ic(im_p0,im_u,im_v,im_w,nu,nv,nw,image.image()))
359     vimt3d_sample_grid_trilin_ic_no_checks(vec,image.image(),im_p0,im_u,im_v,im_w,nu,nv,nw);
360   else
361     vimt3d_sample_grid_trilin_ic_extend(vec,image.image(),im_p0,im_u,im_v,im_w,nu,nv,nw);
362 
363   return;
364 }
365 
366 
367 //: Sample grid p+i.u+j.v+k.w using trilinear interpolation in world coordinates.
368 //  Profile points are p+i.u+j.v+k.w, where i=[0..nu-1],j=[0..nv-1], k=[0..nw-1]
369 //  Vector v is resized to nu*nv*nw*np elements, where np=image.n_planes().
370 //  v[0]..v[np-1] are the values from point p.
371 //  Samples are taken along direction w first. Samples
372 //  outside the image are set to the value of the nearest voxel's value.
373 template <class imType, class vecType>
vimt3d_sample_grid_trilin_edgena(vnl_vector<vecType> & vec,const vimt3d_image_3d_of<imType> & image,const vgl_point_3d<double> & p,const vgl_vector_3d<double> & u,const vgl_vector_3d<double> & v,const vgl_vector_3d<double> & w,unsigned nu,unsigned nv,unsigned nw)374 void vimt3d_sample_grid_trilin_edgena(
375   vnl_vector<vecType>& vec,
376   const vimt3d_image_3d_of<imType>& image,
377   const vgl_point_3d<double>& p,
378   const vgl_vector_3d<double>& u,
379   const vgl_vector_3d<double>& v,
380   const vgl_vector_3d<double>& w,
381   unsigned nu, unsigned nv, unsigned nw)
382 {
383   // convert to image coordinates
384   vgl_point_3d<double> im_p0 = image.world2im()(p);
385   vgl_vector_3d<double> im_u = image.world2im()(p+u)-im_p0;
386   vgl_vector_3d<double> im_v = image.world2im()(p+v)-im_p0;
387   vgl_vector_3d<double> im_w = image.world2im()(p+w)-im_p0;
388 
389   // call image coordinate version of grid sampler
390   if (vimt3d_grid_in_image_ic(im_p0,im_u,im_v,im_w,nu,nv,nw,image.image()))
391     vimt3d_sample_grid_trilin_ic_no_checks(vec,image.image(),im_p0,im_u,im_v,im_w,nu,nv,nw);
392   else
393     vimt3d_sample_grid_trilin_ic_edgena(vec,image.image(),im_p0,im_u,im_v,im_w,nu,nv,nw);
394 
395   return;
396 }
397 
398 //: Sample grid p+i.u+j.v+k.w using trilinear interpolation in image coordinates.
399 //  Profile points are p+i.u+j.v+k.w, where i=[0..nu-1],j=[0..nv-1], k=[0..nw-1]
400 //  Vector v is resized to nu*nv*nw*np elements, where np=image.n_planes().
401 //  v[0]..v[np-1] are the values from point p
402 //  Samples are taken along direction w first.
403 //  Samples outside the image are set to 0.
404 template <class imType, class vecType>
vimt3d_sample_grid_trilin_ic(vnl_vector<vecType> & vec,const vil3d_image_view<imType> & image,const vgl_point_3d<double> & im_p,const vgl_vector_3d<double> & im_u,const vgl_vector_3d<double> & im_v,const vgl_vector_3d<double> & im_w,unsigned nu,unsigned nv,unsigned nw)405 void vimt3d_sample_grid_trilin_ic(vnl_vector<vecType>& vec,
406                                   const vil3d_image_view<imType>& image,
407                                   const vgl_point_3d<double>& im_p,
408                                   const vgl_vector_3d<double>& im_u,
409                                   const vgl_vector_3d<double>& im_v,
410                                   const vgl_vector_3d<double>& im_w,
411                                   unsigned nu, unsigned nv, unsigned nw)
412 {
413   if (vimt3d_grid_in_image_ic(im_p,im_u,im_v,im_w,nu,nv,nw,image))
414     vimt3d_sample_grid_trilin_ic_no_checks(vec,image,im_p,im_u,im_v,im_w,nu,nv,nw);
415   else
416     vimt3d_sample_grid_trilin_ic_safe(vec,image,im_p,im_u,im_v,im_w,nu,nv,nw);
417 
418   return;
419 }
420 
421 
422 #define VIMT3D_SAMPLE_GRID_TRILIN_INSTANTIATE( imType, vecType ) \
423 template void vimt3d_sample_grid_trilin( \
424   vnl_vector<vecType >& vec, \
425   const vimt3d_image_3d_of<imType >& image, \
426   const vgl_point_3d<double >& p, \
427   const vgl_vector_3d<double >& u, \
428   const vgl_vector_3d<double >& v, \
429   const vgl_vector_3d<double >& w, \
430   unsigned nu, unsigned nv, unsigned nw); \
431 template void vimt3d_sample_grid_trilin_extend( \
432   vnl_vector<vecType >& vec, \
433   const vimt3d_image_3d_of<imType >& image, \
434   const vgl_point_3d<double >& p, \
435   const vgl_vector_3d<double >& u, \
436   const vgl_vector_3d<double >& v, \
437   const vgl_vector_3d<double >& w, \
438   unsigned nu, unsigned nv, unsigned nw); \
439 template void vimt3d_sample_grid_trilin_edgena( \
440   vnl_vector<vecType >& vec, \
441   const vimt3d_image_3d_of<imType >& image, \
442   const vgl_point_3d<double >& p, \
443   const vgl_vector_3d<double >& u, \
444   const vgl_vector_3d<double >& v, \
445   const vgl_vector_3d<double >& w, \
446   unsigned nu, unsigned nv, unsigned nw); \
447 template void vimt3d_sample_grid_trilin_ic( \
448   vnl_vector<vecType >& vec, \
449   const vil3d_image_view<imType >& image, \
450   const vgl_point_3d<double >& im_p, \
451   const vgl_vector_3d<double >& im_u, \
452   const vgl_vector_3d<double >& im_v, \
453   const vgl_vector_3d<double >& im_w, \
454   unsigned nu, unsigned nv, unsigned nw)
455 
456 #endif // vimt3d_sample_grid_trilin_hxx_
457