FotoSHOCK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Pages
ImageBuffer.hpp
1 /*
2  * Copyright 2011, 2012 Lukas Jirkovsky
3  *
4  * This file is part of FotoSHOCKcore.
5  *
6  * FotoSHOCKcore is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, version 3 of the License.
9  *
10  * FotoSHOCKcore is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with FotoSHOCKcore. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #ifndef IMAGEBUFFER_H
20 #define IMAGEBUFFER_H
21 
22 #include "ImageBufferBase.hpp"
23 #include "Tile.hpp"
24 
25 #include <cmath>
26 
27 namespace FotoSHOCKcore{
28 
29 // Forward declaration to make iterator available to ImageBuffer declaration
30 template <ValueType::Enum PixelFormat> class ImageBufferIterator;
31 
33 
38 template <ValueType::Enum PixelFormat>
39 class ImageBuffer : public ImageBufferBase {
40  public:
41  friend class ImageBufferIterator<PixelFormat>;
42 
44 
53  ImageBuffer(unsigned int width, unsigned int height, PixelData pixelData, unsigned int tileExtent, bool allocateTiles = true);
55 
60  // TODO: throw an exception in case of error
63 
66  virtual ~ImageBuffer();
67 
69 
76 
78 
86  void setStamp (long stamp);
87 
89 
97  Tile<PixelFormat>* getTile(unsigned int horizontal, unsigned int vertical);
99 
106  Tile<PixelFormat>* getTileFromPos(unsigned int x, unsigned int y);
107 
109 
113 
114  // NOTE: all iterator related functions are defined AFTER the ImageBufferIterator definition
116 
121 
126 
131  Iterator getIterator(unsigned int x, unsigned int y);
132  private:
133  Tile<PixelFormat> ***m_tileGrid;
134 };
135 
136 template <ValueType::Enum PixelFormat>
137 ImageBuffer<PixelFormat>::ImageBuffer (unsigned int width, unsigned int height, PixelData pixelData, unsigned int tileExtent, bool allocateTiles) {
138  // ensure that the tileExtent is power of two
139  assert((tileExtent & (tileExtent - 1)) == 0);
140 
141  m_width = width;
142  m_height = height;
143  m_tileExtent = tileExtent;
144  m_numOfTilesHorizontal = std::ceil((double) width/(double) tileExtent);
145  m_numOfTilesVertical = std::ceil((double) height/(double) tileExtent);
146  m_pixelData = pixelData;
147 
148  m_tileGrid = new Tile<PixelFormat>** [m_numOfTilesVertical+1];
149  for (unsigned int i = 0; i < m_numOfTilesVertical; i++) {
150  m_tileGrid[i] = new Tile<PixelFormat>* [m_numOfTilesHorizontal];
151  for (unsigned int j = 0; j < m_numOfTilesHorizontal; j++) {
152  if (allocateTiles) {
153  m_tileGrid[i][j] = new Tile<PixelFormat>(m_tileExtent, m_pixelData.numOfBands());
154  } else {
155  m_tileGrid[i][j] = 0;
156  }
157  }
158  }
159  // Add one small tile after the last valid tilewhich acts as a sentinel
160  // This tile is used with ImageBufferIterator and lowerRight()
161  m_tileGrid[m_numOfTilesVertical] = new Tile<PixelFormat>* [1];
162  m_tileGrid[m_numOfTilesVertical][0] = new Tile<PixelFormat>(1, m_pixelData.numOfBands());
163 }
164 
165 template <ValueType::Enum PixelFormat>
167  m_width = other.m_width;
168  m_height = other.m_height;
169  m_tileExtent = other.m_tileExtent;
170  m_numOfTilesHorizontal = other.m_numOfTilesHorizontal;
171  m_numOfTilesVertical = other.m_numOfTilesVertical;
172  m_pixelData = other.m_pixelData;
173 
174  m_tileGrid = new Tile<PixelFormat>** [m_numOfTilesVertical+1];
175  for (unsigned int i = 0; i < m_numOfTilesVertical; i++) {
176  m_tileGrid[i] = new Tile<PixelFormat>* [m_numOfTilesHorizontal];
177  for (unsigned int j = 0; j < m_numOfTilesHorizontal; j++) {
178  if (other.m_tileGrid[i][j]) {
179  m_tileGrid[i][j] = new Tile<PixelFormat>(*(other.m_tileGrid[i][j]));
180  } else {
181  m_tileGrid[i][j] = 0;
182  }
183  }
184  }
185  // Add one small tile after the last valid tile, which acts as a sentinel
186  // This tile is used with ImageBufferIterator and lowerRight()
187  m_tileGrid[m_numOfTilesVertical] = new Tile<PixelFormat>* [1];
188  m_tileGrid[m_numOfTilesVertical][0] = new Tile<PixelFormat>(1, m_pixelData.numOfBands());
189 }
190 
191 template <ValueType::Enum PixelFormat>
193  for (unsigned int i = 0; i < m_numOfTilesVertical; i++) {
194  // free all allocated tiles
195  for (unsigned int j = 0; j < m_numOfTilesHorizontal; j++) {
196  if (m_tileGrid[i][j]) {
197  delete m_tileGrid[i][j];
198  }
199  }
200  // free the row
201  delete[] m_tileGrid[i];
202  }
203  // delete the sentinel
204  delete m_tileGrid[m_numOfTilesVertical][0];
205  delete[] m_tileGrid[m_numOfTilesVertical];
206  // delete the grid
207  delete[] m_tileGrid;
208 }
209 
210 template <ValueType::Enum PixelFormat>
212  if (this != &other) {
213  if (m_width == other.m_width && m_height == other.m_height &&
214  m_tileExtent == other.m_tileExtent && m_pixelData.numOfBands() == other.m_pixelData.numOfBands())
215  {
216  // we can use the tile copy operator to copy the Tile content directly
217  // because it does only memcpy in this case, it should be exception-safe
218  for (unsigned int i = 0; i < m_numOfTilesVertical; i++) {
219  for (unsigned int j = 0; j < m_numOfTilesHorizontal; j++) {
220  if (other.m_tileGrid[i][j]) {
221  *m_tileGrid[i][j] = *(other.m_tileGrid[i][j]);
222  } else {
223  m_tileGrid[i][j] = 0;
224  }
225  }
226  }
227  // even though the Tile data was be copied directly, the PixelData may be different
228  // (eg. only colorspace is different), so copy PixelData too
229  m_pixelData = other.m_pixelData;
230  } else {
231  // uses copy constructor and std::swap to make the operator= exception safe
232  ImageBuffer<PixelFormat> tmp(other);
233 
234  std::swap(m_width, tmp.m_width);
235  std::swap(m_height, tmp.m_height);
236  std::swap(m_tileExtent, tmp.m_tileExtent);
237  std::swap(m_numOfTilesHorizontal, tmp.m_numOfTilesHorizontal);
238  std::swap(m_numOfTilesVertical, tmp.m_numOfTilesVertical);
239  std::swap(m_pixelData, tmp.m_pixelData);
240  std::swap(m_tileGrid, tmp.m_tileGrid);
241  }
242  }
243 
244  return *this;
245 }
246 
247 template <ValueType::Enum PixelFormat>
249  for (unsigned int i = 0; i < m_numOfTilesVertical; i++) {
250  for (unsigned int j = 0; j < m_numOfTilesHorizontal; j++) {
251  if (m_tileGrid[i][j]) {
252  m_tileGrid[i][j]->setStamp(stamp);
253  }
254  }
255  }
256 }
257 
258 template <ValueType::Enum PixelFormat>
259 Tile<PixelFormat>* ImageBuffer<PixelFormat>::getTile(unsigned int horizontal, unsigned int vertical) {
260  if (m_tileGrid[vertical][horizontal] == 0) {
261  m_tileGrid[vertical][horizontal] = new Tile<PixelFormat>(m_tileExtent, m_pixelData.numOfBands());
262  }
263  return m_tileGrid[vertical][horizontal];
264 }
265 
266 template <ValueType::Enum PixelFormat>
268  // get the position in the tile grid
269  unsigned int horiz = x / m_tileExtent;
270  unsigned int vert = y / m_tileExtent;
271 
272  if (m_tileGrid[vert][horiz] == 0) {
273  m_tileGrid[vert][horiz] = new Tile<PixelFormat>(m_tileExtent, m_pixelData.numOfBands());
274  }
275  return m_tileGrid[vert][horiz];
276 }
277 
279 
284 template <ValueType::Enum PixelFormat>
285 class ImageBufferIterator{
286  public:
287  typedef typename ValueTypeInfo<PixelFormat>::Type format;
288 
290 
297 
303 
305 
309 
311 
316  bool operator==(const ImageBufferIterator<PixelFormat> &other) const;
318 
323  bool operator!=(const ImageBufferIterator<PixelFormat> &other) const;
324 
326 
333 
338 
343  ImageBufferIterator<PixelFormat>& moveTo(unsigned int x, unsigned int y);
344 
346 
349  format* operator*();
351 
354  const format* operator*() const;
355 
357 
365  format* operator()(unsigned int x, unsigned int y);
367 
375  const format* operator()(unsigned int x, unsigned int y) const;
376 
378 
382  format& operator[](unsigned int n);
384 
388  const format operator[](unsigned int n) const;
389 
391 
395  format getValue(unsigned int band) const;
397 
401  void setValue(unsigned int band, format value);
402 
404 
409  const unsigned int getX() const;
411 
416  const unsigned int getY() const;
417  private:
418  typedef typename Tile<PixelFormat>::Iterator TileIterator;
419 
420  TileIterator** m_tileIteratorGrid;
421  TileIterator* m_currentIterator;
422 
423  unsigned int m_currentTileHorizPos;
424  unsigned int m_currentTileVertPos;
425  unsigned int m_currentXoffset;
426  unsigned int m_currentYoffset;
427  unsigned int m_currentXpos;
428  unsigned int m_currentYpos;
429 
430  unsigned int m_width;
431  unsigned int m_tileExtent;
432  unsigned int m_power; // stores the n from "2^n = m_tileExtent"
433 
434  // number of tiles in each dimension
435  unsigned int m_horiz;
436  unsigned int m_vert;
437 };
438 
439 template <ValueType::Enum PixelFormat>
441  // allocate TileIterator grid
442  m_horiz = buffer->getNumOfTilesHoriz();
443  m_vert = buffer->getNumOfTilesVert();
444  // make the space for one iterator after the last valid iterator to make lowerRight() working
445  m_tileIteratorGrid = new TileIterator* [m_vert+1];
446  for (unsigned int i = 0; i < m_vert; i++) {
447  m_tileIteratorGrid[i] = new TileIterator[m_horiz];
448  for (unsigned int j = 0; j < m_horiz; j++) {
449  m_tileIteratorGrid[i][j] = buffer->getTile(j, i)->upperLeft();
450  }
451  }
452  // add sentinel
453  m_tileIteratorGrid[m_vert] = new TileIterator [1];
454  m_tileIteratorGrid[m_vert][0] = buffer->getTile(0, m_vert)->upperLeft();
455 
456  // set dimensions
457  m_width = buffer->getWidth();
458  m_tileExtent = buffer->m_tileExtent;
459  // find which power of the the tileExtent is
460  m_power = 0;
461  for (unsigned int tmp = m_tileExtent; tmp > 1; tmp >>= 1) {
462  m_power++;
463  }
464 
465  // set the iterator to the first pixel of a first Tile
466  m_currentIterator = &m_tileIteratorGrid[0][0];
467  m_currentTileHorizPos = 0;
468  m_currentTileVertPos = 0;
469  m_currentXoffset = 0;
470  m_currentYoffset = 0;
471  m_currentXpos = 0;
472  m_currentYpos = 0;
473 }
474 
475 template <ValueType::Enum PixelFormat>
477  // allocate TileIterator grid
478  m_horiz = other.m_horiz;
479  m_vert = other.m_vert;
480  // make the space for one iterator after the last valid iterator to make lowerRight() working
481  m_tileIteratorGrid = new TileIterator* [m_vert+1];
482  for (unsigned int i = 0; i < m_vert; i++) {
483  m_tileIteratorGrid[i] = new TileIterator[m_horiz];
484  for (unsigned int j = 0; j < m_horiz; j++) {
485  m_tileIteratorGrid[i][j] = TileIterator(other.m_tileIteratorGrid[i][j]);
486  }
487  }
488  // add sentinel
489  m_tileIteratorGrid[m_vert] = new TileIterator [1];
490  m_tileIteratorGrid[m_vert][0] = TileIterator(other.m_tileIteratorGrid[m_vert][0]);
491 
492  // set dimensions
493  m_width = other.m_width;
494  m_tileExtent = other.m_tileExtent;
495  m_power = other.m_power;
496 
497  m_currentTileHorizPos = other.m_currentTileHorizPos;
498  m_currentTileVertPos = other.m_currentTileVertPos;
499  m_currentXoffset = other.m_currentXoffset;
500  m_currentYoffset = other.m_currentYoffset;
501  m_currentXpos = other.m_currentXpos;
502  m_currentYpos = other.m_currentYpos;
503  // set the current iterator to a correct place
504  m_currentIterator = &m_tileIteratorGrid[m_currentTileVertPos][m_currentTileHorizPos];
505  m_currentIterator->moveTo(m_currentXoffset, m_currentYoffset);
506 }
507 
508 template <ValueType::Enum PixelFormat>
510  for (unsigned int i = 0; i < m_vert; i++) {
511  delete[] m_tileIteratorGrid[i];
512  }
513  // delete sentinel
514  delete[] m_tileIteratorGrid[m_vert];
515  // delete the grid
516  delete[] m_tileIteratorGrid;
517 }
518 
519 template <ValueType::Enum PixelFormat>
521  if (this != &other) {
523 
524  std::swap(m_horiz, tmp.m_horiz);
525  std::swap(m_vert, tmp.m_vert);
526  std::swap(m_tileIteratorGrid, tmp.m_tileIteratorGrid);
527  std::swap(m_width, tmp.m_width);
528  std::swap(m_tileExtent, tmp.m_tileExtent);
529  std::swap(m_power, tmp.m_power);
530  std::swap(m_currentIterator, tmp.m_currentIterator);
531  std::swap(m_currentTileHorizPos, tmp.m_currentTileHorizPos);
532  std::swap(m_currentTileVertPos, tmp.m_currentTileVertPos);
533  std::swap(m_currentXoffset, tmp.m_currentXoffset);
534  std::swap(m_currentYoffset, tmp.m_currentYoffset);
535  std::swap(m_currentXpos, tmp.m_currentXpos);
536  std::swap(m_currentYpos, tmp.m_currentYpos);
537  }
538 
539  return *this;
540 }
541 
542 template <ValueType::Enum PixelFormat>
544  m_currentXoffset++;
545  m_currentXpos++;
546  if (m_currentXpos >= m_width) {
547  // move to the next line
548  m_currentTileHorizPos = 0;
549  m_currentXoffset = 0;
550 
551  m_currentXpos = 0;
552  m_currentYpos++;
553 
554  m_currentYoffset++;
555 
556  // move to the next row of tiles
557  if (m_currentYoffset >= m_tileExtent) {
558  m_currentYoffset = 0;
559  m_currentTileVertPos++;
560  }
561  m_currentIterator = &m_tileIteratorGrid[m_currentTileVertPos][m_currentTileHorizPos];
562  m_currentIterator->moveTo(m_currentXoffset, m_currentYoffset);
563  } else if (m_currentXoffset >= m_tileExtent) {
564  m_currentTileHorizPos++;
565  // move to the next tile
566  m_currentXoffset = 0;
567 
568  m_currentIterator = &m_tileIteratorGrid[m_currentTileVertPos][m_currentTileHorizPos];
569  m_currentIterator->moveTo(m_currentXoffset, m_currentYoffset);
570  } else {
571  ++(*m_currentIterator);
572  }
573 
574  return *this;
575 }
576 
577 template <ValueType::Enum PixelFormat>
579  // I'm in the leftmost position of a Tile
580  if (m_currentXoffset == 0) {
581  // I'm in the leftmost Tile
582  if (m_currentTileHorizPos == 0) {
583  m_currentXoffset = (m_width - 1) & (m_tileExtent - 1);
584  m_currentTileHorizPos = m_horiz - 1;
585  m_currentXpos = m_width - 1;
586  m_currentYpos--;
587 
588  if (m_currentYoffset == 0) {
589  if (m_currentTileVertPos != 0) {
590  // move to the previous row
591  m_currentTileVertPos--;
592  m_currentYoffset = m_tileExtent - 1;
593  }
594  } else {
595  // move to the previous row of Tiles
596  m_currentYoffset--;
597  }
598  } else {
599  m_currentXoffset = m_tileExtent - 1;
600  m_currentXpos--;
601  m_currentTileHorizPos--;
602  }
603 
604  m_currentIterator = &m_tileIteratorGrid[m_currentTileVertPos][m_currentTileHorizPos];
605  m_currentIterator->moveTo(m_currentXoffset, m_currentYoffset);
606  } else {
607  m_currentXpos--;
608  m_currentXoffset--;
609  --(*m_currentIterator);
610  }
611 
612  return *this;
613 }
614 
615 template <ValueType::Enum PixelFormat>
617  // NOTE: this might be improved that in the case of a small movement there is no division
618  m_currentTileHorizPos = x >> m_power;
619  m_currentTileVertPos = y >> m_power;
620  m_currentXoffset = x & (m_tileExtent - 1);
621  m_currentYoffset = y & (m_tileExtent - 1);
622  m_currentXpos = x;
623  m_currentYpos = y;
624 
625  m_currentIterator = &m_tileIteratorGrid[m_currentTileVertPos][m_currentTileHorizPos];
626  m_currentIterator->moveTo(m_currentXoffset, m_currentYoffset);
627 
628  return *this;
629 }
630 
631 template <ValueType::Enum PixelFormat>
632 typename ImageBufferIterator<PixelFormat>::format* ImageBufferIterator<PixelFormat>::operator*() {
633  return **m_currentIterator;
634 }
635 
636 template <ValueType::Enum PixelFormat>
637 const typename ImageBufferIterator<PixelFormat>::format* ImageBufferIterator<PixelFormat>::operator*() const {
638  return **m_currentIterator;
639 }
640 
641 template <ValueType::Enum PixelFormat>
642 typename ImageBufferIterator<PixelFormat>::format* ImageBufferIterator<PixelFormat>::operator()(unsigned int x, unsigned int y) {
643  unsigned int tileHorizPos = x >> m_power;
644  unsigned int tileVertPos = y >> m_power;
645  unsigned int Xoffset = x & (m_tileExtent - 1);
646  unsigned int Yoffset = y & (m_tileExtent - 1);
647 
648  return m_tileIteratorGrid[tileVertPos][tileHorizPos].operator()(Xoffset, Yoffset);
649 }
650 
651 template <ValueType::Enum PixelFormat>
652 const typename ImageBufferIterator<PixelFormat>::format* ImageBufferIterator<PixelFormat>::operator()(unsigned int x, unsigned int y) const {
653  unsigned int tileHorizPos = x >> m_power;
654  unsigned int tileVertPos = y >> m_power;
655  unsigned int Xoffset = x & (m_tileExtent - 1);
656  unsigned int Yoffset = y & (m_tileExtent - 1);
657 
658  return m_tileIteratorGrid[tileVertPos][tileHorizPos].operator()(Xoffset, Yoffset);
659 }
660 
661 template <ValueType::Enum PixelFormat>
662 typename ImageBufferIterator<PixelFormat>::format& ImageBufferIterator<PixelFormat>::operator[](unsigned int n) {
663  return (*m_currentIterator)[n];
664 }
665 
666 template <ValueType::Enum PixelFormat>
667 const typename ImageBufferIterator<PixelFormat>::format ImageBufferIterator<PixelFormat>::operator[](unsigned int n) const {
668  return (*m_currentIterator)[n];
669 }
670 
671 template <ValueType::Enum PixelFormat>
672 typename ImageBufferIterator<PixelFormat>::format ImageBufferIterator<PixelFormat>::getValue(unsigned int band) const {
673  return m_currentIterator->getValue(band);
674 }
675 
676 template <ValueType::Enum PixelFormat>
677 void ImageBufferIterator<PixelFormat>::setValue(unsigned int band, typename ImageBufferIterator<PixelFormat>::format value) {
678  m_currentIterator->setValue(band, value);
679 }
680 
681 
682 template <ValueType::Enum PixelFormat>
683 const unsigned int ImageBufferIterator<PixelFormat>::getX() const {
684  return m_currentXpos;
685 }
686 
687 template <ValueType::Enum PixelFormat>
688 const unsigned int ImageBufferIterator<PixelFormat>::getY() const {
689  return m_currentYpos;
690 }
691 
692 template <ValueType::Enum PixelFormat>
694  return *m_currentIterator == *(other.m_currentIterator);
695 }
696 
697 template <ValueType::Enum PixelFormat>
699  return *m_currentIterator != *(other.m_currentIterator);
700 }
701 
702 
703 template <ValueType::Enum PixelFormat>
706 }
707 
708 template <ValueType::Enum PixelFormat>
710  ImageBufferIterator<PixelFormat> iterator(this);
711  // move to the pixel after the last valid pixel
712  iterator.moveTo(0, m_height);
713  return iterator;
714 }
715 
716 template <ValueType::Enum PixelFormat>
718  ImageBufferIterator<PixelFormat> iterator(this);
719  iterator.moveTo(x, y);
720  return iterator;
721 }
722 
723 }
724 
725 #endif