Visual Servoing Platform version 3.6.0
Loading...
Searching...
No Matches
vpArray2D.h
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * This class implements an 2D array as a template class.
32 */
33#ifndef _vpArray2D_h_
34#define _vpArray2D_h_
35
36#include <fstream>
37#include <iostream>
38#include <limits>
39#include <math.h>
40#include <ostream>
41#include <sstream>
42#include <stdlib.h>
43#include <string.h>
44
45#include <visp3/core/vpConfig.h>
46#include <visp3/core/vpException.h>
47
48#ifdef VISP_HAVE_NLOHMANN_JSON
49#include <nlohmann/json.hpp>
50#endif
51
130template <class Type> class vpArray2D
131{
132protected:
134 unsigned int rowNum;
136 unsigned int colNum;
138 Type **rowPtrs;
140 unsigned int dsize;
141
142public:
144 Type *data;
145
146public:
151 vpArray2D<Type>() : rowNum(0), colNum(0), rowPtrs(NULL), dsize(0), data(NULL) { }
152
157 :
158#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
159 vpArray2D<Type>()
160#else
161 rowNum(0), colNum(0), rowPtrs(NULL), dsize(0), data(NULL)
162#endif
163 {
164 resize(A.rowNum, A.colNum, false, false);
165 memcpy(data, A.data, (size_t)rowNum * (size_t)colNum * sizeof(Type));
166 }
167
174 vpArray2D<Type>(unsigned int r, unsigned int c)
175 :
176#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
177 vpArray2D<Type>()
178#else
179 rowNum(0), colNum(0), rowPtrs(NULL), dsize(0), data(NULL)
180#endif
181 {
182 resize(r, c);
183 }
184
192 vpArray2D<Type>(unsigned int r, unsigned int c, Type val)
193 :
194#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
195 vpArray2D<Type>()
196#else
197 rowNum(0), colNum(0), rowPtrs(NULL), dsize(0), data(NULL)
198#endif
199 {
200 resize(r, c, false, false);
201 *this = val;
202 }
203
204#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
205 vpArray2D<Type>(vpArray2D<Type> &&A) noexcept
206 {
207 rowNum = A.rowNum;
208 colNum = A.colNum;
209 rowPtrs = A.rowPtrs;
210 dsize = A.dsize;
211 data = A.data;
212
213 A.rowNum = 0;
214 A.colNum = 0;
215 A.rowPtrs = NULL;
216 A.dsize = 0;
217 A.data = NULL;
218 }
219
220 explicit vpArray2D<Type>(const std::initializer_list<Type> &list) : vpArray2D<Type>()
221 {
222 resize(1, static_cast<unsigned int>(list.size()), false, false);
223 std::copy(list.begin(), list.end(), data);
224 }
225
226 explicit vpArray2D<Type>(unsigned int nrows, unsigned int ncols, const std::initializer_list<Type> &list)
227 : rowNum(0), colNum(0), rowPtrs(NULL), dsize(0), data(NULL)
228 {
229 if (nrows * ncols != static_cast<unsigned int>(list.size())) {
230 std::ostringstream oss;
231 oss << "Cannot create a vpArray2D of size (" << nrows << ", " << ncols << ") with a list of size " << list.size();
233 }
234
235 resize(nrows, ncols, false, false);
236 std::copy(list.begin(), list.end(), data);
237 }
238
239 explicit vpArray2D<Type>(const std::initializer_list<std::initializer_list<Type> > &lists) : vpArray2D<Type>()
240 {
241 unsigned int nrows = static_cast<unsigned int>(lists.size()), ncols = 0;
242 for (auto &l : lists) {
243 if (static_cast<unsigned int>(l.size()) > ncols) {
244 ncols = static_cast<unsigned int>(l.size());
245 }
246 }
247
248 resize(nrows, ncols, false, false);
249 auto it = lists.begin();
250 for (unsigned int i = 0; i < rowNum; i++, ++it) {
251 std::copy(it->begin(), it->end(), rowPtrs[i]);
252 }
253 }
254#endif
255
259 virtual ~vpArray2D<Type>()
260 {
261 if (data != NULL) {
262 free(data);
263 data = NULL;
264 }
265
266 if (rowPtrs != NULL) {
267 free(rowPtrs);
268 rowPtrs = NULL;
269 }
270 rowNum = colNum = dsize = 0;
271 }
272
275
280 inline unsigned int getCols() const { return colNum; }
281
282 Type getMaxValue() const;
283
284 Type getMinValue() const;
285
290 inline unsigned int getRows() const { return rowNum; }
292 inline unsigned int size() const { return colNum * rowNum; }
293
305 void resize(unsigned int nrows, unsigned int ncols, bool flagNullify = true, bool recopy_ = true)
306 {
307 if ((nrows == rowNum) && (ncols == colNum)) {
308 if (flagNullify && this->data != NULL) {
309 memset(this->data, 0, this->dsize * sizeof(Type));
310 }
311 }
312 else {
313 bool recopy = !flagNullify && recopy_; // priority to flagNullify
314 const bool recopyNeeded = (ncols != this->colNum && this->colNum > 0 && ncols > 0 && (!flagNullify || recopy));
315 Type *copyTmp = NULL;
316 unsigned int rowTmp = 0, colTmp = 0;
317
318 // Recopy case per case is required if number of cols has changed;
319 // structure of Type array is not the same in this case.
320 if (recopyNeeded && this->data != NULL) {
321 copyTmp = new Type[this->dsize];
322 memcpy(copyTmp, this->data, sizeof(Type) * this->dsize);
323 rowTmp = this->rowNum;
324 colTmp = this->colNum;
325 }
326
327 // Reallocation of this->data array
328 this->dsize = nrows * ncols;
329 this->data = (Type *)realloc(this->data, this->dsize * sizeof(Type));
330 if ((NULL == this->data) && (0 != this->dsize)) {
331 if (copyTmp != NULL) {
332 delete[] copyTmp;
333 }
334 throw(vpException(vpException::memoryAllocationError, "Memory allocation error when allocating 2D array data"));
335 }
336
337 this->rowPtrs = (Type **)realloc(this->rowPtrs, nrows * sizeof(Type *));
338 if ((NULL == this->rowPtrs) && (0 != this->dsize)) {
339 if (copyTmp != NULL) {
340 delete[] copyTmp;
341 }
343 "Memory allocation error when allocating 2D array rowPtrs"));
344 }
345
346 // Update rowPtrs
347 {
348 Type **t_ = rowPtrs;
349 for (unsigned int i = 0; i < dsize; i += ncols) {
350 *t_++ = this->data + i;
351 }
352 }
353
354 this->rowNum = nrows;
355 this->colNum = ncols;
356
357 // Recopy of this->data array values or nullify
358 if (flagNullify) {
359 memset(this->data, 0, (size_t)(this->dsize) * sizeof(Type));
360 }
361 else if (recopyNeeded && this->rowPtrs != NULL) {
362 // Recopy...
363 unsigned int minRow = (this->rowNum < rowTmp) ? this->rowNum : rowTmp;
364 unsigned int minCol = (this->colNum < colTmp) ? this->colNum : colTmp;
365 for (unsigned int i = 0; i < this->rowNum; ++i) {
366 for (unsigned int j = 0; j < this->colNum; ++j) {
367 if ((minRow > i) && (minCol > j)) {
368 (*this)[i][j] = copyTmp[i * colTmp + j];
369 }
370 else {
371 (*this)[i][j] = 0;
372 }
373 }
374 }
375 }
376
377 if (copyTmp != NULL) {
378 delete[] copyTmp;
379 }
380 }
381 }
382
383 void reshape(unsigned int nrows, unsigned int ncols)
384 {
385 if (dsize == 0) {
386 resize(nrows, ncols);
387 return;
388 }
389
390 if (nrows * ncols != dsize) {
391 std::ostringstream oss;
392 oss << "Cannot reshape array of total size " << dsize << " into shape (" << nrows << ", " << ncols << ")";
394 }
395
396 rowNum = nrows;
397 colNum = ncols;
398 rowPtrs = reinterpret_cast<Type **>(realloc(rowPtrs, nrows * sizeof(Type *)));
399 // Update rowPtrs
400 Type **t_ = rowPtrs;
401 for (unsigned int i = 0; i < dsize; i += ncols) {
402 *t_++ = data + i;
403 }
404 }
405
406
417 void insert(const vpArray2D<Type> &A, unsigned int r, unsigned int c)
418 {
419 if ((r + A.getRows()) <= rowNum && (c + A.getCols()) <= colNum) {
420 if (A.colNum == colNum && data != NULL && A.data != NULL && A.data != data) {
421 memcpy(data + r * colNum, A.data, sizeof(Type) * A.size());
422 }
423 else if (data != NULL && A.data != NULL && A.data != data) {
424 for (unsigned int i = r; i < (r + A.getRows()); i++) {
425 memcpy(data + i * colNum + c, A.data + (i - r) * A.colNum, sizeof(Type) * A.colNum);
426 }
427 }
428 }
429 else {
430 throw vpException(vpException::dimensionError, "Cannot insert (%dx%d) array in (%dx%d) array at position (%d,%d)",
431 A.getRows(), A.getCols(), rowNum, colNum, r, c);
432 }
433 }
434
438 bool operator==(const vpArray2D<Type> &A) const;
442 bool operator!=(const vpArray2D<Type> &A) const;
443
446 {
447 std::fill(data, data + dsize, x);
448 return *this;
449 }
450
455 {
456 resize(A.rowNum, A.colNum, false, false);
457 if (data != NULL && A.data != NULL && data != A.data) {
458 memcpy(data, A.data, (size_t)rowNum * (size_t)colNum * sizeof(Type));
459 }
460 return *this;
461 }
462
463#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
465 {
466 if (this != &other) {
467 free(data);
468 free(rowPtrs);
469
470 rowNum = other.rowNum;
471 colNum = other.colNum;
472 rowPtrs = other.rowPtrs;
473 dsize = other.dsize;
474 data = other.data;
475
476 other.rowNum = 0;
477 other.colNum = 0;
478 other.rowPtrs = NULL;
479 other.dsize = 0;
480 other.data = NULL;
481 }
482
483 return *this;
484 }
485
486 vpArray2D<Type> &operator=(const std::initializer_list<Type> &list)
487 {
488 if (dsize != static_cast<unsigned int>(list.size())) {
489 resize(1, static_cast<unsigned int>(list.size()), false, false);
490 }
491 std::copy(list.begin(), list.end(), data);
492
493 return *this;
494 }
495
496 vpArray2D<Type> &operator=(const std::initializer_list<std::initializer_list<Type> > &lists)
497 {
498 unsigned int nrows = static_cast<unsigned int>(lists.size()), ncols = 0;
499 for (auto &l : lists) {
500 if (static_cast<unsigned int>(l.size()) > ncols) {
501 ncols = static_cast<unsigned int>(l.size());
502 }
503 }
504
505 resize(nrows, ncols, false, false);
506 auto it = lists.begin();
507 for (unsigned int i = 0; i < rowNum; i++, ++it) {
508 std::copy(it->begin(), it->end(), rowPtrs[i]);
509 }
510
511 return *this;
512 }
513
514#ifdef VISP_HAVE_NLOHMANN_JSON
515 vpArray2D<Type> &operator=(const nlohmann::json &j) = delete;
516#endif
517#endif
518
520 inline Type *operator[](unsigned int i) { return rowPtrs[i]; }
522 inline Type *operator[](unsigned int i) const { return rowPtrs[i]; }
523
529 friend std::ostream &operator<<(std::ostream &s, const vpArray2D<Type> &A)
530 {
531 if (A.data == NULL || A.size() == 0) {
532 return s;
533 }
534 std::ios_base::fmtflags original_flags = s.flags();
535
536 s.precision(10);
537 for (unsigned int i = 0; i < A.getRows(); i++) {
538 for (unsigned int j = 0; j < A.getCols() - 1; j++) {
539 s << A[i][j] << " ";
540 }
541 // We don't add " " after the last row element
542 s << A[i][A.getCols() - 1];
543 // We don't add a \n char on the end of the last array line
544 if (i < A.getRows() - 1) {
545 s << std::endl;
546 }
547 }
548
549 s.flags(original_flags); // restore s to standard state
550
551 return s;
552 }
553
555
563
564 //---------------------------------
565 // Inherited array I/O Static Public Member Functions
566 //---------------------------------
582 static bool load(const std::string &filename, vpArray2D<Type> &A, bool binary = false, char *header = NULL)
583 {
584 std::fstream file;
585
586 if (!binary) {
587 file.open(filename.c_str(), std::fstream::in);
588 }
589 else {
590 file.open(filename.c_str(), std::fstream::in | std::fstream::binary);
591 }
592
593 if (!file) {
594 file.close();
595 return false;
596 }
597
598 if (!binary) {
599 std::string h;
600 bool headerIsDecoded = false;
601 do {
602 std::streampos pos = file.tellg();
603 char line[256];
604 file.getline(line, 256);
605 std::string prefix("# ");
606 std::string line_(line);
607 if (line_.compare(0, 2, prefix.c_str()) == 0) {
608 // Line is a comment
609 // If we are not on the first line, we should add "\n" to the end of
610 // the previous line
611 if (pos) {
612 h += "\n";
613 }
614 h += line_.substr(2); // Remove "# "
615 }
616 else {
617 // rewind before the line
618 file.seekg(pos, file.beg);
619 headerIsDecoded = true;
620 }
621 } while (!headerIsDecoded);
622
623 if (header != NULL) {
624#if defined(__MINGW32__) || \
625 !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
626 snprintf(header, h.size() + 1, "%s", h.c_str());
627#else
628 _snprintf_s(header, h.size() + 1, _TRUNCATE, "%s", h.c_str());
629#endif
630 }
631
632 unsigned int rows, cols;
633 file >> rows;
634 file >> cols;
635
636 if (rows >= (std::numeric_limits<unsigned int>::max)() || cols >= (std::numeric_limits<unsigned int>::max)()) {
637 throw vpException(vpException::badValue, "Array exceed the max size.");
638 }
639
640 A.resize(rows, cols);
641
642 Type value;
643 for (unsigned int i = 0; i < rows; i++) {
644 for (unsigned int j = 0; j < cols; j++) {
645 file >> value;
646 A[i][j] = value;
647 }
648 }
649 }
650 else {
651 char c = '0';
652 std::string h;
653 // Decode header until '\0' char that ends the header string
654 while (c != '\0') {
655 file.read(&c, 1);
656 h += c;
657 }
658 if (header != NULL) {
659#if defined(__MINGW32__) || \
660 !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
661 snprintf(header, h.size() + 1, "%s", h.c_str());
662#else
663 _snprintf_s(header, h.size() + 1, _TRUNCATE, "%s", h.c_str());
664#endif
665 }
666
667 unsigned int rows, cols;
668 file.read((char *)&rows, sizeof(unsigned int));
669 file.read((char *)&cols, sizeof(unsigned int));
670 A.resize(rows, cols);
671
672 Type value;
673 for (unsigned int i = 0; i < rows; i++) {
674 for (unsigned int j = 0; j < cols; j++) {
675 file.read((char *)&value, sizeof(Type));
676 A[i][j] = value;
677 }
678 }
679 }
680
681 file.close();
682 return true;
683 }
696 static bool loadYAML(const std::string &filename, vpArray2D<Type> &A, char *header = NULL)
697 {
698 std::fstream file;
699
700 file.open(filename.c_str(), std::fstream::in);
701
702 if (!file) {
703 file.close();
704 return false;
705 }
706
707 unsigned int rows = 0, cols = 0;
708 std::string h;
709 std::string line, subs;
710 bool inheader = true;
711 unsigned int i = 0, j;
712 unsigned int lineStart = 0;
713
714 while (getline(file, line)) {
715 if (inheader) {
716 if (rows == 0 && line.compare(0, 5, "rows:") == 0) {
717 std::stringstream ss(line);
718 ss >> subs;
719 ss >> rows;
720 }
721 else if (cols == 0 && line.compare(0, 5, "cols:") == 0) {
722 std::stringstream ss(line);
723 ss >> subs;
724 ss >> cols;
725 }
726 else if (line.compare(0, 5, "data:") == 0) {
727 inheader = false;
728 }
729 else {
730 h += line + "\n";
731 }
732 }
733 else {
734 // if i == 0, we just got out of the header: initialize matrix
735 // dimensions
736 if (i == 0) {
737 if (rows == 0 || cols == 0) {
738 file.close();
739 return false;
740 }
741 A.resize(rows, cols);
742 // get indentation level which is common to all lines
743 lineStart = (unsigned int)line.find("[") + 1;
744 }
745 std::stringstream ss(line.substr(lineStart, line.find("]") - lineStart));
746 j = 0;
747 while (getline(ss, subs, ',')) {
748 A[i][j++] = atof(subs.c_str());
749 }
750 i++;
751 }
752 }
753
754 if (header != NULL) {
755 std::string h_ = h.substr(0, h.size() - 1); // Remove last '\n' char
756#if defined(__MINGW32__) || \
757 !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
758 snprintf(header, h_.size() + 1, "%s", h_.c_str());
759#else
760 _snprintf_s(header, h_.size() + 1, _TRUNCATE, "%s", h_.c_str());
761#endif
762 }
763
764 file.close();
765 return true;
766 }
767
784 static bool save(const std::string &filename, const vpArray2D<Type> &A, bool binary = false, const char *header = "")
785 {
786 std::fstream file;
787
788 if (!binary) {
789 file.open(filename.c_str(), std::fstream::out);
790 }
791 else {
792 file.open(filename.c_str(), std::fstream::out | std::fstream::binary);
793 }
794
795 if (!file) {
796 file.close();
797 return false;
798 }
799
800 if (!binary) {
801 unsigned int i = 0;
802 file << "# ";
803 while (header[i] != '\0') {
804 file << header[i];
805 if (header[i] == '\n') {
806 file << "# ";
807 }
808 i++;
809 }
810 file << std::endl;
811 file << A.getRows() << "\t" << A.getCols() << std::endl;
812 file << A << std::endl;
813 }
814 else {
815 int headerSize = 0;
816 while (header[headerSize] != '\0') {
817 headerSize++;
818 }
819 file.write(header, (size_t)headerSize + (size_t)1);
820 unsigned int matrixSize;
821 matrixSize = A.getRows();
822 file.write((char *)&matrixSize, sizeof(unsigned int));
823 matrixSize = A.getCols();
824 file.write((char *)&matrixSize, sizeof(unsigned int));
825 Type value;
826 for (unsigned int i = 0; i < A.getRows(); i++) {
827 for (unsigned int j = 0; j < A.getCols(); j++) {
828 value = A[i][j];
829 file.write((char *)&value, sizeof(Type));
830 }
831 }
832 }
833
834 file.close();
835 return true;
836 }
877 static bool saveYAML(const std::string &filename, const vpArray2D<Type> &A, const char *header = "")
878 {
879 std::fstream file;
880
881 file.open(filename.c_str(), std::fstream::out);
882
883 if (!file) {
884 file.close();
885 return false;
886 }
887
888 unsigned int i = 0;
889 bool inIndent = false;
890 std::string indent = "";
891 bool checkIndent = true;
892 while (header[i] != '\0') {
893 file << header[i];
894 if (checkIndent) {
895 if (inIndent) {
896 if (header[i] == ' ') {
897 indent += " ";
898 }
899 else if (indent.length() > 0) {
900 checkIndent = false;
901 }
902 }
903 if (header[i] == '\n' || (inIndent && header[i] == ' ')) {
904 inIndent = true;
905 }
906 else {
907 inIndent = false;
908 }
909 }
910 i++;
911 }
912
913 if (i != 0) {
914 file << std::endl;
915 }
916 file << "rows: " << A.getRows() << std::endl;
917 file << "cols: " << A.getCols() << std::endl;
918
919 if (indent.length() == 0) {
920 indent = " ";
921 }
922
923 file << "data: " << std::endl;
924 unsigned int j;
925 for (i = 0; i < A.getRows(); ++i) {
926 file << indent << "- [";
927 for (j = 0; j < A.getCols() - 1; ++j) {
928 file << A[i][j] << ", ";
929 }
930 file << A[i][j] << "]" << std::endl;
931 }
932
933 file.close();
934 return true;
935 }
936#ifdef VISP_HAVE_NLOHMANN_JSON
937 //template<typename Type>
938 template<class T>
939 friend void from_json(const nlohmann::json &j, vpArray2D<T> &array);
940 //template<typename Type>
941 template<class T>
942 friend void to_json(nlohmann::json &j, const vpArray2D<T> &array);
943#endif
944
956 static vpArray2D<Type> conv2(const vpArray2D<Type> &M, const vpArray2D<Type> &kernel, const std::string &mode);
957
970 static void conv2(const vpArray2D<Type> &M, const vpArray2D<Type> &kernel, vpArray2D<Type> &res, const std::string &mode);
971
984 vpArray2D<Type> insert(const vpArray2D<Type> &A, const vpArray2D<Type> &B, unsigned int r, unsigned int c);
985
999 static void insert(const vpArray2D<Type> &A, const vpArray2D<Type> &B, vpArray2D<Type> &C, unsigned int r, unsigned int c);
1001};
1002
1006template <class Type> Type vpArray2D<Type>::getMinValue() const
1007{
1008 Type *dataptr = data;
1009 Type min = *dataptr;
1010 dataptr++;
1011 for (unsigned int i = 0; i < dsize - 1; i++) {
1012 if (*dataptr < min) {
1013 min = *dataptr;
1014 }
1015 dataptr++;
1016 }
1017 return min;
1018}
1019
1023template <class Type> Type vpArray2D<Type>::getMaxValue() const
1024{
1025 Type *dataptr = data;
1026 Type max = *dataptr;
1027 dataptr++;
1028 for (unsigned int i = 0; i < dsize - 1; i++) {
1029 if (*dataptr > max) {
1030 max = *dataptr;
1031 }
1032 dataptr++;
1033 }
1034 return max;
1035}
1036
1043template <class Type> vpArray2D<Type> vpArray2D<Type>::hadamard(const vpArray2D<Type> &m) const
1044{
1045 if (m.getRows() != rowNum || m.getCols() != colNum) {
1046 throw(vpException(vpException::dimensionError, "Hadamard product: bad dimensions!"));
1047 }
1048
1049 vpArray2D<Type> out;
1050 out.resize(rowNum, colNum, false);
1051
1052 for (unsigned int i = 0; i < dsize; i++) {
1053 out.data[i] = data[i] * m.data[i];
1054 }
1055
1056 return out;
1057}
1058
1059template <class Type> vpArray2D<Type> vpArray2D<Type>::t() const
1060{
1061 vpArray2D<Type> At(colNum, rowNum);
1062 for (unsigned int i = 0; i < rowNum; i++) {
1063 for (unsigned int j = 0; j < colNum; j++) {
1064 At[j][i] = (*this)[i][j];
1065 }
1066 }
1067 return At;
1068}
1069
1070template <class Type> vpArray2D<Type> vpArray2D<Type>::conv2(const vpArray2D<Type> &M, const vpArray2D<Type> &kernel, const std::string &mode)
1071{
1072 vpArray2D<Type> res;
1073 conv2(M, kernel, res, mode);
1074 return res;
1075}
1076
1077template <class Type> void vpArray2D<Type>::conv2(const vpArray2D<Type> &M, const vpArray2D<Type> &kernel, vpArray2D<Type> &res, const std::string &mode)
1078{
1079 if (M.getRows() * M.getCols() == 0 || kernel.getRows() * kernel.getCols() == 0)
1080 return;
1081
1082 if (mode == "valid") {
1083 if (kernel.getRows() > M.getRows() || kernel.getCols() > M.getCols())
1084 return;
1085 }
1086
1087 vpArray2D<Type> M_padded, res_same;
1088
1089 if (mode == "full" || mode == "same") {
1090 const unsigned int pad_x = kernel.getCols() - 1;
1091 const unsigned int pad_y = kernel.getRows() - 1;
1092 M_padded.resize(M.getRows() + 2 * pad_y, M.getCols() + 2 * pad_x, true, false);
1093 M_padded.insert(M, pad_y, pad_x);
1094
1095 if (mode == "same") {
1096 res.resize(M.getRows(), M.getCols(), false, false);
1097 res_same.resize(M.getRows() + pad_y, M.getCols() + pad_x, true, false);
1098 }
1099 else {
1100 res.resize(M.getRows() + pad_y, M.getCols() + pad_x, true, false);
1101 }
1102 }
1103 else if (mode == "valid") {
1104 M_padded = M;
1105 res.resize(M.getRows() - kernel.getRows() + 1, M.getCols() - kernel.getCols() + 1);
1106 }
1107 else {
1108 return;
1109 }
1110
1111 if (mode == "same") {
1112 for (unsigned int i = 0; i < res_same.getRows(); i++) {
1113 for (unsigned int j = 0; j < res_same.getCols(); j++) {
1114 for (unsigned int k = 0; k < kernel.getRows(); k++) {
1115 for (unsigned int l = 0; l < kernel.getCols(); l++) {
1116 res_same[i][j] += M_padded[i + k][j + l] * kernel[kernel.getRows() - k - 1][kernel.getCols() - l - 1];
1117 }
1118 }
1119 }
1120 }
1121
1122 const unsigned int start_i = kernel.getRows() / 2;
1123 const unsigned int start_j = kernel.getCols() / 2;
1124 for (unsigned int i = 0; i < M.getRows(); i++) {
1125 memcpy(res.data + i * M.getCols(), res_same.data + (i + start_i) * res_same.getCols() + start_j,
1126 sizeof(Type) * M.getCols());
1127 }
1128 }
1129 else {
1130 for (unsigned int i = 0; i < res.getRows(); i++) {
1131 for (unsigned int j = 0; j < res.getCols(); j++) {
1132 for (unsigned int k = 0; k < kernel.getRows(); k++) {
1133 for (unsigned int l = 0; l < kernel.getCols(); l++) {
1134 res[i][j] += M_padded[i + k][j + l] * kernel[kernel.getRows() - k - 1][kernel.getCols() - l - 1];
1135 }
1136 }
1137 }
1138 }
1139 }
1140}
1141
1142template<class Type> vpArray2D<Type> vpArray2D<Type>::insert(const vpArray2D<Type> &A, const vpArray2D<Type> &B, unsigned int r, unsigned int c)
1143{
1145
1146 insert(A, B, C, r, c);
1147
1148 return C;
1149}
1150
1151template<class Type> void vpArray2D<Type>::insert(const vpArray2D<Type> &A, const vpArray2D<Type> &B, vpArray2D<Type> &C, unsigned int r, unsigned int c)
1152{
1153 if (((r + B.getRows()) <= A.getRows()) && ((c + B.getCols()) <= A.getCols())) {
1154 C.resize(A.getRows(), A.getCols(), false, false);
1155
1156 for (unsigned int i = 0; i < A.getRows(); i++) {
1157 for (unsigned int j = 0; j < A.getCols(); j++) {
1158 if (i >= r && i < (r + B.getRows()) && j >= c && j < (c + B.getCols())) {
1159 C[i][j] = B[i - r][j - c];
1160 }
1161 else {
1162 C[i][j] = A[i][j];
1163 }
1164 }
1165 }
1166 }
1167 else {
1168 throw vpException(vpException::dimensionError, "Cannot insert (%dx%d) array in (%dx%d) array at position (%d,%d)",
1169 B.getRows(), B.getCols(), A.getCols(), A.getRows(), r, c);
1170 }
1171}
1172
1173template <class Type> bool vpArray2D<Type>::operator==(const vpArray2D<Type> &A) const
1174{
1175 if (A.rowNum != rowNum || A.colNum != colNum) {
1176 return false;
1177 }
1178
1179 for (unsigned int i = 0; i < A.size(); i++) {
1180 if (data[i] != A.data[i]) {
1181 return false;
1182 }
1183 }
1184
1185 return true;
1186}
1187
1191template <> inline bool vpArray2D<double>::operator==(const vpArray2D<double> &A) const
1192{
1193 if (A.rowNum != rowNum || A.colNum != colNum) {
1194 return false;
1195 }
1196
1197 for (unsigned int i = 0; i < A.size(); i++) {
1198 if (fabs(data[i] - A.data[i]) > std::numeric_limits<double>::epsilon()) {
1199 return false;
1200 }
1201 }
1202
1203 return true;
1204}
1205
1209template <> inline bool vpArray2D<float>::operator==(const vpArray2D<float> &A) const
1210{
1211 if (A.rowNum != rowNum || A.colNum != colNum) {
1212 return false;
1213 }
1214
1215 for (unsigned int i = 0; i < A.size(); i++) {
1216 if (fabsf(data[i] - A.data[i]) > std::numeric_limits<float>::epsilon()) {
1217 return false;
1218 }
1219 }
1220
1221 return true;
1222}
1223
1227template <class Type> bool vpArray2D<Type>::operator!=(const vpArray2D<Type> &A) const { return !(*this == A); }
1228
1229#ifdef VISP_HAVE_NLOHMANN_JSON
1230
1231
1232template <class Type>
1233inline void from_json(const nlohmann::json &j, vpArray2D<Type> &array)
1234{
1235 if (j.is_array()) {
1236 const unsigned int nrows = static_cast<unsigned int>(j.size());
1237 if (nrows == 0) { // Initialize an empty array, Finished
1238 array.resize(0, 0);
1239 return;
1240 }
1241 unsigned int ncols = 0;
1242 bool first = true;
1243 for (const auto &item: j) { // Find number of columns, validate that all rows have same number of cols
1244 if (!item.is_array()) {
1245 throw vpException(vpException::badValue, "Trying to instantiate a 2D array with a JSON object that is not an array of array");
1246 }
1247 if (first) {
1248 first = false;
1249 ncols = static_cast<unsigned int>(item.size());
1250 }
1251 else if (ncols != item.size()) {
1252 throw vpException(vpException::badValue, "Trying to instantiate a 2D array with JSON row arrays that are not of the same size");
1253 }
1254 }
1255 array.resize(nrows, ncols);
1256 unsigned i = 0;
1257 for (const auto &item: j) {
1258 std::vector<Type> row = item;
1259 std::copy(row.begin(), row.end(), array.rowPtrs[i]);
1260 ++i;
1261 }
1262 }
1263 else if (j.is_object()) {
1264 const unsigned ncols = j.at("cols");
1265 const unsigned nrows = j.at("rows");
1266 array.resize(nrows, ncols);
1267 const nlohmann::json jData = j.at("data");
1268 if (!jData.is_array() || jData.size() != nrows * ncols) {
1269 std::stringstream ss;
1270 ss << "JSON \"data\" field must be an array of size " << nrows * ncols;
1271 throw vpException(vpException::badValue, ss.str());
1272 }
1273 unsigned i = 0;
1274 for (const auto &jValue: jData) {
1275 array.data[i] = jValue;
1276 ++i;
1277 }
1278 }
1279 else {
1280 throw vpException(vpException::badValue, "Trying to read a vpArray2D from something that is not an array or object");
1281 }
1282}
1283
1284
1285template <class Type>
1286inline void to_json(nlohmann::json &j, const vpArray2D<Type> &array)
1287{
1288 j = {
1289 {"cols", array.colNum},
1290 {"rows", array.rowNum},
1291 {"type", "vpArray2D"}
1292 };
1293
1294 nlohmann::json::array_t data;
1295 data.reserve(array.size());
1296 for (unsigned i = 0; i < array.size(); ++i) {
1297 data.push_back(array.data[i]);
1298 }
1299 j["data"] = data;
1300}
1301#endif
1302#endif
Implementation of a generic 2D array used as base class for matrices and vectors.
Definition vpArray2D.h:131
static bool load(const std::string &filename, vpArray2D< Type > &A, bool binary=false, char *header=NULL)
Definition vpArray2D.h:582
unsigned int getCols() const
Definition vpArray2D.h:280
Type * operator[](unsigned int i)
Set element using A[i][j] = x.
Definition vpArray2D.h:520
vpArray2D< Type > insert(const vpArray2D< Type > &A, const vpArray2D< Type > &B, unsigned int r, unsigned int c)
Definition vpArray2D.h:1142
static void conv2(const vpArray2D< Type > &M, const vpArray2D< Type > &kernel, vpArray2D< Type > &res, const std::string &mode)
Definition vpArray2D.h:1077
Type * data
Address of the first element of the data array.
Definition vpArray2D.h:144
Type ** rowPtrs
Address of the first element of each rows.
Definition vpArray2D.h:138
vpArray2D< Type > & operator=(Type x)
Set all the elements of the array to x.
Definition vpArray2D.h:445
void insert(const vpArray2D< Type > &A, unsigned int r, unsigned int c)
Definition vpArray2D.h:417
Type getMinValue() const
Definition vpArray2D.h:1006
vpArray2D< Type > & operator=(const std::initializer_list< Type > &list)
Definition vpArray2D.h:486
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
Definition vpArray2D.h:305
vpArray2D< Type > & operator=(const vpArray2D< Type > &A)
Definition vpArray2D.h:454
Type * operator[](unsigned int i) const
Get element using x = A[i][j].
Definition vpArray2D.h:522
static void insert(const vpArray2D< Type > &A, const vpArray2D< Type > &B, vpArray2D< Type > &C, unsigned int r, unsigned int c)
Definition vpArray2D.h:1151
static bool saveYAML(const std::string &filename, const vpArray2D< Type > &A, const char *header="")
Definition vpArray2D.h:877
unsigned int rowNum
Number of rows in the array.
Definition vpArray2D.h:134
friend std::ostream & operator<<(std::ostream &s, const vpArray2D< Type > &A)
Definition vpArray2D.h:529
vpArray2D< Type > & operator=(const nlohmann::json &j)=delete
friend void to_json(nlohmann::json &j, const vpArray2D< T > &array)
static vpArray2D< Type > conv2(const vpArray2D< Type > &M, const vpArray2D< Type > &kernel, const std::string &mode)
Definition vpArray2D.h:1070
unsigned int dsize
Current array size (rowNum * colNum)
Definition vpArray2D.h:140
unsigned int size() const
Return the number of elements of the 2D array.
Definition vpArray2D.h:292
vpArray2D< Type > & operator=(const std::initializer_list< std::initializer_list< Type > > &lists)
Definition vpArray2D.h:496
vpArray2D< Type > & operator=(vpArray2D< Type > &&other) noexcept
Definition vpArray2D.h:464
vpArray2D< Type > t() const
Compute the transpose of the array.
Definition vpArray2D.h:1059
static bool loadYAML(const std::string &filename, vpArray2D< Type > &A, char *header=NULL)
Definition vpArray2D.h:696
unsigned int getRows() const
Definition vpArray2D.h:290
bool operator!=(const vpArray2D< Type > &A) const
Definition vpArray2D.h:1227
vpArray2D< Type > hadamard(const vpArray2D< Type > &m) const
Definition vpArray2D.h:1043
Type getMaxValue() const
Definition vpArray2D.h:1023
static bool save(const std::string &filename, const vpArray2D< Type > &A, bool binary=false, const char *header="")
Definition vpArray2D.h:784
friend void from_json(const nlohmann::json &j, vpArray2D< T > &array)
void reshape(unsigned int nrows, unsigned int ncols)
Definition vpArray2D.h:383
unsigned int colNum
Number of columns in the array.
Definition vpArray2D.h:136
bool operator==(const vpArray2D< Type > &A) const
Definition vpArray2D.h:1173
error that can be emitted by ViSP classes.
Definition vpException.h:59
@ badValue
Used to indicate that a value is not in the allowed range.
Definition vpException.h:85
@ dimensionError
Bad dimension.
Definition vpException.h:83
@ memoryAllocationError
Memory allocation error.
Definition vpException.h:76