From 8badff598e97227c1a3e923f709d32b0c4ef4651 Mon Sep 17 00:00:00 2001 From: Maxim Smolskiy Date: Thu, 6 Feb 2025 18:47:07 +0300 Subject: [PATCH] Merge pull request #26871 from MaximSmolskiy:fix-filestorage_io_test-test_base64-for-64-bit-integer-types Support 64-bit integer types for FileStorage Base64 #26871 ### Pull Request Readiness Checklist Related to https://github.com/opencv/opencv/pull/26846#issuecomment-2618159277 OpenCV extra: https://github.com/opencv/opencv_extra/pull/1232 See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake --- modules/core/src/persistence.cpp | 15 +++ .../core/src/persistence_base64_encoding.cpp | 7 ++ modules/core/src/persistence_impl.hpp | 2 + modules/core/test/test_io.cpp | 98 +++++++++++++++---- 4 files changed, 104 insertions(+), 18 deletions(-) diff --git a/modules/core/src/persistence.cpp b/modules/core/src/persistence.cpp index e3240d3d1d..a1eeec41ea 100644 --- a/modules/core/src/persistence.cpp +++ b/modules/core/src/persistence.cpp @@ -1818,6 +1818,15 @@ int FileStorage::Impl::Base64Decoder::getInt32() { return ival; } +int64_t FileStorage::Impl::Base64Decoder::getInt64() { + size_t sz = decoded.size(); + if (ofs + 8 > sz && !readMore(8)) + return 0; + int64_t ival = readLong(&decoded[ofs]); + ofs += 8; + return ival; +} + double FileStorage::Impl::Base64Decoder::getFloat64() { size_t sz = decoded.size(); if (ofs + 8 > sz && !readMore(8)) @@ -1876,6 +1885,12 @@ char *FileStorage::Impl::parseBase64(char *ptr, int indent, FileNode &collection case CV_32S: ival = base64decoder.getInt32(); break; + case CV_64U: + ival = base64decoder.getInt64(); + break; + case CV_64S: + ival = base64decoder.getInt64(); + break; case CV_32F: { Cv32suf v; v.i = base64decoder.getInt32(); diff --git a/modules/core/src/persistence_base64_encoding.cpp b/modules/core/src/persistence_base64_encoding.cpp index 3fce79c080..a7225c0ded 100644 --- a/modules/core/src/persistence_base64_encoding.cpp +++ b/modules/core/src/persistence_base64_encoding.cpp @@ -208,6 +208,8 @@ int base64::icvCalcStructSize(const char *dt, int initial_size) { case 'i': { elem_max_size = std::max( elem_max_size, sizeof(int ) ); break; } case 'f': { elem_max_size = std::max( elem_max_size, sizeof(float ) ); break; } case 'd': { elem_max_size = std::max( elem_max_size, sizeof(double) ); break; } + case 'I': { elem_max_size = std::max( elem_max_size, sizeof(int64_t)); break; } + case 'U': { elem_max_size = std::max( elem_max_size, sizeof(uint64_t)); break; } default: break; } } @@ -347,6 +349,11 @@ size_t base64::RawDataToBinaryConvertor::make_to_binary_funcs(const std::string size = sizeof(double); pack.func = to_binary; break; + case 'I': + case 'U': + size = sizeof(uint64_t); + pack.func = to_binary; + break; case 'r': default: CV_Error(cv::Error::StsError, "type is not supported"); diff --git a/modules/core/src/persistence_impl.hpp b/modules/core/src/persistence_impl.hpp index 7f902079a5..11a83f2253 100644 --- a/modules/core/src/persistence_impl.hpp +++ b/modules/core/src/persistence_impl.hpp @@ -151,6 +151,8 @@ public: int getInt32(); + int64_t getInt64(); + double getFloat64(); bool endOfStream() const; diff --git a/modules/core/test/test_io.cpp b/modules/core/test/test_io.cpp index cfa2b7ff71..d6a611dfd1 100644 --- a/modules/core/test/test_io.cpp +++ b/modules/core/test/test_io.cpp @@ -601,17 +601,31 @@ static void test_filestorage_basic(int write_flags, const char* suffix_name, boo std::vector rawdata; cv::Mat _em_out, _em_in; - cv::Mat _2d_out, _2d_in; + cv::Mat _2d_out_u8, _2d_in_u8; + cv::Mat _2d_out_i64, _2d_in_i64; + cv::Mat _2d_out_u64, _2d_in_u64; cv::Mat _nd_out, _nd_in; cv::Mat _rd_out(8, 16, CV_64FC1), _rd_in; { /* init */ - /* a normal mat */ - _2d_out = cv::Mat(10, 20, CV_8UC3, cv::Scalar(1U, 2U, 127U)); - for (int i = 0; i < _2d_out.rows; ++i) - for (int j = 0; j < _2d_out.cols; ++j) - _2d_out.at(i, j)[1] = (i + j) % 256; + /* a normal mat u8 */ + _2d_out_u8 = cv::Mat(10, 20, CV_8UC3, cv::Scalar(1U, 2U, 127U)); + for (int i = 0; i < _2d_out_u8.rows; ++i) + for (int j = 0; j < _2d_out_u8.cols; ++j) + _2d_out_u8.at(i, j)[1] = (i + j) % 256; + + /* a normal mat i64 */ + _2d_out_i64 = cv::Mat(10, 20, CV_64SC3, cv::Scalar(1LL, 2LL, 2251799813685247LL)); + for (int i = 0; i < _2d_out_i64.rows; ++i) + for (int j = 0; j < _2d_out_i64.cols; ++j) + _2d_out_i64.at(i, j)[1] = i + j; + + /* a normal mat u64 */ + _2d_out_u64 = cv::Mat(10, 20, CV_64UC3, cv::Scalar(1ULL, 2ULL, 4503599627370495ULL)); + for (int i = 0; i < _2d_out_u64.rows; ++i) + for (int j = 0; j < _2d_out_u64.cols; ++j) + _2d_out_u64.at>(i, j)[1] = i + j; /* a 4d mat */ const int Size[] = {4, 4, 4, 4}; @@ -643,7 +657,9 @@ static void test_filestorage_basic(int write_flags, const char* suffix_name, boo if (testReadWrite || useMemory || generateTestData) { cv::FileStorage fs(name, write_flags + (useMemory ? cv::FileStorage::MEMORY : 0)); - fs << "normal_2d_mat" << _2d_out; + fs << "normal_2d_mat_u8" << _2d_out_u8; + fs << "normal_2d_mat_i64" << _2d_out_i64; + fs << "normal_2d_mat_u64" << _2d_out_u64; fs << "normal_nd_mat" << _nd_out; fs << "empty_2d_mat" << _em_out; fs << "random_mat" << _rd_out; @@ -686,14 +702,16 @@ static void test_filestorage_basic(int write_flags, const char* suffix_name, boo } } std::cout << "Storage size: " << sz << std::endl; - EXPECT_LE(sz, (size_t)6000); + EXPECT_LE(sz, (size_t)21000); } { /* read */ cv::FileStorage fs(name, cv::FileStorage::READ + (useMemory ? cv::FileStorage::MEMORY : 0)); /* mat */ fs["empty_2d_mat"] >> _em_in; - fs["normal_2d_mat"] >> _2d_in; + fs["normal_2d_mat_u8"] >> _2d_in_u8; + fs["normal_2d_mat_i64"] >> _2d_in_i64; + fs["normal_2d_mat_u64"] >> _2d_in_u64; fs["normal_nd_mat"] >> _nd_in; fs["random_mat"] >> _rd_in; @@ -729,22 +747,66 @@ static void test_filestorage_basic(int write_flags, const char* suffix_name, boo EXPECT_EQ(_em_in.depth(), _em_out.depth()); EXPECT_TRUE(_em_in.empty()); - ASSERT_EQ(_2d_in.rows , _2d_out.rows); - ASSERT_EQ(_2d_in.cols , _2d_out.cols); - ASSERT_EQ(_2d_in.dims , _2d_out.dims); - ASSERT_EQ(_2d_in.depth(), _2d_out.depth()); + ASSERT_EQ(_2d_in_u8.rows , _2d_out_u8.rows); + ASSERT_EQ(_2d_in_u8.cols , _2d_out_u8.cols); + ASSERT_EQ(_2d_in_u8.dims , _2d_out_u8.dims); + ASSERT_EQ(_2d_in_u8.depth(), _2d_out_u8.depth()); + + ASSERT_EQ(_2d_in_i64.rows , _2d_out_i64.rows); + ASSERT_EQ(_2d_in_i64.cols , _2d_out_i64.cols); + ASSERT_EQ(_2d_in_i64.dims , _2d_out_i64.dims); + ASSERT_EQ(_2d_in_i64.depth(), _2d_out_i64.depth()); + + ASSERT_EQ(_2d_in_u64.rows , _2d_out_u64.rows); + ASSERT_EQ(_2d_in_u64.cols , _2d_out_u64.cols); + ASSERT_EQ(_2d_in_u64.dims , _2d_out_u64.dims); + ASSERT_EQ(_2d_in_u64.depth(), _2d_out_u64.depth()); errors = 0; - for(int i = 0; i < _2d_out.rows; ++i) + for(int i = 0; i < _2d_out_u8.rows; ++i) { - for (int j = 0; j < _2d_out.cols; ++j) + for (int j = 0; j < _2d_out_u8.cols; ++j) { - if (_2d_in.at(i, j) != _2d_out.at(i, j)) { - EXPECT_EQ(_2d_in.at(i, j), _2d_out.at(i, j)); + if (_2d_in_u8.at(i, j) != _2d_out_u8.at(i, j)) { + EXPECT_EQ(_2d_in_u8.at(i, j), _2d_out_u8.at(i, j)); printf("i = %d, j = %d\n", i, j); if (++errors >= 3) { - i = _2d_out.rows; + i = _2d_out_u8.rows; + break; + } + } + } + } + + errors = 0; + for(int i = 0; i < _2d_out_i64.rows; ++i) + { + for (int j = 0; j < _2d_out_i64.cols; ++j) + { + if (_2d_in_i64.at(i, j) != _2d_out_i64.at(i, j)) { + EXPECT_EQ(_2d_in_i64.at(i, j), _2d_out_i64.at(i, j)); + printf("i = %d, j = %d\n", i, j); + if (++errors >= 3) + { + i = _2d_out_i64.rows; + break; + } + } + } + } + + errors = 0; + for(int i = 0; i < _2d_out_u64.rows; ++i) + { + for (int j = 0; j < _2d_out_u64.cols; ++j) + { + if (_2d_in_u64.at>(i, j) != _2d_out_u64.at>(i, j)) { + EXPECT_EQ((_2d_in_u64.at>(i, j)), (_2d_out_u64.at>(i, j))); + printf("i = %d, j = %d\n", i, j); + if (++errors >= 3) + { + i = _2d_out_u64.rows; break; } }