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