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