46#include <visp3/core/vpConfig.h>
47#include <visp3/core/vpException.h>
48#include <visp3/core/vpMath.h>
50#ifdef VISP_HAVE_NLOHMANN_JSON
51#include VISP_NLOHMANN_JSON(json.hpp)
162#if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
180#if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
198#if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
204 resize(r, c,
false,
false);
219 vpArray2D(
const std::vector<Type> &vec,
unsigned int r = 0,
unsigned int c = 0)
221#if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
227 if ((r > 0) && (c > 0)) {
228 if ((r * c) != vec.size()) {
230 "Cannot initialize vpArray(%d, %d) from std::vector(%d). Wrong dimension", r, c, vec.size()));
232 resize(r, c,
false,
false);
234 else if ((c == 0) && (r == 0)) {
236 "Cannot initialize vpArray(%d, %d) from std::vector(%d). Using rows = 0 and cols = 0 is ambiguous", r, c, vec.size()));
239 if (r != vec.size()) {
241 "Cannot initialize vpArray(%d, %d) from std::vector(%d). Wrong dimension", r, c, vec.size()));
243 resize(
static_cast<unsigned int>(vec.size()), 1,
false,
false);
246 if (c != vec.size()) {
248 "Cannot initialize vpArray(%d, %d) from std::vector(%d). Wrong dimension", r, c, vec.size()));
250 resize(1,
static_cast<unsigned int>(vec.size()),
false,
false);
253#if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
254 std::copy(vec.begin(), vec.end(),
data);
256 memcpy(
data, vec.data(), vec.size() *
sizeof(Type));
260#if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
280 resize(1,
static_cast<unsigned int>(list.size()),
false,
false);
281 std::copy(list.begin(), list.end(),
data);
284 VP_EXPLICIT
vpArray2D(
unsigned int nrows,
unsigned int ncols,
const std::initializer_list<Type> &list)
287 if ((nrows * ncols) !=
static_cast<unsigned int>(list.size())) {
288 std::ostringstream oss;
289 oss <<
"Cannot create a vpArray2D of size (" << nrows <<
", " << ncols <<
") with a list of size " << list.size();
290 throw vpException(vpException::dimensionError, oss.str());
293 resize(nrows, ncols,
false,
false);
294 std::copy(list.begin(), list.end(),
data);
297 VP_EXPLICIT
vpArray2D(
const std::initializer_list<std::initializer_list<Type> > &lists) :
vpArray2D()
299 unsigned int nrows =
static_cast<unsigned int>(lists.size()), ncols = 0;
300 for (
auto &l : lists) {
301 if (
static_cast<unsigned int>(l.size()) > ncols) {
302 ncols =
static_cast<unsigned int>(l.size());
306 resize(nrows, ncols,
false,
false);
307 auto it = lists.begin();
308 for (
unsigned int i = 0; i <
rowNum; ++i, ++it) {
309 std::copy(it->begin(), it->end(),
rowPtrs[i]);
332 v.isMemoryOwner =
false;
333 v.isRowPtrsOwner =
false;
365 unsigned int oldRows = v.rowNum;
366 unsigned int oldCols = v.colNum;
367 Type *oldData = v.data;
370 v.dsize = numRows * numCols;
372 if ((v.isMemoryOwner ==
true) && (v.data !=
nullptr)) {
376 v.isMemoryOwner =
false;
377 bool requiresRowPtrRealloc =
data != oldData || numRows != oldRows || numCols != oldCols;
379 if (requiresRowPtrRealloc) {
380 if ((v.isRowPtrsOwner ==
true) && (v.rowPtrs !=
nullptr)) {
383 v.isRowPtrsOwner =
true;
384 v.rowPtrs =
reinterpret_cast<Type **
>(malloc(v.rowNum *
sizeof(Type *)));
385 for (
unsigned int i = 0; i < v.rowNum; ++i) {
386 v.rowPtrs[i] =
data + i * v.colNum;
398 if (
data !=
nullptr) {
448 void resize(
unsigned int nrows,
unsigned int ncols,
bool flagNullify =
true,
bool recopy_ =
true)
451 if (flagNullify && (this->data !=
nullptr)) {
452 memset(this->data, 0, this->
dsize *
sizeof(Type));
459 bool recopy = (!flagNullify) && recopy_;
460 bool colcond = (ncols != this->
colNum) && (this->
colNum > 0) && (ncols > 0);
461 const bool recopyNeeded = colcond && ((!flagNullify) || recopy);
462 Type *copyTmp =
nullptr;
463 unsigned int rowTmp = 0, colTmp = 0;
467 if (recopyNeeded && (this->data !=
nullptr)) {
468 copyTmp =
new Type[this->
dsize];
469 memcpy(copyTmp, this->data,
sizeof(Type) * this->
dsize);
475 this->
dsize = nrows * ncols;
476 Type *tmp_data =
reinterpret_cast<Type *
>(realloc(this->data, this->
dsize *
sizeof(Type)));
478 this->data = tmp_data;
481 this->data =
nullptr;
484 if ((
nullptr == this->data) && (0 != this->
dsize)) {
485 if (copyTmp !=
nullptr) {
491 Type **tmp_rowPtrs =
reinterpret_cast<Type **
>(realloc(this->
rowPtrs, nrows *
sizeof(Type *)));
499 if (copyTmp !=
nullptr) {
503 "Memory allocation error when allocating 2D array rowPtrs"));
509 for (
unsigned int i = 0; i <
dsize; i += ncols) {
510 *t_++ = this->data + i;
519 if ((
nullptr != this->data) && (0 != this->dsize)) {
520 memset(this->data, 0,
static_cast<size_t>(this->dsize) *
sizeof(Type));
523 else if (recopyNeeded && (this->
rowPtrs !=
nullptr)) {
525 unsigned int minRow = (this->
rowNum < rowTmp) ? this->
rowNum : rowTmp;
526 unsigned int minCol = (this->
colNum < colTmp) ? this->
colNum : colTmp;
527 for (
unsigned int i = 0; i < this->
rowNum; ++i) {
528 for (
unsigned int j = 0; j < this->
colNum; ++j) {
529 if ((minRow > i) && (minCol > j)) {
530 (*this)[i][j] = copyTmp[(i * colTmp) + j];
539 if (copyTmp !=
nullptr) {
545 void reshape(
unsigned int nrows,
unsigned int ncols)
552 if ((nrows * ncols) !=
dsize) {
553 std::ostringstream oss;
554 oss <<
"Cannot reshape array of total size " <<
dsize <<
" into shape (" << nrows <<
", " << ncols <<
")";
561 Type **tmp =
reinterpret_cast<Type **
>(realloc(
rowPtrs, nrows *
sizeof(Type *)));
569 for (
unsigned int i = 0; i <
dsize; i += ncols) {
593 unsigned int a_rows = A.
getRows();
594 for (
unsigned int i = r; i < (r + a_rows); ++i) {
633#if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
636 if (
this != &other) {
654 other.rowPtrs =
nullptr;
656 other.data =
nullptr;
664 if (
dsize !=
static_cast<unsigned int>(list.size())) {
665 resize(1,
static_cast<unsigned int>(list.size()),
false,
false);
667 std::copy(list.begin(), list.end(),
data);
674 unsigned int nrows =
static_cast<unsigned int>(lists.size()), ncols = 0;
675 for (
auto &l : lists) {
676 if (
static_cast<unsigned int>(l.size()) > ncols) {
677 ncols =
static_cast<unsigned int>(l.size());
681 resize(nrows, ncols,
false,
false);
682 auto it = lists.begin();
683 for (
unsigned int i = 0; i <
rowNum; ++i, ++it) {
684 std::copy(it->begin(), it->end(),
rowPtrs[i]);
690#ifdef VISP_HAVE_NLOHMANN_JSON
707 if ((A.
data ==
nullptr) || (A.
size() == 0)) {
710 std::ios_base::fmtflags original_flags = s.flags();
711 const unsigned int precision = 10;
712 s.precision(precision);
713 unsigned int a_rows = A.
getRows();
714 unsigned int a_cols = A.
getCols();
715 for (
unsigned int i = 0; i < a_rows; ++i) {
716 for (
unsigned int j = 0; j < (a_cols - 1); ++j) {
720 s << A[i][a_cols - 1];
722 if (i < (a_rows - 1)) {
727 s.flags(original_flags);
760 static bool load(
const std::string &filename,
vpArray2D<Type> &A,
bool binary =
false,
char *header =
nullptr)
765 file.open(filename.c_str(), std::fstream::in);
768 file.open(filename.c_str(), std::fstream::in | std::fstream::binary);
778 bool headerIsDecoded =
false;
780 std::streampos pos = file.tellg();
781 char line[FILENAME_MAX];
782 file.getline(line, FILENAME_MAX);
783 std::string prefix(
"# ");
784 std::string line_(line);
785 if (line_.compare(0, prefix.size(), prefix.c_str()) == 0) {
792 h += line_.substr(prefix.size());
796 file.seekg(pos, file.beg);
797 headerIsDecoded =
true;
799 }
while (!headerIsDecoded);
801 if (header !=
nullptr) {
802#if defined(__MINGW32__) || \
803 !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
804 snprintf(header, h.size() + 1,
"%s", h.c_str());
806 _snprintf_s(header, h.size() + 1, _TRUNCATE,
"%s", h.c_str());
810 unsigned int rows, cols;
814 if ((rows >= std::numeric_limits<unsigned int>::max()) || (cols >= std::numeric_limits<unsigned int>::max())) {
821 for (
unsigned int i = 0; i < rows; ++i) {
822 for (
unsigned int j = 0; j < cols; ++j) {
836 if (header !=
nullptr) {
837#if defined(__MINGW32__) || \
838 !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
839 snprintf(header, h.size() + 1,
"%s", h.c_str());
841 _snprintf_s(header, h.size() + 1, _TRUNCATE,
"%s", h.c_str());
845 unsigned int rows, cols;
846 file.read(
reinterpret_cast<char *
>(&rows),
sizeof(
unsigned int));
847 file.read(
reinterpret_cast<char *
>(&cols),
sizeof(
unsigned int));
851 for (
unsigned int i = 0; i < rows; ++i) {
852 for (
unsigned int j = 0; j < cols; ++j) {
853 file.read(
reinterpret_cast<char *
>(&value),
sizeof(Type));
878 file.open(filename.c_str(), std::fstream::in);
885 unsigned int rows = 0, cols = 0;
887 std::string line, subs;
888 bool inheader =
true;
889 unsigned int i = 0, j;
890 unsigned int lineStart = 0;
892 while (getline(file, line)) {
894 const std::string str_rows(
"rows:");
895 const std::string str_cols(
"cols:");
896 const std::string str_data(
"data:");
897 if ((rows == 0) && (line.compare(0, str_rows.size(), str_rows.c_str()) == 0)) {
898 std::stringstream ss(line);
902 else if ((cols == 0) && (line.compare(0, str_cols.size(), str_cols.c_str()) == 0)) {
903 std::stringstream ss(line);
907 else if (line.compare(0, str_data.size(), str_data.c_str()) == 0) {
918 if ((rows == 0) || (cols == 0)) {
924 lineStart =
static_cast<unsigned int>(line.find(
"[")) + 1;
926 std::stringstream ss(line.substr(lineStart, line.find(
"]") - lineStart));
928 while (getline(ss, subs,
',')) {
929 A[i][j++] =
static_cast<Type
>(atof(subs.c_str()));
935 if (header !=
nullptr) {
936 std::string h_ = h.substr(0, h.size() - 1);
937#if defined(__MINGW32__) || \
938 !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
939 snprintf(header, h_.size() + 1,
"%s", h_.c_str());
941 _snprintf_s(header, h_.size() + 1, _TRUNCATE,
"%s", h_.c_str());
965 static bool save(
const std::string &filename,
const vpArray2D<Type> &A,
bool binary =
false,
const char *header =
"")
970 file.open(filename.c_str(), std::fstream::out);
973 file.open(filename.c_str(), std::fstream::out | std::fstream::binary);
984 while (header[i] !=
'\0') {
986 if (header[i] ==
'\n') {
993 file << A << std::endl;
997 while (header[headerSize] !=
'\0') {
1000 file.write(header,
static_cast<std::streamsize
>(headerSize)+
static_cast<std::streamsize
>(1));
1001 unsigned int matrixSize;
1003 file.write(
reinterpret_cast<char *
>(&matrixSize),
sizeof(
unsigned int));
1005 file.write(
reinterpret_cast<char *
>(&matrixSize),
sizeof(
unsigned int));
1007 unsigned int a_rows = A.
getRows();
1008 unsigned int a_cols = A.
getCols();
1009 for (
unsigned int i = 0; i < a_rows; ++i) {
1010 for (
unsigned int j = 0; j < a_cols; ++j) {
1012 file.write(
reinterpret_cast<char *
>(&value),
sizeof(Type));
1067 file.open(filename.c_str(), std::fstream::out);
1075 bool inIndent =
false;
1076 std::string indent =
"";
1077 bool checkIndent =
true;
1078 while (header[i] !=
'\0') {
1082 if (header[i] ==
' ') {
1085 else if (indent.length() > 0) {
1086 checkIndent =
false;
1089 if ((header[i] ==
'\n') || (inIndent && (header[i] ==
' '))) {
1102 file <<
"rows: " << A.
getRows() << std::endl;
1103 file <<
"cols: " << A.
getCols() << std::endl;
1105 if (indent.length() == 0) {
1109 file <<
"data: " << std::endl;
1111 unsigned int a_rows = A.
getRows();
1112 unsigned int a_cols = A.
getCols();
1113 for (i = 0; i < a_rows; ++i) {
1114 file << indent <<
"- [";
1115 for (j = 0; j < (a_cols - 1); ++j) {
1116 file << A[i][j] <<
", ";
1118 file << A[i][j] <<
"]" << std::endl;
1124#ifdef VISP_HAVE_NLOHMANN_JSON
1192 const unsigned int s = A.
size();
1193 for (
unsigned int i = 0; i < s; ++i) {
1222 Type *dataptr =
data;
1223 Type min = *dataptr;
1225 for (
unsigned int i = 0; i < (
dsize - 1); ++i) {
1226 if (*dataptr < min) {
1239 Type *dataptr =
data;
1240 Type max = *dataptr;
1242 for (
unsigned int i = 0; i < (
dsize - 1); ++i) {
1243 if (*dataptr > max) {
1266 for (
unsigned int i = 0; i <
dsize; ++i) {
1276 for (
unsigned int i = 0; i <
rowNum; ++i) {
1277 for (
unsigned int j = 0; j <
colNum; ++j) {
1278 At[j][i] = (*this)[i][j];
1287 conv2(M, kernel, res, mode);
1297 if (mode ==
"valid") {
1305 if ((mode ==
"full") || (mode ==
"same")) {
1306 const unsigned int pad_x = kernel.
getCols() - 1;
1307 const unsigned int pad_y = kernel.
getRows() - 1;
1308 const unsigned int pad = 2;
1310 M_padded.
insert(M, pad_y, pad_x);
1312 if (mode ==
"same") {
1320 else if (mode ==
"valid") {
1328 if (mode ==
"same") {
1329 unsigned int res_same_rows = res_same.
getRows();
1330 unsigned int res_same_cols = res_same.
getCols();
1331 unsigned int kernel_rows = kernel.
getRows();
1332 unsigned int kernel_cols = kernel.
getCols();
1333 for (
unsigned int i = 0; i < res_same_rows; ++i) {
1334 for (
unsigned int j = 0; j < res_same_cols; ++j) {
1335 for (
unsigned int k = 0; k < kernel_rows; ++k) {
1336 for (
unsigned int l = 0; l < kernel_cols; ++l) {
1337 res_same[i][j] += M_padded[i + k][j + l] * kernel[kernel.
getRows() - k - 1][kernel.
getCols() - l - 1];
1343 const unsigned int start_i = kernel.
getRows() / 2;
1344 const unsigned int start_j = kernel.
getCols() / 2;
1345 unsigned int m_rows = M.
getRows();
1346 for (
unsigned int i = 0; i < m_rows; ++i) {
1352 unsigned int res_rows = res.
getRows();
1353 unsigned int res_cols = res.
getCols();
1354 unsigned int kernel_rows = kernel.
getRows();
1355 unsigned int kernel_cols = kernel.
getCols();
1356 for (
unsigned int i = 0; i < res_rows; ++i) {
1357 for (
unsigned int j = 0; j < res_cols; ++j) {
1358 for (
unsigned int k = 0; k < kernel_rows; ++k) {
1359 for (
unsigned int l = 0; l < kernel_cols; ++l) {
1360 res[i][j] += M_padded[i + k][j + l] * kernel[kernel.
getRows() - k - 1][kernel.
getCols() - l - 1];
1382 unsigned int a_rows = A.
getRows();
1383 unsigned int a_cols = A.
getCols();
1384 for (
unsigned int i = 0; i < a_rows; ++i) {
1385 for (
unsigned int j = 0; j < a_cols; ++j) {
1386 if ((i >= r) && (i < (r + B.
getRows())) && (j >= c) && (j < (c + B.
getCols()))) {
1387 C[i][j] = B[i - r][j - c];
1407 unsigned int a_size = A.
size();
1408 for (
unsigned int i = 0; i < a_size; ++i) {
1426 unsigned int a_size = A.
size();
1427 for (
unsigned int i = 0; i < a_size; ++i) {
1428 if (fabs(
data[i] - A.
data[i]) > std::numeric_limits<double>::epsilon()) {
1445 unsigned int a_size = A.
size();
1446 for (
unsigned int i = 0; i < a_size; ++i) {
1447 if (fabsf(
data[i] - A.
data[i]) > std::numeric_limits<float>::epsilon()) {
1460#ifdef VISP_HAVE_NLOHMANN_JSON
1461template <
class Type>
1465 const unsigned int nrows =
static_cast<unsigned int>(j.size());
1470 unsigned int ncols = 0;
1472 for (
const auto &item : j) {
1473 if (!item.is_array()) {
1478 ncols =
static_cast<unsigned int>(item.size());
1480 else if (ncols != item.size()) {
1484 array.
resize(nrows, ncols);
1486 for (
const auto &item : j) {
1487 std::vector<Type> row = item;
1488 std::copy(row.begin(), row.end(), array.
rowPtrs[i]);
1492 else if (
j.is_object()) {
1493 const unsigned ncols =
j.at(
"cols");
1494 const unsigned nrows =
j.at(
"rows");
1495 array.
resize(nrows, ncols);
1496 const nlohmann::json jData =
j.at(
"data");
1497 if (!jData.is_array() || jData.size() != nrows * ncols) {
1498 std::stringstream ss;
1499 ss <<
"JSON \"data\" field must be an array of size " << nrows * ncols;
1503 for (
const auto &jValue : jData) {
1504 array.
data[
i] = jValue;
1514template <
class Type>
1520 {
"type",
"vpArray2D"}
1523 nlohmann::json::array_t
data;
1525 for (
unsigned i = 0;
i < array.
size(); ++
i) {
Implementation of a generic 2D array used as base class for matrices and vectors.
vpArray2D(vpArray2D< Type > &&A) noexcept
unsigned int getCols() const
static void view(vpArray2D< Type > &v, Type *data, unsigned int numRows, unsigned int numCols)
Create an array view of a raw data pointer. After this function has been called, the array data can b...
Type * operator[](unsigned int i)
Set element using A[i][j] = x.
Type * data
Address of the first element of the data array.
vpArray2D(const vpArray2D< Type > &A)
bool isRowPtrsOwner
Whether this array owns the row pointers.
static bool loadYAML(const std::string &filename, vpArray2D< Type > &A, char *header=nullptr)
Type ** rowPtrs
Address of the first element of each rows.
vpArray2D(const std::vector< Type > &vec, unsigned int r=0, unsigned int c=0)
vpArray2D< Type > & operator=(Type x)
Set all the elements of the array to x.
void insert(const vpArray2D< Type > &A, unsigned int r, unsigned int c)
vpArray2D< Type > & operator=(const std::initializer_list< Type > &list)
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
vpArray2D< Type > & operator=(const vpArray2D< Type > &A)
Type * operator[](unsigned int i) const
Get element using x = A[i][j].
static bool saveYAML(const std::string &filename, const vpArray2D< Type > &A, const char *header="")
static vpArray2D< Type > view(const vpArray2D< Type > &A)
Creates a view of the Matrix A. A view shares the same underlying memory as the original array....
unsigned int rowNum
Number of rows in the array.
friend std::ostream & operator<<(std::ostream &s, const vpArray2D< Type > &A)
static vpArray2D< Type > view(Type *data, unsigned int numRows, unsigned int numCols)
Create an array view of a raw data pointer. This data is not owned by the resulting array and should ...
vpArray2D< Type > & operator=(const nlohmann::json &j)=delete
friend void to_json(nlohmann::json &j, const vpArray2D< T > &array)
VP_EXPLICIT vpArray2D(unsigned int nrows, unsigned int ncols, const std::initializer_list< Type > &list)
static vpArray2D< Type > conv2(const vpArray2D< Type > &M, const vpArray2D< Type > &kernel, const std::string &mode)
unsigned int dsize
Current array size (rowNum * colNum).
unsigned int size() const
Return the number of elements of the 2D array.
VP_EXPLICIT vpArray2D(const std::initializer_list< Type > &list)
static bool load(const std::string &filename, vpArray2D< Type > &A, bool binary=false, char *header=nullptr)
VP_EXPLICIT vpArray2D(const std::initializer_list< std::initializer_list< Type > > &lists)
vpArray2D< Type > & operator=(const std::initializer_list< std::initializer_list< Type > > &lists)
vpArray2D< Type > & operator=(vpArray2D< Type > &&other) noexcept
vpArray2D< Type > t() const
Compute the transpose of the array.
static bool isFinite(const vpArray2D< double > &A)
unsigned int getRows() const
bool operator!=(const vpArray2D< Type > &A) const
bool isMemoryOwner
Whether this array owns the memory it points to.
vpArray2D(unsigned int r, unsigned int c, Type val)
vpArray2D(unsigned int r, unsigned int c)
vpArray2D< Type > hadamard(const vpArray2D< Type > &m) const
static bool save(const std::string &filename, const vpArray2D< Type > &A, bool binary=false, const char *header="")
friend void from_json(const nlohmann::json &j, vpArray2D< T > &array)
void reshape(unsigned int nrows, unsigned int ncols)
unsigned int colNum
Number of columns in the array.
bool operator==(const vpArray2D< Type > &A) const
error that can be emitted by ViSP classes.
@ badValue
Used to indicate that a value is not in the allowed range.
@ dimensionError
Bad dimension.
@ memoryAllocationError
Memory allocation error.
static bool isFinite(double value)