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