AliceVision
Photogrammetric Computer Vision Framework
cachedImage.hpp
1 // This file is part of the AliceVision project.
2 // Copyright (c) 2020 AliceVision contributors.
3 // This Source Code Form is subject to the terms of the Mozilla Public License,
4 // v. 2.0. If a copy of the MPL was not distributed with this file,
5 // You can obtain one at https://mozilla.org/MPL/2.0/.
6 
7 #pragma once
8 
9 #include <aliceVision/image/Image.hpp>
10 #include <aliceVision/image/io.hpp>
11 #include <aliceVision/image/cache.hpp>
12 
13 #include <aliceVision/panorama/boundingBox.hpp>
14 #include <aliceVision/system/Logger.hpp>
15 #include <aliceVision/types.hpp>
16 #include <iterator>
17 
18 namespace aliceVision {
19 
20 template<class T>
22 {
23  public:
24  using RowType = std::vector<image::CachedTile::smart_pointer>;
25 
26  public:
27  bool createImage(std::shared_ptr<image::TileCacheManager> manager, size_t width, size_t height)
28  {
29  _width = width;
30  _height = height;
31  _tileSize = manager->getTileWidth();
32 
33  _tilesArray.clear();
34 
35  int countHeight = int(ceil(double(height) / double(manager->getTileHeight())));
36  int countWidth = int(ceil(double(width) / double(manager->getTileWidth())));
37 
38  _memoryWidth = countWidth * _tileSize;
39  _memoryHeight = countHeight * _tileSize;
40 
41  for (int i = 0; i < countHeight; i++)
42  {
43  int tile_height = manager->getTileHeight();
44  if (i == countHeight - 1)
45  {
46  tile_height = height - (i * tile_height);
47  }
48 
49  std::vector<image::CachedTile::smart_pointer> row;
50 
51  for (int j = 0; j < countWidth; j++)
52  {
53  int tile_width = manager->getTileWidth();
54  if (j == countWidth - 1)
55  {
56  tile_width = width - (i * tile_width);
57  }
58 
59  image::CachedTile::smart_pointer tile = manager->requireNewCachedTile<T>(tile_width, tile_height);
60  if (tile == nullptr)
61  {
62  return false;
63  }
64 
65  row.push_back(tile);
66  }
67 
68  _tilesArray.push_back(row);
69  }
70 
71  return true;
72  }
73 
74  bool writeImage(const std::string& path, const image::EStorageDataType& storageDataType = image::EStorageDataType::Auto)
75  {
76  ALICEVISION_LOG_ERROR("incorrect template function");
77  return false;
78  }
79 
80  template<class UnaryFunction>
81  bool perPixelOperation(UnaryFunction f)
82  {
83  for (int i = 0; i < _tilesArray.size(); i++)
84  {
85  RowType& row = _tilesArray[i];
86 
87  for (int j = 0; j < _tilesArray[i].size(); j++)
88  {
89  image::CachedTile::smart_pointer ptr = row[j];
90  if (!ptr)
91  {
92  continue;
93  }
94 
95  if (!ptr->acquire())
96  {
97  continue;
98  }
99 
100  T* data = (T*)ptr->getDataPointer();
101 
102  std::transform(data, data + ptr->getTileWidth() * ptr->getTileHeight(), data, f);
103  }
104  }
105 
106  return true;
107  }
108 
109  template<class T2, class BinaryFunction>
110  bool perPixelOperation(CachedImage<T2>& other, BinaryFunction f)
111  {
112  if (other.getWidth() != _width || other.getHeight() != _height)
113  {
114  return false;
115  }
116 
117  for (int i = 0; i < _tilesArray.size(); i++)
118  {
119  RowType& row = _tilesArray[i];
120  RowType& rowOther = other.getTiles()[i];
121 
122  for (int j = 0; j < _tilesArray[i].size(); j++)
123  {
124  image::CachedTile::smart_pointer ptr = row[j];
125  if (!ptr)
126  {
127  continue;
128  }
129 
130  image::CachedTile::smart_pointer ptrOther = rowOther[j];
131  if (!ptrOther)
132  {
133  continue;
134  }
135 
136  if (!ptr->acquire())
137  {
138  continue;
139  }
140 
141  if (!ptrOther->acquire())
142  {
143  continue;
144  }
145 
146  T* data = (T*)ptr->getDataPointer();
147  T2* dataOther = (T2*)ptrOther->getDataPointer();
148 
149  std::transform(data, data + ptr->getTileWidth() * ptr->getTileHeight(), dataOther, data, f);
150  }
151  }
152 
153  return true;
154  }
155 
156  bool deepCopy(CachedImage<T>& source)
157  {
158  if (source._memoryWidth != _memoryWidth)
159  return false;
160  if (source._memoryHeight != _memoryHeight)
161  return false;
162  if (source._tileSize != _tileSize)
163  return false;
164 
165  for (int i = 0; i < _tilesArray.size(); i++)
166  {
167  RowType& row = _tilesArray[i];
168  RowType& rowSource = source._tilesArray[i];
169 
170  for (int j = 0; j < _tilesArray[i].size(); j++)
171  {
172  image::CachedTile::smart_pointer ptr = row[j];
173  if (!ptr)
174  {
175  continue;
176  }
177 
178  image::CachedTile::smart_pointer ptrSource = rowSource[j];
179  if (!ptrSource)
180  {
181  continue;
182  }
183 
184  if (!ptr->acquire())
185  {
186  continue;
187  }
188 
189  if (!ptrSource->acquire())
190  {
191  continue;
192  }
193 
194  T* data = (T*)ptr->getDataPointer();
195  T* dataSource = (T*)ptrSource->getDataPointer();
196 
197  std::memcpy(data, dataSource, _tileSize * _tileSize * sizeof(T));
198  }
199  }
200 
201  return true;
202  }
203 
204  bool assign(const aliceVision::image::Image<T>& input, const BoundingBox& inputBb, const BoundingBox& outputBb)
205  {
206  BoundingBox outputMemoryBb;
207  outputMemoryBb.left = 0;
208  outputMemoryBb.top = 0;
209  outputMemoryBb.width = _width;
210  outputMemoryBb.height = _height;
211 
212  if (!outputBb.isInside(outputMemoryBb))
213  {
214  return false;
215  }
216 
217  BoundingBox inputMemoryBb;
218  inputMemoryBb.left = 0;
219  inputMemoryBb.top = 0;
220  inputMemoryBb.width = input.width();
221  inputMemoryBb.height = input.height();
222 
223  if (!inputBb.isInside(inputMemoryBb))
224  {
225  return false;
226  }
227 
228  if (inputBb.width != outputBb.width)
229  {
230  return false;
231  }
232 
233  if (inputBb.height != outputBb.height)
234  {
235  return false;
236  }
237 
238  // Make sure we have our bounding box aligned with the tiles
239  BoundingBox snapedBb = outputBb;
240  snapedBb.snapToGrid(_tileSize);
241 
242  // Compute grid parameters
243  BoundingBox gridBb;
244  gridBb.left = snapedBb.left / _tileSize;
245  gridBb.top = snapedBb.top / _tileSize;
246  gridBb.width = snapedBb.width / _tileSize;
247  gridBb.height = snapedBb.height / _tileSize;
248 
249  int delta_y = outputBb.top - snapedBb.top;
250  int delta_x = outputBb.left - snapedBb.left;
251 
252  for (int i = 0; i < gridBb.height; i++)
253  {
254  // ibb.top + i * tileSize --> snapedBb.top + delta + i * tileSize
255  int ti = gridBb.top + i;
256  int oy = ti * _tileSize;
257  int sy = inputBb.top - delta_y + i * _tileSize;
258 
259  RowType& row = _tilesArray[ti];
260 
261  for (int j = 0; j < gridBb.width; j++)
262  {
263  int tj = gridBb.left + j;
264  int ox = tj * _tileSize;
265  int sx = inputBb.left - delta_x + j * _tileSize;
266 
267  image::CachedTile::smart_pointer ptr = row[tj];
268  if (!ptr)
269  {
270  continue;
271  }
272 
273  if (!ptr->acquire())
274  {
275  continue;
276  }
277 
278  T* data = (T*)ptr->getDataPointer();
279 
280  for (int y = 0; y < _tileSize; y++)
281  {
282  for (int x = 0; x < _tileSize; x++)
283  {
284  if (sy + y < inputBb.top || sy + y > inputBb.getBottom())
285  continue;
286  if (sx + x < inputBb.left || sx + x > inputBb.getRight())
287  continue;
288  if (oy + y < outputBb.top || oy + y > outputBb.getBottom())
289  continue;
290  if (ox + x < outputBb.left || ox + x > outputBb.getRight())
291  continue;
292 
293  data[y * _tileSize + x] = input(sy + y, sx + x);
294  }
295  }
296  }
297  }
298 
299  return true;
300  }
301 
302  bool extract(aliceVision::image::Image<T>& output, const BoundingBox& outputBb, const BoundingBox& inputBb)
303  {
304  BoundingBox thisBb;
305  thisBb.left = 0;
306  thisBb.top = 0;
307  thisBb.width = _width;
308  thisBb.height = _height;
309 
310  if (!inputBb.isInside(thisBb))
311  {
312  return false;
313  }
314 
315  BoundingBox outputMemoryBb;
316  outputMemoryBb.left = 0;
317  outputMemoryBb.top = 0;
318  outputMemoryBb.width = output.width();
319  outputMemoryBb.height = output.height();
320 
321  if (!outputBb.isInside(outputMemoryBb))
322  {
323  return false;
324  }
325 
326  if (inputBb.width != outputBb.width)
327  {
328  return false;
329  }
330 
331  if (inputBb.height != outputBb.height)
332  {
333  return false;
334  }
335 
336  BoundingBox snapedBb = inputBb;
337  snapedBb.snapToGrid(_tileSize);
338 
339  BoundingBox gridBb;
340  gridBb.left = snapedBb.left / _tileSize;
341  gridBb.top = snapedBb.top / _tileSize;
342  gridBb.width = snapedBb.width / _tileSize;
343  gridBb.height = snapedBb.height / _tileSize;
344 
345  int delta_y = inputBb.top - snapedBb.top;
346  int delta_x = inputBb.left - snapedBb.left;
347 
348  for (int i = 0; i < gridBb.height; i++)
349  {
350  int ti = gridBb.top + i;
351  int oy = ti * _tileSize;
352  int sy = outputBb.top - delta_y + i * _tileSize;
353 
354  RowType& row = _tilesArray[ti];
355 
356  for (int j = 0; j < gridBb.width; j++)
357  {
358  int tj = gridBb.left + j;
359  int ox = tj * _tileSize;
360  int sx = outputBb.left - delta_x + j * _tileSize;
361 
362  image::CachedTile::smart_pointer ptr = row[tj];
363  if (!ptr)
364  {
365  continue;
366  }
367 
368  if (!ptr->acquire())
369  {
370  continue;
371  }
372 
373  T* data = (T*)ptr->getDataPointer();
374 
375  for (int y = 0; y < _tileSize; y++)
376  {
377  for (int x = 0; x < _tileSize; x++)
378  {
379  if (sy + y < outputBb.top || sy + y > outputBb.getBottom())
380  continue;
381  if (sx + x < outputBb.left || sx + x > outputBb.getRight())
382  continue;
383  if (oy + y < inputBb.top || oy + y > inputBb.getBottom())
384  continue;
385  if (ox + x < inputBb.left || ox + x > inputBb.getRight())
386  continue;
387 
388  output(sy + y, sx + x) = data[y * _tileSize + x];
389  }
390  }
391  }
392  }
393 
394  return true;
395  }
396 
397  static bool getTileAsImage(image::Image<T>& ret, image::CachedTile::smart_pointer tile)
398  {
399  if (!tile)
400  {
401  return false;
402  }
403 
404  if (!tile->acquire())
405  {
406  return false;
407  }
408 
409  ret.resize(tile->getTileWidth(), tile->getTileHeight());
410  T* data = (T*)tile->getDataPointer();
411  for (int i = 0; i < tile->getTileHeight(); i++)
412  {
413  for (int j = 0; j < tile->getTileWidth(); j++)
414  {
415  ret(i, j) = *data;
416  data++;
417  }
418  }
419 
420  return true;
421  }
422 
423  static bool setTileWithImage(image::CachedTile::smart_pointer tile, const image::Image<T>& ret)
424  {
425  if (ret.width() != tile->getTileWidth())
426  {
427  return false;
428  }
429 
430  if (ret.height() != tile->getTileHeight())
431  {
432  return false;
433  }
434 
435  if (!tile)
436  {
437  return false;
438  }
439 
440  if (!tile->acquire())
441  {
442  return false;
443  }
444 
445  T* data = (T*)tile->getDataPointer();
446  for (int i = 0; i < tile->getTileHeight(); i++)
447  {
448  for (int j = 0; j < tile->getTileWidth(); j++)
449  {
450  *data = ret(i, j);
451  data++;
452  }
453  }
454 
455  return true;
456  }
457 
458  bool fill(const T& val)
459  {
460  if (!perPixelOperation([val](T) -> T { return val; }))
461  {
462  return false;
463  }
464 
465  return true;
466  }
467 
468  std::vector<RowType>& getTiles() { return _tilesArray; }
469 
470  int getWidth() const { return _width; }
471 
472  int getHeight() const { return _height; }
473 
474  int getTileSize() const { return _tileSize; }
475 
476  private:
477  int _width;
478  int _height;
479  int _memoryWidth;
480  int _memoryHeight;
481  int _tileSize;
482 
483  std::vector<RowType> _tilesArray;
484 };
485 
486 template<>
487 bool CachedImage<image::RGBAfColor>::writeImage(const std::string& path, const image::EStorageDataType& storageDataType);
488 
489 template<>
490 bool CachedImage<image::RGBfColor>::writeImage(const std::string& path, const image::EStorageDataType& storageDataType);
491 
492 template<>
493 bool CachedImage<IndexT>::writeImage(const std::string& path, const image::EStorageDataType& storageDataType);
494 
495 template<>
496 bool CachedImage<float>::writeImage(const std::string& path, const image::EStorageDataType& storageDataType);
497 
498 template<>
499 bool CachedImage<unsigned char>::writeImage(const std::string& path, const image::EStorageDataType& storageDataType);
500 
501 } // namespace aliceVision
aliceVision::BoundingBox
Definition: boundingBox.hpp:17
aliceVision::CachedImage
Definition: cachedImage.hpp:21
aliceVision
Definition: checkerDetector.cpp:32
aliceVision::image::Image
Definition: ImageDescriber_AKAZE_OCV.hpp:21
aliceVision::image::Image::width
int width() const
Retrieve the width of the image.
Definition: Image.hpp:110
aliceVision::image::Image::height
int height() const
Retrieve the height of the image.
Definition: Image.hpp:116
aliceVision::image::Image::resize
void resize(int width, int height, bool fInit=true, const T val=T())
Change geometry of image.
Definition: Image.hpp:95