46 #include <visp3/core/vpConfig.h>
47 #include <visp3/core/vpException.h>
49 #ifdef VISP_HAVE_NLOHMANN_JSON
50 #include <nlohmann/json.hpp>
153 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
171 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
189 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
195 resize(r, c,
false,
false);
210 vpArray2D<Type>(
const std::vector<Type> &vec,
unsigned int r = 0,
unsigned int c = 0)
212 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
218 if (r > 0 && c > 0) {
219 if ((r * c) != vec.size()) {
221 "Cannot initialize vpArray(%d, %d) from std::vector(%d). Wrong dimension", r, c, vec.size()));
223 resize(r, c,
false,
false);
225 else if ((c == 0) && (r == 0)) {
227 "Cannot initialize vpArray(%d, %d) from std::vector(%d). Using rows = 0 and cols = 0 is ambiguous", r, c, vec.size()));
230 if (r != vec.size()) {
232 "Cannot initialize vpArray(%d, %d) from std::vector(%d). Wrong dimension", r, c, vec.size()));
234 resize(
static_cast<unsigned int>(vec.size()), 1,
false,
false);
237 if (c != vec.size()) {
239 "Cannot initialize vpArray(%d, %d) from std::vector(%d). Wrong dimension", r, c, vec.size()));
241 resize(1,
static_cast<unsigned int>(vec.size()),
false,
false);
244 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
245 std::copy(vec.begin(), vec.end(),
data);
247 memcpy(
data, vec.data(), vec.size() *
sizeof(Type));
251 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
269 resize(1,
static_cast<unsigned int>(list.size()),
false,
false);
270 std::copy(list.begin(), list.end(),
data);
273 explicit vpArray2D<Type>(
unsigned int nrows,
unsigned int ncols,
const std::initializer_list<Type> &list)
276 if (nrows * ncols !=
static_cast<unsigned int>(list.size())) {
277 std::ostringstream oss;
278 oss <<
"Cannot create a vpArray2D of size (" << nrows <<
", " << ncols <<
") with a list of size " << list.size();
282 resize(nrows, ncols,
false,
false);
283 std::copy(list.begin(), list.end(),
data);
288 unsigned int nrows =
static_cast<unsigned int>(lists.size()), ncols = 0;
289 for (
auto &l : lists) {
290 if (
static_cast<unsigned int>(l.size()) > ncols) {
291 ncols =
static_cast<unsigned int>(l.size());
295 resize(nrows, ncols,
false,
false);
296 auto it = lists.begin();
297 for (
unsigned int i = 0; i <
rowNum; i++, ++it) {
298 std::copy(it->begin(), it->end(),
rowPtrs[i]);
308 if (
data !=
nullptr) {
352 void resize(
unsigned int nrows,
unsigned int ncols,
bool flagNullify =
true,
bool recopy_ =
true)
355 if (flagNullify && this->data !=
nullptr) {
356 memset(this->data, 0, this->dsize *
sizeof(Type));
360 bool recopy = !flagNullify && recopy_;
361 const bool recopyNeeded = (ncols != this->colNum && this->colNum > 0 && ncols > 0 && (!flagNullify || recopy));
362 Type *copyTmp =
nullptr;
363 unsigned int rowTmp = 0, colTmp = 0;
367 if (recopyNeeded && this->data !=
nullptr) {
368 copyTmp =
new Type[this->
dsize];
369 memcpy(copyTmp, this->data,
sizeof(Type) * this->dsize);
375 this->dsize = nrows * ncols;
376 Type *tmp_data =
reinterpret_cast<Type *
>(realloc(this->data, this->dsize *
sizeof(Type)));
378 this->data = tmp_data;
381 this->data =
nullptr;
384 if ((
nullptr == this->data) && (0 != this->
dsize)) {
385 if (copyTmp !=
nullptr) {
391 Type **tmp_rowPtrs =
reinterpret_cast<Type **
>(realloc(this->rowPtrs, nrows *
sizeof(Type *)));
393 this->rowPtrs = tmp_rowPtrs;
396 this->rowPtrs =
nullptr;
398 if ((
nullptr == this->rowPtrs) && (0 != this->
dsize)) {
399 if (copyTmp !=
nullptr) {
403 "Memory allocation error when allocating 2D array rowPtrs"));
409 for (
unsigned int i = 0; i <
dsize; i += ncols) {
410 *t_++ = this->data + i;
414 this->rowNum = nrows;
415 this->colNum = ncols;
419 memset(this->data, 0, (
size_t)(this->dsize) *
sizeof(Type));
421 else if (recopyNeeded && this->rowPtrs !=
nullptr) {
423 unsigned int minRow = (this->rowNum < rowTmp) ? this->rowNum : rowTmp;
424 unsigned int minCol = (this->colNum < colTmp) ? this->colNum : colTmp;
425 for (
unsigned int i = 0; i < this->
rowNum; ++i) {
426 for (
unsigned int j = 0; j < this->
colNum; ++j) {
427 if ((minRow > i) && (minCol > j)) {
428 (*this)[i][j] = copyTmp[i * colTmp + j];
437 if (copyTmp !=
nullptr) {
443 void reshape(
unsigned int nrows,
unsigned int ncols)
450 if (nrows * ncols !=
dsize) {
451 std::ostringstream oss;
452 oss <<
"Cannot reshape array of total size " <<
dsize <<
" into shape (" << nrows <<
", " << ncols <<
")";
459 Type **tmp =
reinterpret_cast<Type **
>(realloc(
rowPtrs, nrows *
sizeof(Type *)));
467 for (
unsigned int i = 0; i <
dsize; i += ncols) {
491 for (
unsigned int i = r; i < (r + A.
getRows()); ++i) {
530 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
533 if (
this != &other) {
549 other.rowPtrs =
nullptr;
551 other.data =
nullptr;
559 if (
dsize !=
static_cast<unsigned int>(list.size())) {
560 resize(1,
static_cast<unsigned int>(list.size()),
false,
false);
562 std::copy(list.begin(), list.end(),
data);
569 unsigned int nrows =
static_cast<unsigned int>(lists.size()), ncols = 0;
570 for (
auto &l : lists) {
571 if (
static_cast<unsigned int>(l.size()) > ncols) {
572 ncols =
static_cast<unsigned int>(l.size());
576 resize(nrows, ncols,
false,
false);
577 auto it = lists.begin();
578 for (
unsigned int i = 0; i <
rowNum; i++, ++it) {
579 std::copy(it->begin(), it->end(),
rowPtrs[i]);
585 #ifdef VISP_HAVE_NLOHMANN_JSON
602 if (A.
data ==
nullptr || A.
size() == 0) {
605 std::ios_base::fmtflags original_flags = s.flags();
608 for (
unsigned int i = 0; i < A.
getRows(); ++i) {
609 for (
unsigned int j = 0; j < A.
getCols() - 1; ++j) {
615 if (i < A.getRows() - 1) {
620 s.flags(original_flags);
653 static bool load(
const std::string &filename,
vpArray2D<Type> &A,
bool binary =
false,
char *header =
nullptr)
658 file.open(filename.c_str(), std::fstream::in);
661 file.open(filename.c_str(), std::fstream::in | std::fstream::binary);
671 bool headerIsDecoded =
false;
673 std::streampos pos = file.tellg();
675 file.getline(line, 256);
676 std::string prefix(
"# ");
677 std::string line_(line);
678 if (line_.compare(0, 2, prefix.c_str()) == 0) {
685 h += line_.substr(2);
689 file.seekg(pos, file.beg);
690 headerIsDecoded =
true;
692 }
while (!headerIsDecoded);
694 if (header !=
nullptr) {
695 #if defined(__MINGW32__) || \
696 !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
697 snprintf(header, h.size() + 1,
"%s", h.c_str());
699 _snprintf_s(header, h.size() + 1, _TRUNCATE,
"%s", h.c_str());
703 unsigned int rows, cols;
707 if (rows >= (std::numeric_limits<unsigned int>::max)() || cols >= (std::numeric_limits<unsigned int>::max)()) {
714 for (
unsigned int i = 0; i < rows; ++i) {
715 for (
unsigned int j = 0; j < cols; ++j) {
729 if (header !=
nullptr) {
730 #if defined(__MINGW32__) || \
731 !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
732 snprintf(header, h.size() + 1,
"%s", h.c_str());
734 _snprintf_s(header, h.size() + 1, _TRUNCATE,
"%s", h.c_str());
738 unsigned int rows, cols;
739 file.read((
char *)&rows,
sizeof(
unsigned int));
740 file.read((
char *)&cols,
sizeof(
unsigned int));
744 for (
unsigned int i = 0; i < rows; ++i) {
745 for (
unsigned int j = 0; j < cols; ++j) {
746 file.read((
char *)&value,
sizeof(Type));
771 file.open(filename.c_str(), std::fstream::in);
778 unsigned int rows = 0, cols = 0;
780 std::string line, subs;
781 bool inheader =
true;
782 unsigned int i = 0, j;
783 unsigned int lineStart = 0;
785 while (getline(file, line)) {
787 if (rows == 0 && line.compare(0, 5,
"rows:") == 0) {
788 std::stringstream ss(line);
792 else if (cols == 0 && line.compare(0, 5,
"cols:") == 0) {
793 std::stringstream ss(line);
797 else if (line.compare(0, 5,
"data:") == 0) {
808 if (rows == 0 || cols == 0) {
814 lineStart = (
unsigned int)line.find(
"[") + 1;
816 std::stringstream ss(line.substr(lineStart, line.find(
"]") - lineStart));
818 while (getline(ss, subs,
',')) {
819 A[i][j++] = atof(subs.c_str());
825 if (header !=
nullptr) {
826 std::string h_ = h.substr(0, h.size() - 1);
827 #if defined(__MINGW32__) || \
828 !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
829 snprintf(header, h_.size() + 1,
"%s", h_.c_str());
831 _snprintf_s(header, h_.size() + 1, _TRUNCATE,
"%s", h_.c_str());
855 static bool save(
const std::string &filename,
const vpArray2D<Type> &A,
bool binary =
false,
const char *header =
"")
860 file.open(filename.c_str(), std::fstream::out);
863 file.open(filename.c_str(), std::fstream::out | std::fstream::binary);
874 while (header[i] !=
'\0') {
876 if (header[i] ==
'\n') {
883 file << A << std::endl;
887 while (header[headerSize] !=
'\0') {
890 file.write(header, (
size_t)headerSize + (
size_t)1);
891 unsigned int matrixSize;
893 file.write((
char *)&matrixSize,
sizeof(
unsigned int));
895 file.write((
char *)&matrixSize,
sizeof(
unsigned int));
897 for (
unsigned int i = 0; i < A.
getRows(); ++i) {
898 for (
unsigned int j = 0; j < A.
getCols(); ++j) {
900 file.write((
char *)&value,
sizeof(Type));
954 file.open(filename.c_str(), std::fstream::out);
962 bool inIndent =
false;
963 std::string indent =
"";
964 bool checkIndent =
true;
965 while (header[i] !=
'\0') {
969 if (header[i] ==
' ') {
972 else if (indent.length() > 0) {
976 if (header[i] ==
'\n' || (inIndent && header[i] ==
' ')) {
989 file <<
"rows: " << A.
getRows() << std::endl;
990 file <<
"cols: " << A.
getCols() << std::endl;
992 if (indent.length() == 0) {
996 file <<
"data: " << std::endl;
998 for (i = 0; i < A.
getRows(); ++i) {
999 file << indent <<
"- [";
1000 for (j = 0; j < A.
getCols() - 1; ++j) {
1001 file << A[i][j] <<
", ";
1003 file << A[i][j] <<
"]" << std::endl;
1009 #ifdef VISP_HAVE_NLOHMANN_JSON
1081 Type *dataptr = data;
1082 Type min = *dataptr;
1084 for (
unsigned int i = 0; i < dsize - 1; ++i) {
1085 if (*dataptr < min) {
1098 Type *dataptr = data;
1099 Type max = *dataptr;
1101 for (
unsigned int i = 0; i < dsize - 1; ++i) {
1102 if (*dataptr > max) {
1123 out.
resize(rowNum, colNum,
false);
1125 for (
unsigned int i = 0; i < dsize; ++i) {
1135 for (
unsigned int i = 0; i < rowNum; ++i) {
1136 for (
unsigned int j = 0; j < colNum; ++j) {
1137 At[j][i] = (*this)[i][j];
1146 conv2(M, kernel, res, mode);
1155 if (mode ==
"valid") {
1162 if (mode ==
"full" || mode ==
"same") {
1163 const unsigned int pad_x = kernel.
getCols() - 1;
1164 const unsigned int pad_y = kernel.
getRows() - 1;
1166 M_padded.
insert(M, pad_y, pad_x);
1168 if (mode ==
"same") {
1176 else if (mode ==
"valid") {
1184 if (mode ==
"same") {
1185 for (
unsigned int i = 0; i < res_same.
getRows(); ++i) {
1186 for (
unsigned int j = 0; j < res_same.
getCols(); ++j) {
1187 for (
unsigned int k = 0; k < kernel.
getRows(); ++k) {
1188 for (
unsigned int l = 0; l < kernel.
getCols(); ++l) {
1189 res_same[i][j] += M_padded[i + k][j + l] * kernel[kernel.
getRows() - k - 1][kernel.
getCols() - l - 1];
1195 const unsigned int start_i = kernel.
getRows() / 2;
1196 const unsigned int start_j = kernel.
getCols() / 2;
1197 for (
unsigned int i = 0; i < M.
getRows(); ++i) {
1203 for (
unsigned int i = 0; i < res.
getRows(); ++i) {
1204 for (
unsigned int j = 0; j < res.
getCols(); ++j) {
1205 for (
unsigned int k = 0; k < kernel.
getRows(); ++k) {
1206 for (
unsigned int l = 0; l < kernel.
getCols(); ++l) {
1207 res[i][j] += M_padded[i + k][j + l] * kernel[kernel.
getRows() - k - 1][kernel.
getCols() - l - 1];
1229 for (
unsigned int i = 0; i < A.
getRows(); ++i) {
1230 for (
unsigned int j = 0; j < A.
getCols(); ++j) {
1231 if (i >= r && i < (r + B.
getRows()) && j >= c && j < (c + B.
getCols())) {
1232 C[i][j] = B[i - r][j - c];
1252 for (
unsigned int i = 0; i < A.
size(); ++i) {
1253 if (data[i] != A.
data[i]) {
1270 for (
unsigned int i = 0; i < A.
size(); ++i) {
1271 if (fabs(
data[i] - A.
data[i]) > std::numeric_limits<double>::epsilon()) {
1288 for (
unsigned int i = 0; i < A.
size(); ++i) {
1289 if (fabsf(
data[i] - A.
data[i]) > std::numeric_limits<float>::epsilon()) {
1302 #ifdef VISP_HAVE_NLOHMANN_JSON
1305 template <
class Type>
1306 inline void from_json(
const nlohmann::json &j,
vpArray2D<Type> &array)
1309 const unsigned int nrows =
static_cast<unsigned int>(j.size());
1314 unsigned int ncols = 0;
1316 for (
const auto &item : j) {
1317 if (!item.is_array()) {
1322 ncols =
static_cast<unsigned int>(item.size());
1324 else if (ncols != item.size()) {
1328 array.
resize(nrows, ncols);
1330 for (
const auto &item : j) {
1331 std::vector<Type> row = item;
1332 std::copy(row.begin(), row.end(), array.
rowPtrs[i]);
1336 else if (j.is_object()) {
1337 const unsigned ncols = j.at(
"cols");
1338 const unsigned nrows = j.at(
"rows");
1339 array.
resize(nrows, ncols);
1340 const nlohmann::json jData = j.at(
"data");
1341 if (!jData.is_array() || jData.size() != nrows * ncols) {
1342 std::stringstream ss;
1343 ss <<
"JSON \"data\" field must be an array of size " << nrows * ncols;
1347 for (
const auto &jValue : jData) {
1348 array.
data[i] = jValue;
1358 template <
class Type>
1364 {
"type",
"vpArray2D"}
1367 nlohmann::json::array_t data;
1368 data.reserve(array.
size());
1369 for (
unsigned i = 0; i < array.
size(); ++i) {
1370 data.push_back(array.
data[i]);
Implementation of a generic 2D array used as base class for matrices and vectors.
unsigned int getCols() const
vpArray2D< Type > insert(const vpArray2D< Type > &A, const vpArray2D< Type > &B, unsigned int r, unsigned int c)
static void conv2(const vpArray2D< Type > &M, const vpArray2D< Type > &kernel, vpArray2D< Type > &res, const std::string &mode)
Type * data
Address of the first element of the data array.
static bool loadYAML(const std::string &filename, vpArray2D< Type > &A, char *header=nullptr)
Type ** rowPtrs
Address of the first element of each rows.
void insert(const vpArray2D< Type > &A, unsigned int r, unsigned int c)
vpArray2D< Type > & operator=(const vpArray2D< Type > &A)
Type * operator[](unsigned int i)
Set element using A[i][j] = x.
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
static void insert(const vpArray2D< Type > &A, const vpArray2D< Type > &B, vpArray2D< Type > &C, unsigned int r, unsigned int c)
static bool saveYAML(const std::string &filename, const vpArray2D< Type > &A, const char *header="")
unsigned int rowNum
Number of rows in the array.
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)
friend std::ostream & operator<<(std::ostream &s, const vpArray2D< Type > &A)
unsigned int dsize
Current array size (rowNum * colNum)
unsigned int size() const
Return the number of elements of the 2D array.
static bool load(const std::string &filename, vpArray2D< Type > &A, bool binary=false, char *header=nullptr)
vpArray2D< Type > t() const
Compute the transpose of the array.
unsigned int getRows() const
bool operator!=(const vpArray2D< Type > &A) const
vpArray2D< Type > & operator=(Type x)
Set all the elements of the array to x.
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)
Type * operator[](unsigned int i) const
Get element using x = A[i][j].
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.