00001
00002 #ifndef vimt3d_gaussian_pyramid_builder_3d_txx_
00003 #define vimt3d_gaussian_pyramid_builder_3d_txx_
00004
00005
00006
00007
00008
00009 #include "vimt3d_gaussian_pyramid_builder_3d.h"
00010
00011 #include <vcl_cstdlib.h>
00012 #include <vcl_string.h>
00013
00014 #include <vgl/vgl_point_3d.h>
00015 #include <vgl/vgl_vector_3d.h>
00016 #include <vimt/vimt_image_pyramid.h>
00017 #include <vil3d/algo/vil3d_gauss_reduce.h>
00018 #include <vcl_cassert.h>
00019 #include <vcl_cmath.h>
00020
00021
00022
00023 template<class T>
00024 vimt3d_gaussian_pyramid_builder_3d<T>::vimt3d_gaussian_pyramid_builder_3d()
00025 : max_levels_(99),uniform_reduction_(false),filter_width_(5)
00026 {
00027 set_min_size(5, 5, 5);
00028 }
00029
00030
00031
00032 template<class T>
00033 vimt3d_gaussian_pyramid_builder_3d<T>::~vimt3d_gaussian_pyramid_builder_3d()
00034 {
00035 }
00036
00037
00038
00039
00040 template<class T>
00041 void vimt3d_gaussian_pyramid_builder_3d<T>::set_max_levels(int max_l)
00042 {
00043 if (max_l<1)
00044 {
00045 vcl_cerr<<"vimt3d_gaussian_pyramid_builder_3d<T>::setMaxLevels() param is "
00046 <<max_l<<", must be >=1\n";
00047 vcl_abort();
00048 }
00049 max_levels_ = max_l;
00050 }
00051
00052
00053 template<class T>
00054 int vimt3d_gaussian_pyramid_builder_3d<T>::max_levels() const
00055 {
00056 return max_levels_;
00057 }
00058
00059
00060 template<class T>
00061 int vimt3d_gaussian_pyramid_builder_3d<T>::n_levels(const vimt3d_image_3d_of<T>& base_image) const
00062 {
00063 int ni = base_image.image().ni();
00064 int nj = base_image.image().nj();
00065 int nk = base_image.image().nk();
00066 double dx,dy,dz;
00067 get_pixel_size(dx,dy,dz,base_image);
00068
00069
00070 int max_levels = 0;
00071 while ((ni>=int(min_x_size_)) && (nj>=int(min_y_size_)) && (nk>=int(min_z_size_)))
00072 {
00073 if (uniform_reduction_)
00074 {
00075 ni = (ni+1)/2; dx*=2;
00076 nj = (nj+1)/2; dy*=2;
00077 nk = (nk+1)/2; dz*=2;
00078 }
00079 else if (dz*dz/(dx*dx)>2.0)
00080 {
00081
00082 ni = (ni+1)/2; dx*=2;
00083 nj = (nj+1)/2; dy*=2;
00084 }
00085 else if (dy*dy/(dx*dx)>2.0)
00086 {
00087
00088 ni = (ni+1)/2; dx*=2;
00089 nk = (nk+1)/2; dz*=2;
00090 }
00091 else if (dx*dx/(dy*dy)>2.0)
00092 {
00093
00094 nj = (nj+1)/2; dy*=2;
00095 nk = (nk+1)/2; dz*=2;
00096 }
00097 else
00098 {
00099 ni = (ni+1)/2; dx*=2;
00100 nj = (nj+1)/2; dy*=2;
00101 nk = (nk+1)/2; dz*=2;
00102 }
00103 max_levels++;
00104 }
00105 if (max_levels<1) max_levels = 1;
00106 if (max_levels>max_levels_)
00107 max_levels=max_levels_;
00108
00109 return max_levels;
00110 }
00111
00112
00113
00114
00115 template<class T>
00116 vimt_image_pyramid* vimt3d_gaussian_pyramid_builder_3d<T>::new_image_pyramid() const
00117 {
00118 return new vimt_image_pyramid;
00119 }
00120
00121
00122
00123
00124 template<class T>
00125 double vimt3d_gaussian_pyramid_builder_3d<T>::scale_step() const
00126 {
00127 return 2.0;
00128 }
00129
00130
00131 template<class T>
00132 void vimt3d_gaussian_pyramid_builder_3d<T>::set_filter_width(unsigned w)
00133 {
00134 assert(w==5);
00135 filter_width_ = w;
00136 }
00137
00138
00139
00140
00141
00142 template<class T>
00143 void vimt3d_gaussian_pyramid_builder_3d<T>::gauss_reduce(vimt3d_image_3d_of<T>& dest_im,
00144 vimt3d_image_3d_of<T>const& src_im) const
00145 {
00146
00147 if (filter_width_!=5)
00148 {
00149 vcl_cerr<<"vimt3d_gaussian_pyramid_builder_3d<T>::gauss_reduce()\n"
00150 <<" Cannot cope with filter width of "<<filter_width_<<'\n';
00151 vcl_abort();
00152 }
00153
00154 double dx,dy,dz;
00155 get_pixel_size(dx,dy,dz,src_im);
00156
00157 vimt3d_transform_3d scaling;
00158
00159 if (uniform_reduction_)
00160 {
00161 vil3d_gauss_reduce(src_im.image(),dest_im.image(),work_im1_,work_im2_);
00162 scaling.set_zoom_only(0.5,0.5,0.5,0,0,0);
00163 dest_im.set_world2im(scaling * src_im.world2im());
00164
00165 return;
00166 }
00167
00168
00169 if (dz*dz/(dx*dx)>2.0)
00170 {
00171 vil3d_gauss_reduce_ij(src_im.image(),dest_im.image(),work_im1_);
00172 scaling.set_zoom_only(0.5,0.5,1.0,0,0,0);
00173 dest_im.set_world2im(scaling * src_im.world2im());
00174 }
00175 else if (dy*dy/(dx*dx)>2.0)
00176 {
00177 vil3d_gauss_reduce_ik(src_im.image(),dest_im.image(),work_im1_);
00178 scaling.set_zoom_only(0.5,1.0,0.5,0,0,0);
00179 dest_im.set_world2im(scaling * src_im.world2im());
00180 }
00181 else if (dx*dx/(dy*dy)>2.0)
00182 {
00183 vil3d_gauss_reduce_jk(src_im.image(),dest_im.image(),work_im1_);
00184 scaling.set_zoom_only(1.0,0.5,0.5,0,0,0);
00185 dest_im.set_world2im(scaling * src_im.world2im());
00186 }
00187 else
00188 {
00189 vil3d_gauss_reduce(src_im.image(),dest_im.image(),work_im1_,work_im2_);
00190
00191 scaling.set_zoom_only(0.5,0.5,0.5,0,0,0);
00192 dest_im.set_world2im(scaling * src_im.world2im());
00193 }
00194 }
00195
00196
00197
00198 template<class T>
00199 void vimt3d_gaussian_pyramid_builder_3d<T>::emptyPyr(vimt_image_pyramid& im_pyr) const
00200 {
00201 for (int i=0; i<im_pyr.n_levels();++i)
00202 delete im_pyr.data()[i];
00203 }
00204
00205
00206
00207 template<class T>
00208 void vimt3d_gaussian_pyramid_builder_3d<T>::checkPyr(vimt_image_pyramid& im_pyr, int n_levels) const
00209 {
00210 const int got_levels = im_pyr.n_levels();
00211 if (got_levels >= n_levels && im_pyr(0).is_a()==work_im1_.is_a())
00212 {
00213 if (im_pyr.n_levels()==n_levels) return;
00214 else
00215 {
00216 for (int i=n_levels;i<got_levels;++i)
00217 delete im_pyr.data()[i];
00218 }
00219 im_pyr.data().resize(n_levels);
00220 return;
00221 }
00222
00223 im_pyr.resize(n_levels,vimt3d_image_3d_of<T>());
00224 }
00225
00226
00227 template<class T>
00228 void vimt3d_gaussian_pyramid_builder_3d<T>::set_min_size(unsigned X, unsigned Y, unsigned Z)
00229 { min_x_size_ = X; min_y_size_ = Y; min_z_size_ = Z; }
00230
00231
00232
00233 template<class T>
00234 void vimt3d_gaussian_pyramid_builder_3d<T>::build(vimt_image_pyramid& image_pyr,
00235 vimt_image const& im) const
00236 {
00237
00238 assert(im.is_class("vimt3d_image_3d"));
00239
00240
00241 const vimt3d_image_3d &im3d = static_cast<const vimt3d_image_3d &>(im);
00242
00243
00244 assert(im3d.image_base().is_a()==work_im1_.is_a());
00245
00246 const vimt3d_image_3d_of<T>& base_image = static_cast<const vimt3d_image_3d_of<T>&>(im3d);
00247
00248 int ni = base_image.image().ni();
00249 int nj = base_image.image().nj();
00250 int nk = base_image.image().nk();
00251
00252 int max_levels=n_levels(base_image);
00253
00254
00255 checkPyr(image_pyr,max_levels);
00256
00257 vimt3d_image_3d_of<T>& im0 = static_cast<vimt3d_image_3d_of<T>&>(image_pyr(0));
00258
00259
00260 im0=base_image;
00261
00262 int i;
00263 for (i=1;i<max_levels;i++)
00264 {
00265 vimt3d_image_3d_of<T>& im_i0 = static_cast<vimt3d_image_3d_of<T>&>(image_pyr(i));
00266 vimt3d_image_3d_of<T>& im_i1 = static_cast<vimt3d_image_3d_of<T>&>(image_pyr(i-1));
00267
00268 gauss_reduce(im_i0,im_i1);
00269 }
00270
00271
00272 vgl_point_3d<double> c0(0.5*(ni-1),0.5*(nj-1),0.5*(nk-1));
00273 vgl_point_3d<double> c1 = c0 + vgl_vector_3d<double> (1,1,1);
00274 vimt3d_transform_3d im2world = base_image.world2im().inverse();
00275 vgl_vector_3d<double> dw = im2world(c1) - im2world(c0);
00276
00277 double base_pixel_width = dw.length()/vcl_sqrt(3.0);
00278 double scale_step = 2.0;
00279
00280 image_pyr.set_widths(base_pixel_width,scale_step);
00281 }
00282
00283
00284 template<class T>
00285 void vimt3d_gaussian_pyramid_builder_3d<T>::get_pixel_size(double &dx, double& dy, double& dz,
00286 const vimt3d_image_3d_of<T>& image) const
00287 {
00288
00289 vgl_point_3d<double> c0(0,0,0);
00290 vgl_point_3d<double> cx(1,0,0);
00291 vgl_point_3d<double> cy(0,1,0);
00292 vgl_point_3d<double> cz(0,0,1);
00293 vimt3d_transform_3d im2world = image.world2im().inverse();
00294 dx = (im2world(cx) - im2world(c0)).length();
00295 dy = (im2world(cy) - im2world(c0)).length();
00296 dz = (im2world(cz) - im2world(c0)).length();
00297 }
00298
00299
00300
00301 template<class T>
00302 void vimt3d_gaussian_pyramid_builder_3d<T>::extend(vimt_image_pyramid& image_pyr) const
00303 {
00304
00305 assert(image_pyr(0).is_a() == work_im1_.is_a());
00306
00307 assert(image_pyr.scale_step() == scale_step());
00308
00309 vimt3d_image_3d_of<T>& im_base = static_cast<vimt3d_image_3d_of<T>&>(image_pyr(0));
00310 int ni = im_base.image().ni();
00311 int nj = im_base.image().nj();
00312 int nk = im_base.image().nk();
00313
00314 int max_levels=n_levels(static_cast<const vimt3d_image_3d_of<T>&>(image_pyr(0)));
00315
00316 work_im1_.set_size(ni,nj,nk);
00317 work_im2_.set_size(ni,nj,nk);
00318
00319
00320 int oldsize = image_pyr.n_levels();
00321 if (oldsize<max_levels)
00322 {
00323 image_pyr.data().resize(max_levels);
00324
00325 int i;
00326 for (i=oldsize;i<max_levels;++i)
00327 image_pyr.data()[i] = new vimt3d_image_3d_of<T>;
00328
00329 for (i=oldsize;i<max_levels;i++)
00330 {
00331 vimt3d_image_3d_of<T>& im_i0 = static_cast<vimt3d_image_3d_of<T>&>(image_pyr(i));
00332 vimt3d_image_3d_of<T>& im_i1 = static_cast<vimt3d_image_3d_of<T>&>(image_pyr(i-1));
00333
00334 gauss_reduce(im_i0,im_i1);
00335 }
00336 }
00337 }
00338
00339
00340
00341 template<class T>
00342 bool vimt3d_gaussian_pyramid_builder_3d<T>::is_class(vcl_string const& s) const
00343 {
00344 return s==vimt3d_gaussian_pyramid_builder_3d<T>::is_a() || vimt_image_pyramid_builder::is_class(s);
00345 }
00346
00347
00348
00349 template<class T>
00350 short vimt3d_gaussian_pyramid_builder_3d<T>::version_no() const
00351 {
00352 return 1;
00353 }
00354
00355
00356
00357 template<class T>
00358 vimt_image_pyramid_builder* vimt3d_gaussian_pyramid_builder_3d<T>::clone() const
00359 {
00360 return new vimt3d_gaussian_pyramid_builder_3d<T>(*this);
00361 }
00362
00363
00364
00365 template<class T>
00366 void vimt3d_gaussian_pyramid_builder_3d<T>::print_summary(vcl_ostream&) const
00367 {
00368 }
00369
00370
00371
00372 template<class T>
00373 void vimt3d_gaussian_pyramid_builder_3d<T>::b_write(vsl_b_ostream& bfs) const
00374 {
00375 vsl_b_write(bfs,version_no());
00376 vsl_b_write(bfs,max_levels_);
00377 vsl_b_write(bfs,uniform_reduction_);
00378 vsl_b_write(bfs,filter_width_);
00379 }
00380
00381
00382
00383 template<class T>
00384 void vimt3d_gaussian_pyramid_builder_3d<T>::b_read(vsl_b_istream& bfs)
00385 {
00386 if (!bfs) return;
00387
00388 short version;
00389 vsl_b_read(bfs,version);
00390 switch (version)
00391 {
00392 case (1):
00393 vsl_b_read(bfs,max_levels_);
00394 vsl_b_read(bfs,uniform_reduction_);
00395 vsl_b_read(bfs,filter_width_);
00396 break;
00397 default:
00398 vcl_cerr << "I/O ERROR: vimt3d_gaussian_pyramid_builder_3d<T>::b_read(vsl_b_istream&)\n"
00399 << " Unknown version number "<< version << '\n';
00400 bfs.is().clear(vcl_ios::badbit);
00401 return;
00402 }
00403 }
00404
00405 #undef VIMT3D_GAUSSIAN_PYRAMID_BUILDER_3D_INSTANTIATE
00406 #define VIMT3D_GAUSSIAN_PYRAMID_BUILDER_3D_INSTANTIATE(T) \
00407 VCL_DEFINE_SPECIALIZATION vcl_string vimt3d_gaussian_pyramid_builder_3d<T >::is_a() const \
00408 { return vcl_string("vimt3d_gaussian_pyramid_builder_3d<" #T ">"); } \
00409 template class vimt3d_gaussian_pyramid_builder_3d<T >
00410
00411 #endif // vimt3d_gaussian_pyramid_builder_3d_txx_