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