Signal/Geometry Processing Library (SPL)  1.1.24
Sequence2.hpp
Go to the documentation of this file.
1 // Copyright (c) 2011 Michael D. Adams
2 // All rights reserved.
3 
4 // __START_OF_LICENSE__
5 //
6 // Copyright (c) 2015 Michael D. Adams
7 // All rights reserved.
8 //
9 // This file is part of the Signal Processing Library (SPL).
10 //
11 // This program is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU General Public License as
13 // published by the Free Software Foundation; either version 3,
14 // or (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public
22 // License along with this program; see the file LICENSE. If not,
23 // see <http://www.gnu.org/licenses/>.
24 //
25 // __END_OF_LICENSE__
26 
32 #ifndef SPL_Sequence2_hpp
33 #define SPL_Sequence2_hpp
34 
36 // Configuration
38 
40 //#define SPL_SEQUENCE2_DEBUG
41 
43 #define SPL_SEQUENCE2_USE_NEW_CONV
44 
45 #if defined(SPL_SEQUENCE2_DEBUG)
46 #define SPL_SEQUENCE2_INLINE
48 #else
49 #define SPL_SEQUENCE2_INLINE inline
51 #endif
52 
54 // Include files.
56 
57 #include <SPL/config.hpp>
58 #include <iostream>
59 #include <vector>
60 #include <SPL/Array2.hpp>
61 #include <SPL/Sequence.hpp>
62 #include <SPL/Sequence1.hpp>
63 #include <SPL/Sequence.hpp>
64 #include <SPL/math.hpp>
65 
66 namespace SPL {
67 
69 // Types.
71 
82 template <class T>
83 class Sequence2
84 {
85 public:
86 
88  // Types
90 
92  typedef T ElemType;
93 
96 
98  typedef typename Array2<T>::Iterator Iterator;
99 
102 
104  typedef typename Array2<T>::XIterator XIterator;
105 
108 
110  typedef typename Array2<T>::YIterator YIterator;
111 
113  // Constructors and destructor
115 
119  Sequence2();
120 
124  Sequence2(int startX, int startY, int width, int height);
125 
130  Sequence2(int startX, int startY, int width, int height, const T& data);
131 
136  template <class InputIterator>
137  Sequence2(int startX, int startY, int width, int height,
138  InputIterator data);
139 
143  Sequence2(const Sequence2& f);
144 
149  template <class OtherT>
150  Sequence2(const Sequence2<OtherT>& f);
151 
155  Sequence2(const Array2<T>& data);
156 
160  Sequence2(int startX, int startY, const Array2<T>& data);
161 
165  ~Sequence2();
166 
168  // Assignment operators
170 
174  Sequence2& operator=(const Sequence2& f);
175 
182  template <class OtherT>
184 
186  // Compound assignment operators
188 
192  Sequence2& operator+=(const Sequence2& f);
193 
197  Sequence2& operator-=(const Sequence2& f);
198 
202  Sequence2& operator*=(const Sequence2& f);
203 
207  Sequence2& operator/=(const Sequence2& f);
208 
212  Sequence2& operator+=(const T& value);
213 
217  Sequence2& operator-=(const T& value);
218 
222  Sequence2& operator*=(const T& value);
223 
227  Sequence2& operator/=(const T& value);
228 
230  // Basic queries
232 
236  int getStartX() const;
237 
241  int getStartY() const;
242 
246  int getEndX() const;
247 
251  int getEndY() const;
252 
256  int getWidth() const;
257 
261  int getHeight() const;
262 
266  int getSize() const;
267 
271  bool isShared() const;
272 
274  // Accessors
276 
280  T& operator()(int x, int y);
281 
285  const T& operator()(int x, int y) const;
286 
288  // Iterators
290 
294  ConstIterator begin() const;
295 
299  Iterator begin();
300 
305  ConstIterator end() const;
306 
311  Iterator end();
312 
317  ConstXIterator rowBegin(int y) const;
318 
323  XIterator rowBegin(int y);
324 
329  ConstXIterator rowEnd(int y) const;
330 
335  XIterator rowEnd(int y);
336 
341  ConstYIterator colBegin(int x) const;
342 
347  YIterator colBegin(int x);
348 
353  ConstYIterator colEnd(int x) const;
354 
359  YIterator colEnd(int x);
360 
362  // Resizing
364 
366  // Get various statistics
368 
374  T min() const;
375 
381  T max() const;
382 
386  T sum() const;
387 
389  // Input/ouput
391 
396  std::ostream& output(std::ostream& out, int fieldWidth) const;
397 
399  // Miscellaneous
401 
405  Array2<T> getArray() const;
406 
410  void swapArray(Array2<T>& data);
411 
415  void fill(const T& value);
416 
420  Sequence2& translate(int x, int y);
421 
422 private:
423 
424  template <class> friend class Sequence2;
425 
426  template <class U>
427  friend std::ostream& operator<<(std::ostream& out, const Sequence2<U>&);
428  template <class U>
429  friend Sequence2<U> translate(const Sequence2<U>&, int x, int y);
430 
432  typedef Array2<T> Array;
433 
435  int startX_;
436 
438  int startY_;
439 
441  Array data_;
442 
443 };
444 
446 //
448 
450 
457 void combineDomains(int firstStartX, int firstStartY, int firstEndX,
458  int firstEndY, int secondStartX, int secondStartY, int secondEndX,
459  int secondEndY, int& startX, int& startY, int& endX, int& endY);
460 
462 
464 // Constructors and destructor
466 
467 template <class T>
469  data_()
470 {
471 }
472 
473 template <class T>
475  int width, int height) : startX_(startX), startY_(startY),
476  data_(width, height)
477 {
478  assert(width >= 0 && height >= 0);
479 }
480 
481 template <class T>
483  int width, int height, const T& value) : startX_(startX), startY_(startY),
484  data_(width, height, value)
485 {
486  assert(width >= 0 && height >= 0);
487 }
488 
489 template <class T>
490 template <class InputIterator>
491 SPL_SEQUENCE2_INLINE Sequence2<T>::Sequence2(int startX, int startY,
492  int width, int height, InputIterator data) : startX_(startX),
493  startY_(startY), data_(width, height, data)
494 {
495  assert(width >= 0 && height >= 0);
496  assert(getWidth() == width && getHeight() == height);
497 }
498 
499 template <class T>
501  startX_(f.startX_), startY_(f.startY_), data_(f.data_)
502 {
503 }
504 
505 template <class T>
507  startX_(0), startY_(0), data_(data)
508 {
509 }
510 
511 template <class T>
513  const Array2<T>& data) :
514  startX_(startX), startY_(startY), data_(data)
515 {
516 }
517 
518 template <class T>
520 {
521 }
522 
523 template <class T>
524 template <class OtherT>
526  startX_(f.startX_), startY_(f.startY_), data_(f.data_)
527 {
528 }
529 
531 // Assignment operators
533 
534 template <class T>
536  const Sequence2<T>& f)
537 {
538  startX_ = f.startX_;
539  startY_ = f.startY_;
540  data_ = f.data_;
541  return *this;
542 }
543 
544 template <class T>
545 template <class OtherT>
547  const Sequence2<OtherT>& f)
548 {
549  startX_ = f.startX_;
550  startY_ = f.startY_;
551  data_ = f.data_;
552  return *this;
553 }
554 
556 // Compound assignment operators
558 
559 template <class T>
561  const Sequence2<T>& f)
562 {
563  // Ensure that both sequences have the same domain.
564  assert((!getSize() && !f.getSize()) ||
565  (getStartX() == f.getStartX() && getEndX() == f.getEndX() &&
566  getStartY() == f.getStartY() && getEndY() == f.getEndY()));
567 
568  data_ += f.data_;
569  return *this;
570 }
571 
572 template <class T>
574  const Sequence2<T>& f)
575 {
576  // Ensure that both sequences have the same domain.
577  assert((!getSize() && !f.getSize()) ||
578  (getStartX() == f.getStartX() && getEndX() == f.getEndX() &&
579  getStartY() == f.getStartY() && getEndY() == f.getEndY()));
580 
581  data_ -= f.data_;
582  return *this;
583 }
584 
585 template <class T>
587  const Sequence2<T>& f)
588 {
589  // Ensure that both sequences have the same domain.
590  assert((!getSize() && !f.getSize()) ||
591  (getStartX() == f.getStartX() && getEndX() == f.getEndX() &&
592  getStartY() == f.getStartY() && getEndY() == f.getEndY()));
593 
594  data_ *= f.data_;
595  return *this;
596 }
597 
598 template <class T>
600  const Sequence2<T>& f)
601 {
602  // Ensure that both sequences have the same domain.
603  assert((!getSize() && !f.getSize()) ||
604  (getStartX() == f.getStartX() && getEndX() == f.getEndX() &&
605  getStartY() == f.getStartY() && getEndY() == f.getEndY()));
606 
607  data_ /= f.data_;
608  return *this;
609 }
610 
611 template <class T>
613  const T& value)
614 {
615  data_ += value;
616  return *this;
617 }
618 
619 template <class T>
621  const T& value)
622 {
623  data_ -= value;
624  return *this;
625 }
626 
627 template <class T>
629  const T& value)
630 {
631  data_ *= value;
632  return *this;
633 }
634 
635 template <class T>
637  const T& value)
638 {
639  data_ /= value;
640  return *this;
641 }
642 
644 // Basic queries
646 
647 template <class T>
649 {
650  return startX_;
651 }
652 
653 template <class T>
655 {
656  return startY_;
657 }
658 
659 template <class T>
661 {
662  return startX_ + getWidth();
663 }
664 
665 template <class T>
667 {
668  return startY_ + getHeight();
669 }
670 
671 template <class T>
673 {
674  return data_.getWidth();
675 }
676 
677 template <class T>
679 {
680  return data_.getHeight();
681 }
682 
683 template <class T>
685 {
686  return data_.getWidth() * data_.getHeight();
687 }
688 
689 template <class T>
691 {
692  return data_.isShared();
693 }
694 
696 // Accessors
698 
699 template <class T>
700 SPL_SEQUENCE2_INLINE const T& Sequence2<T>::operator()(int x, int y) const
701 {
702  assert(x >= startX_ && x < getEndX() && y >= startY_ && y < getEndY());
703  return data_(x - startX_, y - startY_);
704 }
705 
706 template <class T>
708 {
709  assert(x >= startX_ && x < getEndX() && y >= startY_ && y < getEndY());
710  return data_(x - startX_, y - startY_);
711 }
712 
714 // Iterators
716 
717 template <class T>
719  const
720 {
721  return data_.begin();
722 }
723 
724 template <class T>
726 {
727  return data_.begin();
728 }
729 
730 template <class T>
732  const
733 {
734  return data_.end();
735 }
736 
737 template <class T>
739 {
740  return data_.end();
741 }
742 
743 template <class T>
746 {
747  assert(y >= startY_ && y < getEndY());
748  return data_.rowBegin(y - startY_);
749 }
750 
751 template <class T>
754 {
755  assert(y >= startY_ && y < getEndY());
756  return data_.rowBegin(y - startY_);
757 }
758 
759 template <class T>
761  Sequence2<T>::rowEnd(int y) const
762 {
763  assert(y >= startY_ && y < getEndY());
764  return data_.rowEnd(y - startY_);
765 }
766 
767 template <class T>
770 {
771  assert(y >= startY_ && y < getEndY());
772  return data_.rowEnd(y - startY_);
773 }
774 
775 template <class T>
778 {
779  assert(x >= startX_ && x < getEndX());
780  return data_.colBegin(x - startX_);
781 }
782 
783 template <class T>
786 {
787  assert(x >= startX_ && x < getEndX());
788  return data_.colBegin(x - startX_);
789 }
790 
791 template <class T>
793  Sequence2<T>::colEnd(int x) const
794 {
795  assert(x >= startX_ && x < getEndX());
796  return data_.colEnd(x - startX_);
797 }
798 
799 template <class T>
802 {
803  assert(x >= startX_ && x < getEndX());
804  return data_.colEnd(x - startX_);
805 }
806 
808 // Resizing
810 
812 // Get various statistics
814 
815 template <class T>
817 {
818  assert(getSize() > 0);
819  return data_.min();
820 }
821 
822 template <class T>
824 {
825  assert(getSize() > 0);
826  return data_.max();
827 }
828 
829 template <class T>
831 {
832  return data_.sum();
833 }
834 
836 // Input/output
838 
839 template <class T>
840 std::ostream& Sequence2<T>::output(std::ostream& out, int fieldWidth) const
841 {
842  out << startX_ << " " << startY_ << " ";
843  data_.output(out, fieldWidth);
844  return out;
845 }
846 
862 template <class T>
863 std::ostream& operator<<(std::ostream& out, const Sequence2<T>& f)
864 {
865  out << f.getStartX() << " " << f.getStartY() << " ";
866  out << f.data_;
867  return out;
868 }
869 
880 template <class T>
881 std::istream& operator>>(std::istream& in, Sequence2<T>& f)
882 {
883  int startX;
884  int startY;
885  int width;
886  int height;
887  if (!(in >> startX)) {
888  return in;
889  }
890  if (!(in >> startY)) {
891  return in;
892  }
893  if (!(in >> width)) {
894  return in;
895  }
896  if (!(in >> height)) {
897  return in;
898  }
899  typename std::vector<T> data;
900  data.reserve(width * height);
901  for (int y = 0; y < height; ++y) {
902  for (int x = 0; x < width; ++x) {
903  T value;
904  if (!(in >> value)) {
905  return in;
906  }
907  data.push_back(value);
908  }
909  }
910  f = Sequence2<T>(startX, startY, width, height, data.begin());
911  return in;
912 }
913 
915 // Miscellaneous
917 
918 template<class T>
920 {
921  data_.fill(value);
922 }
923 
924 template <class T>
926 {
927  data_.swap(data);
928 }
929 
930 template<class T>
932 {
933  return data_;
934 }
935 
936 template<class T>
938 {
939  startX_ += x;
940  startY_ += y;
941  return *this;
942 }
943 
945 //
947 
955 template <class T>
957  const Sequence2<T>& g)
958 {
959  return Sequence2<T>(f) += g;
960 }
961 
970 template <class T>
972  const Sequence2<T>& g)
973 {
974  return Sequence2<T>(f) -= g;
975 }
976 
984 template <class T>
986  const Sequence2<T>& g)
987 {
988  return Sequence2<T>(f) *= g;
989 }
990 
998 template <class T>
1000  const Sequence2<T>& g)
1001 {
1002  return Sequence2<T>(f) /= g;
1003 }
1004 
1016 template <class T>
1018 {
1019  int startX;
1020  int startY;
1021  int endX;
1022  int endY;
1023  combineDomains(f.getStartX(), f.getStartY(), f.getEndX(), f.getEndY(),
1024  g.getStartX(), g.getStartY(), g.getEndX(), g.getEndY(), startX, startY,
1025  endX, endY);
1026  Sequence2<T> result(startX, startY, endX - startX, endY - startY, T(0));
1027  int xMin = std::max(f.getStartX(), startX);
1028  int xMax = std::min(f.getEndX(), endX) - 1;
1029  int yMin = std::max(f.getStartY(), startY);
1030  int yMax = std::min(f.getEndY(), endY) - 1;
1031  for (int y = yMin; y <= yMax; ++y) {
1032  for (int x = xMin; x <= xMax; ++x) {
1033  result(x, y) += f(x, y);
1034  }
1035  }
1036  xMin = std::max(g.getStartX(), startX);
1037  xMax = std::min(g.getEndX(), endX) - 1;
1038  yMin = std::max(g.getStartY(), startY);
1039  yMax = std::min(g.getEndY(), endY) - 1;
1040  for (int y = yMin; y <= yMax; ++y) {
1041  for (int x = xMin; x <= xMax; ++x) {
1042  result(x, y) += g(x, y);
1043  }
1044  }
1045  return result;
1046 }
1047 
1055 template <class T>
1057  const Sequence2<T>& f)
1058 {
1059  return Sequence2<T>(f) += value;
1060 }
1061 
1069 template <class T>
1071  const T& value)
1072 {
1073  return Sequence2<T>(f) += value;
1074 }
1075 
1083 template <class T>
1085  const T& value)
1086 {
1087  return Sequence2<T>(f) -= value;
1088 }
1089 
1097 template <class T>
1099  const Sequence2<T>& f)
1100 {
1101  return Sequence2<T>(f) *= value;
1102 }
1103 
1111 template <class T>
1113  const T& value)
1114 {
1115  return Sequence2<T>(f) *= value;
1116 }
1117 
1125 template <class T>
1127  const T& value)
1128 {
1129  return Sequence2<T>(f) /= value;
1130 }
1131 
1140 template <class T>
1141 bool operator==(const Sequence2<T>& f, const Sequence2<T>& g)
1142 {
1143  bool result;
1144  if (!f.getSize() && !g.getSize()) {
1145  // Both sequences are empty.
1146  result = true;
1147  } else if (f.getStartX() != g.getStartX() ||
1148  f.getEndX() != g.getEndX() || f.getStartY() != g.getStartY() ||
1149  f.getEndY() != g.getEndY()) {
1150  // The sequences are not defined on the same domain.
1151  result = false;
1152  } else {
1153  // The sequences are defined on the same domain.
1154  result = std::equal(f.begin(), f.end(), g.begin());
1155  }
1156  return result;
1157 }
1158 
1162 template <class T>
1164  const Sequence2<T>& g)
1165 {
1166  return !(f == g);
1167 }
1168 
1172 template <class T>
1174  const Sequence2<T>& g, T threshold = 1e-9)
1175 {
1176  bool result;
1177  if (!f.getSize() && !g.getSize()) {
1178  // Empty sequence.
1179  result = true;
1180  } else if (f.getStartX() != g.getStartX() ||
1181  f.getStartY() != g.getStartY() ||
1182  f.getEndX() != g.getEndX() ||
1183  f.getEndY() != g.getEndY()) {
1184  // Domains do not match.
1185  result = false;
1186  } else {
1187  assert(f.getWidth() == g.getWidth() && f.getHeight() == g.getHeight());
1188  result = true;
1189  typename Sequence2<T>::ConstIterator src = f.begin();
1190  typename Sequence2<T>::ConstIterator dst = g.begin();
1191  while (src != f.end()) {
1192  if (absVal((*src) - (*dst)) > threshold) {
1193  result = false;
1194  break;
1195  }
1196  ++src;
1197  ++dst;
1198  }
1199  }
1200  return result;
1201 }
1202 
1204 //
1206 
1217 template <class T>
1218 Sequence2<T> subsequence(const Sequence2<T>& f, int startX, int startY,
1219  int width, int height)
1220 {
1221  assert(startX >= f.getStartX() && startX + width <= f.getEndX() &&
1222  startY >= f.getStartY() && startY + height <= f.getEndY());
1223  if (!width || !height) {
1224  width = 0;
1225  height = 0;
1226  }
1227  Sequence2<T> result(startX, startY, width, height);
1228  for (int i = 0; i < height; ++i) {
1229  assert(startX - f.getStartX() >= 0);
1230  typename Sequence2<T>::ConstXIterator src =
1231  f.rowBegin(startY + i) + (startX - f.getStartX());
1232  typename Sequence2<T>::XIterator dst = result.rowBegin(startY + i);
1233  SPL::copy_n(src, width, dst);
1234  }
1235  return result;
1236 }
1237 
1247 template <class T>
1249  int deltaX, int deltaY)
1250 {
1251  return Sequence2<T>(f).translate(deltaX, deltaY);
1252 }
1253 
1255 // Convolution
1257 
1259 
1265 template<class T>
1266 SPL_SEQUENCE2_INLINE T getExtSeqValue(const Sequence2<T>& f, int x, int y,
1267  int mode)
1268 {
1269  assert(mode == ConvolveMode::full ||
1274  T value;
1275  switch (mode) {
1276  case ConvolveMode::full:
1278  if (x >= f.getStartX() && x < f.getEndX() &&
1279  y >= f.getStartY() && y < f.getEndY()) {
1280  value = f(x, y);
1281  } else {
1282  value = T(0);
1283  }
1284  break;
1286  if (x < f.getStartX()) {
1287  x = f.getStartX();
1288  } else if (x >= f.getEndX()) {
1289  x = f.getEndX() - 1;
1290  }
1291  if (y < f.getStartY()) {
1292  y = f.getStartY();
1293  } else if (y >= f.getEndY()) {
1294  y = f.getEndY() - 1;
1295  }
1296  value = f(x, y);
1297  break;
1299  if (x < f.getStartX() || x >= f.getEndX()) {
1300  x = f.getStartX() + mod(x - f.getStartX(), f.getWidth());
1301  }
1302  if (y < f.getStartY() || y >= f.getEndY()) {
1303  y = f.getStartY() + mod(y - f.getStartY(), f.getHeight());
1304  }
1305  assert(x >= f.getStartX() && x < f.getEndX());
1306  assert(y >= f.getStartY() && y < f.getEndY());
1307  value = f(x, y);
1308  break;
1310  if (x < f.getStartX() || x >= f.getEndX()) {
1311  int tmp = mod(x - f.getStartX(), 2 * f.getWidth() - 2);
1312  x = f.getStartX() + std::min(tmp, 2 * f.getWidth() - 2 - tmp);
1313  }
1314  if (y < f.getStartY() || y >= f.getEndY()) {
1315  int tmp = mod(y - f.getStartY(), 2 * f.getHeight() - 2);
1316  y = f.getStartY() + std::min(tmp, 2 * f.getHeight() - 2 - tmp);
1317  }
1318  assert(x >= f.getStartX() && x < f.getEndX());
1319  assert(y >= f.getStartY() && y < f.getEndY());
1320  value = f(x, y);
1321  break;
1322  default:
1323  assert(0);
1324  abort();
1325  break;
1326  }
1327  return value;
1328 }
1330 
1332 
1337 template <class T>
1338 Sequence2<T> convolveSeparableFull(const Sequence2<T>& f,
1339  const Sequence1<T>& horzFilt, const Sequence1<T>& vertFilt)
1340 {
1341  if (!horzFilt.getSize() || !vertFilt.getSize()) {
1342  return Sequence2<T>();
1343  }
1344 
1345  // Perform the horizontal filtering.
1346  Sequence2<T> tmpResult(f.getStartX() + horzFilt.getStartInd(),
1347  f.getStartY(), f.getWidth() + horzFilt.getSize() - 1,
1348  f.getHeight());
1349  for (int y = f.getStartY(); y < f.getEndY(); ++y) {
1350  convolveHelper(f.rowBegin(y), f.rowEnd(y), horzFilt.begin(),
1351  horzFilt.end(), tmpResult.rowBegin(y), T());
1352  }
1353 
1354  // Perform the vertical filtering.
1355  Sequence2<T> result(tmpResult.getStartX(), tmpResult.getStartY() +
1356  vertFilt.getStartInd(), tmpResult.getWidth(), tmpResult.getHeight() +
1357  vertFilt.getSize() - 1);
1358  for (int x = tmpResult.getStartX(); x < tmpResult.getEndX(); ++x) {
1359  convolveHelper(tmpResult.colBegin(x), tmpResult.colEnd(x),
1360  vertFilt.begin(), vertFilt.end(), result.colBegin(x), T());
1361  }
1362 
1363  return result;
1364 }
1366 
1368 
1373 template <class T>
1374 Sequence2<T> convolveSeparableSameDomainZeroExt(const Sequence2<T>& f,
1375  const Sequence1<T>& horzFilt, const Sequence1<T>& vertFilt)
1376 {
1377  if (!horzFilt.getSize() || !vertFilt.getSize()) {
1378  return Sequence2<T>();
1379  }
1380 
1381  int skip;
1382  int shift;
1383 
1384  // Perform the horizontal filtering.
1385  Sequence2<T> tmpResult(f.getStartX(), f.getStartY(), f.getWidth(),
1386  f.getHeight());
1387  if (horzFilt.getStartInd() >= 0) {
1388  shift = horzFilt.getStartInd();
1389  skip = 0;
1390  } else {
1391  shift = 0;
1392  skip = -horzFilt.getStartInd();
1393  }
1394  for (int y = f.getStartY(); y < f.getEndY(); ++y) {
1395  convolveHelper2(f.rowBegin(y), f.rowEnd(y), horzFilt.begin(),
1396  horzFilt.end(), tmpResult.rowBegin(y) + shift, skip,
1397  tmpResult.getWidth() - shift, T());
1398  }
1399 
1400  // Perform the vertical filtering.
1401  if (vertFilt.getStartInd() >= 0) {
1402  shift = vertFilt.getStartInd();
1403  skip = 0;
1404  } else {
1405  shift = 0;
1406  skip = -vertFilt.getStartInd();
1407  }
1408  Sequence2<T> result(tmpResult.getStartX(), tmpResult.getStartY(),
1409  tmpResult.getWidth(), tmpResult.getHeight());
1410  for (int x = tmpResult.getStartX(); x < tmpResult.getEndX(); ++x) {
1411  convolveHelper2(tmpResult.colBegin(x), tmpResult.colEnd(x),
1412  vertFilt.begin(), vertFilt.end(), result.colBegin(x) + shift,
1413  skip, result.getHeight() - shift, T());
1414  }
1415 
1416  return result;
1417 }
1419 
1423 template<class T>
1424 Sequence2<T> convolve(const Sequence2<T>& f, const Sequence2<T>& g, int mode)
1425 {
1426  assert(mode == ConvolveMode::full ||
1431  assert(f.getWidth() > 0 && f.getHeight() > 0);
1432  assert(g.getWidth() > 0 && g.getHeight() > 0);
1433 
1434  Sequence2<T> result;
1435 
1436  switch (mode) {
1437  case ConvolveMode::full:
1438  result = Sequence2<T>(f.getStartX() + g.getStartX(),
1439  f.getStartY() + g.getStartY(), f.getWidth() + g.getWidth() - 1,
1440  f.getHeight() + g.getHeight() - 1);
1441  break;
1446  result = Sequence2<T>(f.getStartX(), f.getStartY(), f.getWidth(),
1447  f.getHeight());
1448  break;
1449  default:
1450  assert(0);
1451  abort();
1452  break;
1453  }
1454 
1455  for (int y = result.getStartY(); y < result.getEndY(); ++y) {
1456  for (int x = result.getStartX(); x < result.getEndX(); ++x) {
1457  T sum = T(0);
1458  for (int j = g.getStartY(); j < g.getEndY(); ++j) {
1459  for (int i = g.getStartX(); i < g.getEndX(); ++i) {
1460  sum += getExtSeqValue(f, x - i, y - j, mode) * g(i, j);
1461  }
1462  }
1463  result(x, y) = sum;
1464  }
1465  }
1466 
1467  return result;
1468 }
1469 
1474 template <class T>
1476  const Sequence1<T>& horzFilt, const Sequence1<T>& vertFilt,
1477  int mode = ConvolveMode::full)
1478 {
1479 #if defined(SPL_SEQUENCE2_USE_NEW_CONV)
1480  switch (mode) {
1481  case ConvolveMode::full:
1482  return convolveSeparableFull(f, horzFilt, vertFilt);
1483  break;
1485  return convolveSeparableSameDomainZeroExt(f, horzFilt, vertFilt);
1486  break;
1487  }
1488 #endif
1489  // The following code is quite inefficient. Rewrite it someday.
1490  Sequence2<T> horzFilt0(horzFilt.getStartInd(), 0, horzFilt.getSize(), 1,
1491  horzFilt.begin());
1492  Sequence2<T> vertFilt0(0, vertFilt.getStartInd(), 1, vertFilt.getSize(),
1493  vertFilt.begin());
1494  Sequence2<T> result = convolve(f, horzFilt0, mode);
1495  result = convolve(result, vertFilt0, mode);
1496  return result;
1497 }
1498 
1500 // Downsampling and upsampling
1502 
1507 template <class T>
1508 Sequence2<T> downsample(const Sequence2<T>& f, int factorX, int factorY)
1509 {
1510  assert(factorX >= 1 && factorY >= 1);
1511  int startX = ceilDiv(f.getStartX(), factorX) * factorX;
1512  int startY = ceilDiv(f.getStartY(), factorY) * factorY;
1513  int width = ceilDiv(f.getEndX() - startX, factorX);
1514  int height = ceilDiv(f.getEndY() - startY, factorY);
1515  Sequence2<T> result(roundTowardZeroDiv(startX, factorX),
1516  roundTowardZeroDiv(startY, factorY), width, height);
1517 
1518  for (int i = 0; i < height; ++i) {
1519  typename Sequence2<T>::ConstXIterator srcIter =
1520  f.rowBegin(startY + factorY * i) + (startX - f.getStartX());
1521  typename Sequence2<T>::XIterator dstIter =
1522  result.rowBegin(result.getStartY() + i);
1523  int n = result.getWidth();
1524  while (--n >= 0) {
1525  *dstIter = *srcIter;
1526  ++dstIter;
1527  srcIter += factorX;
1528  }
1529  }
1530 
1531  return result;
1532 }
1533 
1541 template <class T>
1542 Sequence2<T> upsample(const Sequence2<T>& f, int factorX, int factorY)
1543 {
1544  return upsample(f, factorX, factorY, 0, 0);
1545 }
1546 
1554 template <class T>
1555 Sequence2<T> upsample(const Sequence2<T>& f, int factorX, int factorY,
1556  int padX, int padY)
1557 {
1558  assert(factorX >= 1 && factorY >= 1);
1559  assert(padX >= 0 && padX < factorX);
1560  assert(padY >= 0 && padY < factorY);
1561 
1562  Sequence2<T> result(factorX * f.getStartX(), factorY * f.getStartY(),
1563  f.getWidth() + std::max((f.getWidth() - 1), 0) * (factorX - 1) + padX,
1564  f.getHeight() + std::max((f.getHeight() - 1), 0) * (factorY - 1) + padY);
1565  int srcY = f.getStartY();
1566  int dstY = result.getStartY();
1567  int rowCount = f.getHeight();
1568 
1569  while (rowCount > 0) {
1570  typename Sequence2<T>::ConstXIterator srcIter = f.rowBegin(srcY);
1571  typename Sequence2<T>::XIterator dstIter = result.rowBegin(dstY);
1572  int count = f.getWidth();
1573 
1574  while (count > 0) {
1575  *dstIter = *srcIter;
1576  ++srcIter;
1577  ++dstIter;
1578  for (int k = (count > 1) * (factorX - 1); k > 0; --k) {
1579  *dstIter = T(0);
1580  ++dstIter;
1581  }
1582  --count;
1583  }
1584  for (int k = padX; k > 0; --k) {
1585  *dstIter = T(0);
1586  ++dstIter;
1587  }
1588  ++srcY;
1589  ++dstY;
1590 
1591  for (int k = (rowCount > 1) * (factorY - 1); k > 0; --k) {
1592  std::fill_n(result.rowBegin(dstY), result.getWidth(), T(0));
1593  ++dstY;
1594  }
1595  --rowCount;
1596  }
1597 
1598  for (int k = padY; k > 0; --k) {
1599  assert(dstY < result.getEndY());
1600  std::fill_n(result.rowBegin(dstY), result.getWidth(), T(0));
1601  ++dstY;
1602  }
1603 
1604  return result;
1605 }
1606 
1608 // Polyphase decompositions
1610 
1623 template <class T>
1625  int numPhasesX, int typeY, int numPhasesY)
1626 {
1627  assert(numPhasesX >= 2);
1628  assert(numPhasesY >= 2);
1629  Array2<Sequence2<T> > result(numPhasesX, numPhasesY);
1630  for (int j = 0; j < numPhasesY; ++j) {
1631  for (int i = 0; i < numPhasesX; ++i) {
1632  int offsetX = getCosetOffset(typeX, numPhasesX, i);
1633  int offsetY = getCosetOffset(typeY, numPhasesY, j);
1634  result(i, j) = downsample(translate(seq, offsetX, offsetY),
1635  numPhasesX, numPhasesY);
1636  }
1637  }
1638  return result;
1639 }
1640 
1652 template <class T>
1653 Sequence2<T> polyphaseJoin(const Array2<Sequence2<T> >& comps, int typeX,
1654  int typeY)
1655 {
1656  const int numPhasesX = comps.getWidth();
1657  const int numPhasesY = comps.getHeight();
1658  assert(numPhasesX >= 2);
1659  assert(numPhasesY >= 2);
1660  Sequence2<T> seq;
1661  for (int j = 0; j < numPhasesY; ++j) {
1662  for (int i = 0; i < numPhasesX; ++i) {
1663  int offsetX = getCosetOffset(typeX, numPhasesX, i);
1664  int offsetY = getCosetOffset(typeY, numPhasesY, j);
1665 //std::cerr << "XXX " << i << " " << j << " " << upsample(comps(i, j), numPhasesX, numPhasesY) << "\n";
1666  seq = add(seq, translate(upsample(comps(i, j), numPhasesX,
1667  numPhasesY), -offsetX, -offsetY));
1668  }
1669  }
1670  return seq;
1671 }
1672 
1674 // Types.
1676 
1679 
1682 
1684 //
1686 
1691 }
1692 
1693 #endif
1694 
long roundTowardZeroDiv(long x, long y)
Compute a quotient with the result rounded towards zero.
Definition: math.hpp:152
This file contains the Array2 template class and its supporting code.
T & operator()(int x, int y)
Get a mutable reference to the specified element in the sequence.
Definition: Sequence2.hpp:707
int getEndY() const
Get the y-coordinate of the end index for the sequence.
Definition: Sequence2.hpp:666
Array2< T >::YIterator YIterator
The mutable iterator for the elements in a column of the sequence.
Definition: Sequence2.hpp:110
void swapArray(Array2< T > &data)
Swap the data for the underlying array and the specified array.
Definition: Sequence2.hpp:925
A one-dimensional sequence class with lazy copying and reference counting.
Definition: Sequence1.hpp:85
T ElemType
The type of the element in the sequence.
Definition: Sequence2.hpp:92
Sequence2< T > convolveSeparable(const Sequence2< T > &f, const Sequence1< T > &horzFilt, const Sequence1< T > &vertFilt, int mode=ConvolveMode::full)
Compute the convolution of a sequence with two 1-D filters (i.e., convolution with a separable filter...
Definition: Sequence2.hpp:1475
#define SPL_SEQUENCE2_INLINE
Allow the inlining of functions.
Definition: Sequence2.hpp:50
Definition: Arcball.hpp:48
int getStartY() const
Get the y-coordinate of the start index for the sequence.
Definition: Sequence2.hpp:654
ConstIterator end() const
Get a const iterator for one past the last element in the sequence.
Definition: Sequence2.hpp:731
T mod(T x, T y)
Compute the remainder after division.
Definition: math.hpp:184
T absVal(T x)
The absolute value function.
Definition: math.hpp:73
int getStartX() const
Get the x-coordinate of the start index for the sequence.
Definition: Sequence2.hpp:648
ConstXIterator rowEnd(int y) const
Get a const iterator for one past the end in the specified row of the sequence.
Definition: Sequence2.hpp:761
void fill(const T &value)
Get a copy of the underlying array.
Definition: Sequence2.hpp:919
int getWidth() const
Get the width of the sequence.
Definition: Sequence2.hpp:672
T max() const
Get the maximum element in the sequence.
Definition: Sequence2.hpp:823
Sequence2 & operator+=(const Sequence2 &f)
Add another sequence to this one.
Definition: Sequence2.hpp:560
ConstYIterator colEnd(int x) const
Get a const iterator for one past the end in the specified column of the sequence.
Definition: Sequence2.hpp:793
std::vector< T >::const_iterator ConstXIterator
A constant iterator for elements of a row in the array.
Definition: Array2.hpp:231
static const int full
The full convolution result (i.e., the same as "full" in MATLAB)
Definition: Sequence.hpp:57
SPL_SEQUENCE2_INLINE bool approxEqual(const Sequence2< T > &f, const Sequence2< T > &g, T threshold=1e-9)
Test two sequences for approximate equality.
Definition: Sequence2.hpp:1173
SPL_SEQUENCE2_INLINE Sequence2< T > operator/(const Sequence2< T > &f, const T &value)
Divide a sequence by a scalar.
Definition: Sequence2.hpp:1126
Sequence2 & operator*=(const Sequence2 &f)
Multiply elementwise this sequence by another one.
Definition: Sequence2.hpp:586
ConstYIterator colBegin(int x) const
Get a const iterator for the first element in the specified column of the sequence.
Definition: Sequence2.hpp:777
SPL_SEQUENCE2_INLINE Sequence2< T > operator+(const Sequence2< T > &f, const T &value)
Add a value to a sequence.
Definition: Sequence2.hpp:1070
long ceilDiv(long x, long y)
Compute the ceiling of a quotient.
Definition: math.hpp:212
static const int sameDomainPerExt
Periodic extension.
Definition: Sequence.hpp:66
int getHeight() const
Get the height of the sequence.
Definition: Sequence2.hpp:678
static const int sameDomainConstExt
Constant extension.
Definition: Sequence.hpp:63
~Sequence2()
The destructor.
Definition: Sequence2.hpp:519
bool operator==(const Sequence2< T > &f, const Sequence2< T > &g)
Test two sequences for equality.
Definition: Sequence2.hpp:1141
Array2< T >::ConstYIterator ConstYIterator
The const iterator for the elements in a column of the sequence.
Definition: Sequence2.hpp:107
This file contains various mathematical functions/code.
Sequence2< T > subsequence(const Sequence2< T > &f, int startX, int startY, int width, int height)
Extract a subsequence from a sequence.
Definition: Sequence2.hpp:1218
Array2< Sequence2< T > > polyphaseSplit(const Sequence2< T > &seq, int typeX, int numPhasesX, int typeY, int numPhasesY)
Split a sequence into its polyphase components.
Definition: Sequence2.hpp:1624
Sequence2 & operator=(const Sequence2 &f)
The assignment operator.
Definition: Sequence2.hpp:535
Common header for sequence classes.
int getStartInd() const
Get the start index for the sequence.
Definition: Sequence1.hpp:606
std::vector< T >::iterator Iterator
A mutable iterator for all elements in the array.
Definition: Array2.hpp:222
std::istream & operator>>(std::istream &in, Sequence2< T > &f)
Input a sequence from a stream.
Definition: Sequence2.hpp:881
Array2< T >::XIterator XIterator
The mutable iterator for the elements in a row of the sequence.
Definition: Sequence2.hpp:104
ConstXIterator rowBegin(int y) const
Get a const iterator for the first element in the specified row of the sequence.
Definition: Sequence2.hpp:745
YIter< T > YIterator
A mutable iterator for elements of a column in the array.
Definition: Array2.hpp:234
static const int sameDomainSymExt0
Symmetric periodic extension.
Definition: Sequence.hpp:69
Sequence2 & translate(int x, int y)
Translate (i.e., shift) a sequence by the specified displacement.
Definition: Sequence2.hpp:937
Sequence2 & operator-=(const Sequence2 &f)
Subtract another sequence from this one.
Definition: Sequence2.hpp:573
This file contains code for the Sequence1 template class.
SPL_SEQUENCE2_INLINE Sequence2< T > operator-(const Sequence2< T > &f, const T &value)
Subtract a value from a sequence.
Definition: Sequence2.hpp:1084
A two-dimensional array class with lazy copying and reference counting.
Definition: Array2.hpp:83
Sequence2()
The default constructor.
Definition: Sequence2.hpp:468
Array2< T >::Iterator Iterator
The mutable iterator for all elements in the sequence.
Definition: Sequence2.hpp:98
static const int sameDomainZeroExt
The same as "same" in MATLAB.
Definition: Sequence.hpp:60
T min() const
Get the minimum element in the sequence.
Definition: Sequence2.hpp:816
YIter< const T > ConstYIterator
A constant iterator for elements of a column in the array.
Definition: Array2.hpp:237
int getSize() const
Get the number of elements in the sequence.
Definition: Sequence2.hpp:684
Sequence2< T > polyphaseJoin(const Array2< Sequence2< T > > &comps, int typeX, int typeY)
Reassemble a sequence from its polyphase components.
Definition: Sequence2.hpp:1653
Sequence2< T > upsample(const Sequence2< T > &f, int factorX, int factorY, int padX, int padY)
Upsample a sequence in each of the horizontal and vertical directions by the specified factors...
Definition: Sequence2.hpp:1555
SPL_SEQUENCE2_INLINE Sequence2< T > translate(const Sequence2< T > &f, int deltaX, int deltaY)
Translate a sequence by the specified amount.
Definition: Sequence2.hpp:1248
SPL_SEQUENCE2_INLINE bool operator!=(const Sequence2< T > &f, const Sequence2< T > &g)
Test two sequences for inequality.
Definition: Sequence2.hpp:1163
Sequence2< T > convolve(const Sequence2< T > &f, const Sequence2< T > &g, int mode)
Compute the convolution of two sequences.
Definition: Sequence2.hpp:1424
int getSize() const
Get the length of the sequence.
Definition: Sequence1.hpp:618
Array2< T > getArray() const
Get a copy of the underlying array.
Definition: Sequence2.hpp:931
Iterator XIterator
A mutable iterator for elements of a row in the array.
Definition: Array2.hpp:228
T sum() const
Get the sum of the elements in the sequence.
Definition: Sequence2.hpp:830
Sequence2 & operator/=(const Sequence2 &f)
Divide elementwise this sequence by another one.
Definition: Sequence2.hpp:599
Sequence2< T > add(const Sequence2< T > &f, const Sequence2< T > &g)
Compute the sum of two sequences with potentially differing domains.
Definition: Sequence2.hpp:1017
A two-dimensional sequence class with lazy copying and reference counting.
Definition: Sequence2.hpp:83
std::vector< T >::const_iterator ConstIterator
A constant iterator for all elements in the array.
Definition: Array2.hpp:225
SPL_SEQUENCE2_INLINE Sequence2< T > operator*(const Sequence2< T > &f, const T &value)
Compute a scalar multiple of a sequence.
Definition: Sequence2.hpp:1112
Sequence2< double > RealSequence2
Real sequence.
Definition: Sequence2.hpp:1678
int getEndX() const
Get the x-coordinate of the end index for the sequence.
Definition: Sequence2.hpp:660
Array2< T >::ConstXIterator ConstXIterator
The const iterator for the elements in a row of the sequence.
Definition: Sequence2.hpp:101
Sequence2< int > IntSequence2
Integer sequence.
Definition: Sequence2.hpp:1681
Array2< T >::ConstIterator ConstIterator
The const iterator for all elements in the sequence.
Definition: Sequence2.hpp:95
ConstIterator begin() const
Get a const iterator for the first element in the sequence.
Definition: Sequence2.hpp:718
bool isShared() const
Is the array for this sequence shared with another array?
Definition: Sequence2.hpp:690
ConstIterator begin() const
Get an iterator referencing the first element in the sequence.
Definition: Sequence1.hpp:652
std::ostream & output(std::ostream &out, int fieldWidth) const
Output a sequence to the specified stream using the given field width for each sequence element...
Definition: Sequence2.hpp:840
Sequence2< T > downsample(const Sequence2< T > &f, int factorX, int factorY)
Downsample a sequence in each of the horizontal and vertical directions by the specified factors...
Definition: Sequence2.hpp:1508