core/vil/file_formats/vil_pyramid_image_list.cxx
Go to the documentation of this file.
00001 #include "vil_pyramid_image_list.h"
00002 //:
00003 // \file
00004 #include <vcl_algorithm.h>
00005 #include <vcl_cmath.h>
00006 #include <vcl_cassert.h>
00007 #include <vcl_sstream.h>
00008 #include <vil/vil_stream_fstream.h>
00009 #include <vil/vil_image_list.h>
00010 #include <vil/vil_blocked_image_facade.h>
00011 #include <vil/vil_cached_image_resource.h>
00012 #include <vil/vil_new.h>
00013 #include <vil/vil_load.h>
00014 #include <vil/vil_copy.h>
00015 
00016 //:Load a pyramid image.  The path should correspond to a directory.
00017 //If not, return a null resource.
00018 vil_pyramid_image_resource_sptr
00019 vil_pyramid_image_list_format::make_input_pyramid_image(char const* directory)
00020 {
00021   vil_image_list il(directory);
00022   vcl_vector<vil_image_resource_sptr> rescs = il.resources();
00023   unsigned nr = rescs.size();
00024   if (nr < 2)
00025     return 0;
00026   vil_pyramid_image_list* pil = new vil_pyramid_image_list(rescs);
00027   pil->set_directory(directory);
00028   return pil;
00029 }
00030 
00031 vil_pyramid_image_resource_sptr
00032 vil_pyramid_image_list_format::make_pyramid_output_image(char const* file)
00033 {
00034   if (!vil_image_list::vil_is_directory(file))
00035     return 0;
00036   return new vil_pyramid_image_list(file);
00037 }
00038 
00039 static bool copy_base_resc(vil_image_resource_sptr const& base_image,
00040                            vcl_string full_filename,
00041                            char const* file_format,
00042                            vil_blocked_image_resource_sptr& copy)
00043 {
00044   { //scope for closing resource
00045   //Create a new blocked base image resource
00046   vcl_cout << "Copying base resource\n";
00047   vil_blocked_image_resource_sptr brsc = blocked_image_resource(base_image);
00048   if (!brsc||brsc->size_block_i()%2!=0||brsc->size_block_i()%2!=0)
00049     brsc = new vil_blocked_image_facade(base_image);
00050   vil_blocked_image_resource_sptr out_resc =
00051     vil_new_blocked_image_resource(full_filename.c_str(),
00052                                    brsc->ni(), brsc->nj(),
00053                                    brsc->nplanes(),
00054                                    brsc->pixel_format(),
00055                                    brsc->size_block_i(),
00056                                    brsc->size_block_j(),
00057                                    file_format);
00058   if (!out_resc)
00059     return false;
00060   for (unsigned j = 0; j<brsc->n_block_j(); ++j)
00061     for (unsigned i = 0; i<brsc->n_block_i(); ++i)
00062     {
00063       vil_image_view_base_sptr blk = brsc->get_block(i,j);
00064       if (!blk)
00065         return 0;
00066       if (!out_resc->put_block(i, j, *blk))
00067         return 0;
00068     }
00069   }//end scope for out resource
00070   //
00071   //reopen the resource for reading.
00072   vil_image_resource_sptr temp = vil_load_image_resource(full_filename.c_str());
00073   copy = blocked_image_resource(temp);
00074   return (bool)copy;
00075 }
00076 
00077 static vcl_string level_filename(vcl_string& directory, vcl_string& filename,
00078                                  float level)
00079 {
00080   vcl_string slash;
00081 
00082 #ifdef VCL_WIN32
00083   slash =  "\\";
00084 #else
00085   slash = "/";
00086 #endif
00087   vcl_stringstream cs;
00088   cs << level;
00089   return directory + slash + filename + "_" + cs.str();
00090 }
00091 
00092 //: Construct pyramid image files in the directory
00093 //  Each level has the same scale ratio (0.5) to the preceeding level.
00094 //  Level 0 is the original base image.
00095 vil_pyramid_image_resource_sptr vil_pyramid_image_list_format::
00096     make_pyramid_image_from_base(char const* directory,
00097                                  vil_image_resource_sptr const& base_image,
00098                                  unsigned nlevels,
00099                                  bool copy_base,
00100                                  char const* level_file_format,
00101                                  char const* filename
00102                                 )
00103 {
00104   if (!vil_image_list::vil_is_directory(directory))
00105     return 0;
00106   vcl_string d = directory;
00107   vcl_string fn = filename;
00108   vcl_string full_filename = level_filename(d,fn, 0.0f) + '.'+ level_file_format;
00109   vil_blocked_image_resource_sptr blk_base;
00110   if (copy_base)
00111   {
00112     if (!copy_base_resc(base_image, full_filename,
00113                         level_file_format, blk_base))
00114       return 0;
00115   }
00116   else
00117   {
00118     blk_base =
00119       blocked_image_resource(base_image);
00120     if (!blk_base)
00121       return 0;
00122   }
00123   //Create the other pyramid levels
00124   { //program scope to close resource files
00125     vil_image_resource_sptr image = blk_base.ptr();
00126     for (unsigned L = 1; L<nlevels; ++L)
00127     {
00128       vcl_cout << "Decimating Level " << L << vcl_endl;
00129       full_filename = level_filename(d, fn, float(L)) + '.'+ level_file_format;
00130       image = vil_pyramid_image_resource::decimate(image,full_filename.c_str());
00131     }
00132   } //end program scope to close resource files
00133   vil_image_list il(directory);
00134   vcl_vector<vil_image_resource_sptr> rescs = il.resources();
00135   return new vil_pyramid_image_list(rescs);
00136 }
00137 
00138 ///==============  start vil_pyramid_image_list  =========================
00139 //comparison of level scales
00140 static bool level_compare(pyramid_level* const l1, pyramid_level* const l2)
00141 {
00142   assert(l1&&l2);
00143   return l1->image_->ni() > l2->image_->ni();
00144 }
00145 
00146 
00147 vil_pyramid_image_list::vil_pyramid_image_list() : directory_("")
00148 {}
00149 
00150 vil_pyramid_image_list::vil_pyramid_image_list(char const* directory) : directory_(directory)
00151 {}
00152 
00153 vil_pyramid_image_list::vil_pyramid_image_list(vcl_vector<vil_image_resource_sptr> const& images) : directory_("")
00154 {
00155   for (vcl_vector<vil_image_resource_sptr>::const_iterator rit = images.begin();
00156        rit != images.end(); ++rit)
00157   {
00158     //if the resource is blocked use a cached access
00159     vil_blocked_image_resource_sptr brsc = blocked_image_resource(*rit);
00160     if (!brsc)
00161       brsc = new vil_blocked_image_facade(*rit);
00162     vil_cached_image_resource* cimr = new vil_cached_image_resource(brsc, 100);
00163     vil_image_resource_sptr ir = (vil_image_resource*)cimr;
00164     pyramid_level* level = new pyramid_level(ir);
00165     levels_.push_back(level);
00166   }
00167   //sort on image width
00168   vcl_sort(levels_.begin(), levels_.end(), level_compare);
00169   this->normalize_scales();
00170 }
00171 
00172 vil_pyramid_image_list::~vil_pyramid_image_list()
00173 {
00174   unsigned nlevels = levels_.size();
00175   for (unsigned i = 0; i<nlevels; ++i)
00176     delete levels_[i];
00177 }
00178 
00179 //: Assumes that the image in level 0 is the largest
00180 void vil_pyramid_image_list::normalize_scales()
00181 {
00182   unsigned nlevels = levels_.size();
00183   if (nlevels==0)
00184     return;
00185   levels_[0]->scale_ = 1.0f;
00186   if (nlevels==1)
00187     return;
00188   float ni0 = static_cast<float>(levels_[0]->image_->ni());
00189   for (unsigned i = 1; i<nlevels; ++i)
00190     levels_[i]->scale_ = static_cast<float>(levels_[i]->image_->ni())/ni0;
00191 }
00192 
00193 bool vil_pyramid_image_list::is_same_size(vil_image_resource_sptr const& image)
00194 {
00195   unsigned ni = image->ni(), nj = image->nj();
00196   for (unsigned L = 0; L<this->nlevels(); ++L)
00197     if (levels_[L]->image_->ni()==ni&&levels_[L]->image_->nj()==nj)
00198       return true;
00199   return false;
00200 }
00201 
00202 bool
00203 vil_pyramid_image_list::add_resource(vil_image_resource_sptr const& image)
00204 {
00205   if (this->is_same_size(image))
00206     return false;
00207 
00208   pyramid_level* level = new pyramid_level(image);
00209   levels_.push_back(level);
00210 
00211   //is this the first image added?
00212   if (levels_.size() == 1)
00213     return true;
00214   //sort the pyramid
00215   vcl_sort(levels_.begin(), levels_.end(), level_compare);
00216   //normalize the scales
00217   this->normalize_scales();
00218   return true;
00219 }
00220 
00221 //: Find an appropriate filename extension for the image.
00222 // If the size of the image lies between existing scales then use
00223 // the fractional amount in the name
00224 float
00225 vil_pyramid_image_list::find_next_level(vil_image_resource_sptr const& image)
00226 {
00227   unsigned nlevels = this->nlevels();
00228   if (nlevels==0)
00229     return 0.0f;
00230   float base_ni = static_cast<float>(levels_[0]->image_->ni());
00231   return static_cast<float>(image->ni())/base_ni;
00232 }
00233 
00234 //: This method copies the resource into the pyramid.
00235 // Use add_resource if the existing resource is to be just inserted into the level stack.
00236 bool vil_pyramid_image_list::put_resource(vil_image_resource_sptr const& image)
00237 {
00238   if (this->is_same_size(image))
00239     return false;
00240   float level = this->find_next_level(image);
00241   vcl_string copy_name = "copyR";
00242   vcl_string file = level_filename(directory_,copy_name, level);
00243   vcl_string ffmt = "pgm";
00244   if (image->file_format())
00245     ffmt = image->file_format();
00246   file = file +'.'+ ffmt;
00247   unsigned sbi = 0, sbj = 0;
00248   vil_blocked_image_resource_sptr bir = blocked_image_resource(image);
00249   if (bir)
00250   { sbi = bir->size_block_i(); sbj = bir->size_block_j(); }
00251   vil_image_resource_sptr copy;
00252   if (sbi==0||sbj==0)
00253   {
00254 #ifdef VIL_USE_FSTREAM64
00255     vil_stream_fstream64* os = new vil_stream_fstream64(file.c_str(), "w");
00256 #else //VIL_USE_FSTREAM64
00257     vil_stream_fstream* os = new vil_stream_fstream(file.c_str(), "w");
00258 #endif //VIL_USE_FSTREAM64
00259     copy = vil_new_image_resource(os, image->ni(), image->nj(),
00260                                   image->nplanes(), image->pixel_format(),
00261                                   ffmt.c_str());
00262   }
00263   else
00264     copy = vil_new_blocked_image_resource(file.c_str(),
00265                                           image->ni(), image->nj(),
00266                                           image->nplanes(),
00267                                           image->pixel_format(),
00268                                           sbi, sbj,
00269                                           ffmt.c_str()).ptr();
00270   if (!vil_copy_deep(image, copy))
00271     return false;
00272   return this->add_resource(copy);
00273 }
00274 
00275 //:find the level closest to the specified scale
00276 pyramid_level* vil_pyramid_image_list::closest(const float scale) const
00277 {
00278   unsigned nlevels = levels_.size();
00279   if (nlevels == 0)
00280     return 0;
00281 
00282   if (nlevels == 1)
00283     return levels_[0];
00284   float mind = 1.0e08f;//huge scale;
00285   unsigned lmin = 0;
00286   for (unsigned i = 0; i<nlevels; ++i)
00287   {
00288     float ds = vcl_fabs(vcl_log(levels_[i]->scale_ / scale));
00289     if (ds<mind)
00290     {
00291       mind = ds;
00292       lmin = i;
00293     }
00294   }
00295   pyramid_level* pl = levels_[lmin];
00296   if (pl)
00297     pl->cur_level_ = lmin;
00298   return pl;
00299 }
00300 
00301 vil_image_view_base_sptr
00302 vil_pyramid_image_list::get_copy_view(unsigned i0, unsigned n_i,
00303                                       unsigned j0, unsigned n_j,
00304                                       unsigned level) const
00305 {
00306   if (level>=this->nlevels())
00307   {
00308     vcl_cerr << "pyramid_image_list::get_copy_view(.) level = "
00309              << level << " max level = "
00310              << this->nlevels() -1 << '\n';
00311     return 0;
00312   }
00313   pyramid_level* pl = levels_[level];
00314   float actual_scale = pl->scale_;
00315 
00316   float fi0 = actual_scale*i0, fni = actual_scale*n_i, fj0 = actual_scale*j0, fnj = actual_scale*n_j;
00317   //transform image coordinates by actual scale
00318   unsigned si0 = static_cast<unsigned>(fi0);
00319   unsigned sni = static_cast<unsigned>(fni);
00320   if (sni == 0) sni = 1;//can't have less than one pixel
00321   unsigned sj0 = static_cast<unsigned>(fj0);
00322   unsigned snj = static_cast<unsigned>(fnj);
00323   if (snj == 0) snj = 1;//can't have less than one pixel
00324   vil_image_view_base_sptr v = pl->image_->get_copy_view(si0, sni, sj0, snj);
00325   if (!v)
00326   {
00327     vcl_cerr << "pyramid_image_list::get_copy_view(.) level = "
00328              << level << "(i0,j0):("
00329              << i0 << ' ' << j0 << ") (ni, nj):("
00330              << n_i << ' ' << n_j << ")\n"
00331              << "Get copy view from level image failed\n";
00332     return 0;
00333   }
00334   return v;
00335 }
00336 
00337 //:return a view with image scale that is closest to scale.
00338 vil_image_view_base_sptr
00339 vil_pyramid_image_list::get_copy_view(unsigned i0, unsigned n_i,
00340                                       unsigned j0, unsigned n_j,
00341                                       const float scale,
00342                                       float& actual_scale) const
00343 {
00344   //find the resource that is closest to the specified scale
00345   pyramid_level* pl = this->closest(scale);
00346   if (!pl)
00347   {
00348     actual_scale = 0;
00349     return 0;
00350   }
00351   actual_scale = pl->scale_;
00352   unsigned level = pl->cur_level_;
00353   return this->get_copy_view(i0, n_i, j0, n_j, level);
00354 }
00355