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