vil_pyramid_image_list.cxx
Go to the documentation of this file.
1 #include <algorithm>
2 #include <cmath>
3 #include <sstream>
5 //:
6 // \file
7 #include <cassert>
8 #ifdef _MSC_VER
9 # include <vcl_msvc_warnings.h>
10 #endif
11 #include <vil/vil_stream_fstream.h>
12 #include <vil/vil_image_list.h>
15 #include <vil/vil_new.h>
16 #include <vil/vil_load.h>
17 #include <vil/vil_copy.h>
18 
19 //:Load a pyramid image. The path should correspond to a directory.
20 //If not, return a null resource.
23 {
24  vil_image_list il(directory);
25  std::vector<vil_image_resource_sptr> rescs = il.resources();
26  if (rescs.size() < 2L)
27  return nullptr;
28  auto* pil = new vil_pyramid_image_list(rescs);
29  pil->set_directory(directory);
30  return pil;
31 }
32 
35 {
37  return nullptr;
38  return new vil_pyramid_image_list(file);
39 }
40 
41 static bool copy_base_resc(vil_image_resource_sptr const& base_image,
42  const std::string& full_filename,
43  char const* file_format,
45 {
46  { //scope for closing resource
47  //Create a new blocked base image resource
48  std::cout << "Copying base resource\n";
50  if (!brsc||brsc->size_block_i()%2!=0||brsc->size_block_i()%2!=0)
51  brsc = new vil_blocked_image_facade(base_image);
52  // handle case of RGBA as four planes
53  vil_pixel_format fmt = vil_pixel_format_component_format(brsc->pixel_format());
55  vil_new_blocked_image_resource(full_filename.c_str(),
56  brsc->ni(), brsc->nj(),
57  brsc->nplanes(),
58  fmt,
59  brsc->size_block_i(),
60  brsc->size_block_j(),
61  file_format);
62  if (!out_resc)
63  return false;
64  for (unsigned int j = 0; j<brsc->n_block_j(); ++j)
65  for (unsigned int i = 0; i<brsc->n_block_i(); ++i)
66  {
67  vil_image_view_base_sptr blk = brsc->get_block(i,j);
68  if (!blk)
69  return false;
70  if (!out_resc->put_block(i, j, *blk))
71  return false;
72  }
73  }//end scope for out resource
74  //
75  //reopen the resource for reading.
76  vil_image_resource_sptr temp = vil_load_image_resource(full_filename.c_str());
77  copy = blocked_image_resource(temp);
78  return (bool)copy;
79 }
80 
81 static std::string level_filename(std::string& directory, std::string& filename,
82  float level)
83 {
84  std::string slash;
85 
86 #ifdef _WIN32
87  slash = "\\";
88 #else
89  slash = "/";
90 #endif
91  std::stringstream cs;
92  cs << level;
93  return directory + slash + filename + "_" + cs.str();
94 }
95 
96 //: Construct pyramid image files in the directory
97 // Each level has the same scale ratio (0.5) to the preceding level.
98 // Level 0 is the original base image.
100  make_pyramid_image_from_base(char const* directory,
101  vil_image_resource_sptr const& base_image,
102  unsigned int nlevels,
103  bool copy_base,
104  char const* level_file_format,
105  char const* filename
106  )
107 {
108  if (!vil_image_list::vil_is_directory(directory))
109  return nullptr;
110  std::string d = directory;
111  std::string fn = filename;
112  std::string full_filename = level_filename(d,fn, 0.0f) + '.'+ level_file_format;
114  if (copy_base)
115  {
116  if (!copy_base_resc(base_image, full_filename,
117  level_file_format, blk_base))
118  return nullptr;
119  }
120  else
121  {
122  blk_base =
123  blocked_image_resource(base_image);
124  if (!blk_base)
125  return nullptr;
126  }
127  //Create the other pyramid levels
128  { //program scope to close resource files
129  vil_image_resource_sptr image = blk_base.ptr();
130  for (unsigned int L = 1; L<nlevels; ++L)
131  {
132  std::cout << "Decimating Level " << L << std::endl;
133  full_filename = level_filename(d, fn, float(L)) + '.'+ level_file_format;
134  image = vil_pyramid_image_resource::decimate(image,full_filename.c_str());
135  }
136  } //end program scope to close resource files
137  vil_image_list il(directory);
138  std::vector<vil_image_resource_sptr> rescs = il.resources();
139  return new vil_pyramid_image_list(rescs);
140 }
141 
142 ///============== start vil_pyramid_image_list =========================
143 //comparison of level scales
144 static bool level_compare(pyramid_level* const l1, pyramid_level* const l2)
145 {
146  assert(l1&&l2);
147  return l1->image_->ni() > l2->image_->ni();
148 }
149 
150 
152 {}
153 
154 vil_pyramid_image_list::vil_pyramid_image_list(char const* directory) : directory_(directory)
155 {}
156 
157 vil_pyramid_image_list::vil_pyramid_image_list(std::vector<vil_image_resource_sptr> const& images) : directory_("")
158 {
159  for (const auto & image : images)
160  {
161  //if the resource is blocked use a cached access
163  if (!brsc)
164  brsc = new vil_blocked_image_facade(image);
167  auto* level = new pyramid_level(ir);
168  levels_.push_back(level);
169  }
170  //sort on image width
171  std::sort(levels_.begin(), levels_.end(), level_compare);
172  this->normalize_scales();
173 }
174 
176 {
177  auto nlevels = (unsigned int)(levels_.size());
178  for (unsigned int i = 0; i<nlevels; ++i)
179  delete levels_[i];
180 }
181 
182 //: Assumes that the image in level 0 is the largest
184 {
185  auto nlevels = (unsigned int)(levels_.size());
186  if (nlevels==0)
187  return;
188  levels_[0]->scale_ = 1.0f;
189  if (nlevels==1)
190  return;
191  auto ni0 = static_cast<float>(levels_[0]->image_->ni());
192  for (unsigned int i = 1; i<nlevels; ++i)
193  levels_[i]->scale_ = static_cast<float>(levels_[i]->image_->ni())/ni0;
194 }
195 
197 {
198  unsigned int ni = image->ni(), nj = image->nj();
199  for (unsigned int L = 0; L<this->nlevels(); ++L)
200  if (levels_[L]->image_->ni()==ni&&levels_[L]->image_->nj()==nj)
201  return true;
202  return false;
203 }
204 
205 bool
207 {
208  if (this->is_same_size(image))
209  return false;
210 
211  auto* level = new pyramid_level(image);
212  levels_.push_back(level);
213 
214  //is this the first image added?
215  if (levels_.size() == 1)
216  return true;
217  //sort the pyramid
218  std::sort(levels_.begin(), levels_.end(), level_compare);
219  //normalize the scales
220  this->normalize_scales();
221  return true;
222 }
223 
224 //: Find an appropriate filename extension for the image.
225 // If the size of the image lies between existing scales then use
226 // the fractional amount in the name
227 float
229 {
230  unsigned int nlevels = this->nlevels();
231  if (nlevels==0)
232  return 0.0f;
233  auto base_ni = static_cast<float>(levels_[0]->image_->ni());
234  return static_cast<float>(image->ni())/base_ni;
235 }
236 
237 //: This method copies the resource into the pyramid.
238 // Use add_resource if the existing resource is to be just inserted into the level stack.
240 {
241  if (this->is_same_size(image))
242  return false;
243  float level = this->find_next_level(image);
244  std::string copy_name = "copyR";
245  std::string file = level_filename(directory_,copy_name, level);
246  std::string ffmt = "pgm";
247  if (image->file_format())
248  ffmt = image->file_format();
249  file = file +'.'+ ffmt;
250  unsigned int sbi = 0, sbj = 0;
252  if (bir)
253  { sbi = bir->size_block_i(); sbj = bir->size_block_j(); }
255  if (sbi==0||sbj==0)
256  {
257 #ifdef VIL_USE_FSTREAM64
258  vil_stream_fstream64* os = new vil_stream_fstream64(file.c_str(), "w");
259 #else //VIL_USE_FSTREAM64
260  auto* os = new vil_stream_fstream(file.c_str(), "w");
261 #endif //VIL_USE_FSTREAM64
262  copy = vil_new_image_resource(os, image->ni(), image->nj(),
263  image->nplanes(), image->pixel_format(),
264  ffmt.c_str());
265  }
266  else
267  copy = vil_new_blocked_image_resource(file.c_str(),
268  image->ni(), image->nj(),
269  image->nplanes(),
270  image->pixel_format(),
271  sbi, sbj,
272  ffmt.c_str()).ptr();
273  if (!vil_copy_deep(image, copy))
274  return false;
275  return this->add_resource(copy);
276 }
277 
278 //:find the level closest to the specified scale
280 {
281  auto nlevels = (unsigned int)(levels_.size());
282  if (nlevels == 0)
283  return nullptr;
284 
285  if (nlevels == 1)
286  return levels_[0];
287  float mind = 1.0e08f;//huge scale;
288  unsigned int lmin = 0;
289  for (unsigned int i = 0; i<nlevels; ++i)
290  {
291  float ds = std::fabs(std::log(levels_[i]->scale_ / scale));
292  if (ds<mind)
293  {
294  mind = ds;
295  lmin = i;
296  }
297  }
298  pyramid_level* pl = levels_[lmin];
299  if (pl)
300  pl->cur_level_ = lmin;
301  return pl;
302 }
303 
305 vil_pyramid_image_list::get_copy_view(unsigned int i0, unsigned int n_i,
306  unsigned int j0, unsigned int n_j,
307  unsigned int level) const
308 {
309  if (level>=this->nlevels())
310  {
311  std::cerr << "pyramid_image_list::get_copy_view(.) level = "
312  << level << " max level = "
313  << this->nlevels() -1 << '\n';
314  return nullptr;
315  }
316  pyramid_level* pl = levels_[level];
317  float actual_scale = pl->scale_;
318 
319  float fi0 = actual_scale*i0, fni = actual_scale*n_i, fj0 = actual_scale*j0, fnj = actual_scale*n_j;
320  //transform image coordinates by actual scale
321  auto si0 = static_cast<unsigned int>(fi0);
322  auto sni = static_cast<unsigned int>(fni);
323  if (sni == 0) sni = 1;//can't have less than one pixel
324  auto sj0 = static_cast<unsigned int>(fj0);
325  auto snj = static_cast<unsigned int>(fnj);
326  if (snj == 0) snj = 1;//can't have less than one pixel
327  vil_image_view_base_sptr v = pl->image_->get_copy_view(si0, sni, sj0, snj);
328  if (!v)
329  {
330  std::cerr << "pyramid_image_list::get_copy_view(.) level = "
331  << level << "(i0,j0):("
332  << i0 << ' ' << j0 << ") (ni, nj):("
333  << n_i << ' ' << n_j << ")\n"
334  << "Get copy view from level image failed\n";
335  return nullptr;
336  }
337  return v;
338 }
339 
340 //:return a view with image scale that is closest to scale.
342 vil_pyramid_image_list::get_copy_view(unsigned int i0, unsigned int n_i,
343  unsigned int j0, unsigned int n_j,
344  const float scale,
345  float& actual_scale) const
346 {
347  //find the resource that is closest to the specified scale
348  pyramid_level* pl = this->closest(scale);
349  if (!pl)
350  {
351  actual_scale = 0;
352  return nullptr;
353  }
354  actual_scale = pl->scale_;
355  unsigned int level = pl->cur_level_;
356  return this->get_copy_view(i0, n_i, j0, n_j, level);
357 }
std::vector< vil_image_resource_sptr > resources()
finds all the image files in the directory, regardless of extension.
vil_pixel_format
Describes the type of the concrete data.
vil_pixel_format vil_pixel_format_component_format(enum vil_pixel_format f)
Return the number of components in pixel format f.
bool add_resource(vil_image_resource_sptr const &image)
Add an image resource directly to the pyramid without copying.
A templated smart pointer class.
Definition: vil_fwd.h:16
static bool vil_is_directory(char const *)
utility functions.
vil_pyramid_image_resource_sptr make_input_pyramid_image(char const *directory) override
Read a pyramid resource. Image list files are stored in directory.
vil_pyramid_image_resource_sptr make_pyramid_image_from_base(char const *directory, vil_image_resource_sptr const &base_image, unsigned int nlevels, bool copy_base, char const *level_file_format, char const *filename) override
Construct a pyramid image resource from a base image.
vil_image_resource_sptr image_
the resource.
static vil_image_resource_sptr decimate(vil_image_resource_sptr const &resc, char const *filename, char const *format="tiff")
Utility for decimating a resource to create a new pyramid level.
vil_image_resource_sptr vil_new_image_resource(unsigned ni, unsigned nj, unsigned nplanes, vil_pixel_format format)
Make a new image of given format.
Definition: vil_new.cxx:32
A vil_stream implementation using std::fstream.
float scale_
scale associated with level.
A cached and blocked representation of the image_resource.
pyramid_level * closest(const float scale) const
find the image resource with scale closest to specified scale.
vil_blocked_image_resource_sptr vil_new_blocked_image_resource(vil_stream *os, unsigned ni, unsigned nj, unsigned nplanes, vil_pixel_format format, unsigned size_block_i, unsigned size_block_j, char const *file_format)
Make a new blocked resource file.
Definition: vil_new.cxx:156
unsigned int nj() const override
The number of pixels in each column.
unsigned int cur_level_
the current pyramid level for this resource.
read an image from a file
bool put_resource(vil_image_resource_sptr const &image) override
Copy an image resource to the pyramid.
vil_pyramid_image_resource_sptr make_pyramid_output_image(char const *directory) override
bool is_same_size(vil_image_resource_sptr const &image)
input image is the same size as one already in the pyramid.
A vil_stream implementation using std::fstream.
#define v
vil_blocked_image_resource_sptr blocked_image_resource(const vil_image_resource_sptr &ir)
cast to blocked resource if possible.
A blocked image facade for any image resource.
Various image copying functions.
Abstract representation of an image source or image destination.
float find_next_level(vil_image_resource_sptr const &image)
find the nearest level to the image size.
void normalize_scales()
normalize the scale factors so that the base image scale = 1.0.
vil_image_view_base_sptr get_copy_view() const
Create a read/write view of a copy of all the data.
An image resource list reader. Finds all resources of a type in the given directory.
unsigned int nlevels() const override
number of levels in the pyramid.
Make a new image.
vil_image_resource_sptr vil_load_image_resource(char const *filename, bool verbose=true)
Load an image resource object from a file.
Definition: vil_load.cxx:68
bool vil_copy_deep(const vil_image_resource_sptr &src, vil_image_resource_sptr &dest)
Copy src to dest.
Definition: vil_copy.cxx:45
unsigned int ni() const override
The number of pixels in each row.
T * ptr() const
These methods all return the raw/dumb pointer.
A pyramid image resource based on multiple file-based image resources.
std::vector< pyramid_level * > levels_