From 77eb6ed52dfb43e682db1b02ae916787d7e7c11a Mon Sep 17 00:00:00 2001 From: Maxim Smolskiy Date: Fri, 7 Mar 2025 08:35:44 +0300 Subject: [PATCH] Merge pull request #26937 from MaximSmolskiy:support-bool-type-for-filestorage-base64 Support bool type for FileStorage Base64 #26937 ### Pull Request Readiness Checklist OpenCV extra: https://github.com/opencv/opencv_extra/pull/1238 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 | 3 +++ modules/core/src/persistence_base64_encoding.cpp | 5 +++++ modules/core/src/persistence_base64_encoding.hpp | 5 +++++ modules/core/test/test_io.cpp | 10 +++++++++- modules/python/test/test_filestorage_io.py | 11 +++++++++-- 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/modules/core/src/persistence.cpp b/modules/core/src/persistence.cpp index 8279ab4d26..673a4f8a80 100644 --- a/modules/core/src/persistence.cpp +++ b/modules/core/src/persistence.cpp @@ -1876,6 +1876,9 @@ char *FileStorage::Impl::parseBase64(char *ptr, int indent, FileNode &collection case CV_8S: ival = (char) base64decoder.getUInt8(); break; + case CV_Bool: + ival = base64decoder.getUInt8() != 0; + break; case CV_16U: ival = base64decoder.getUInt16(); break; diff --git a/modules/core/src/persistence_base64_encoding.cpp b/modules/core/src/persistence_base64_encoding.cpp index efb173f80b..149117d436 100644 --- a/modules/core/src/persistence_base64_encoding.cpp +++ b/modules/core/src/persistence_base64_encoding.cpp @@ -202,6 +202,7 @@ int base64::icvCalcStructSize(const char *dt, int initial_size) { switch ( *type ) { case 'u': { elem_max_size = std::max( elem_max_size, sizeof(uchar ) ); break; } + case 'b': { elem_max_size = std::max( elem_max_size, sizeof(uchar ) ); break; } case 'c': { elem_max_size = std::max( elem_max_size, sizeof(schar ) ); break; } case 'w': { elem_max_size = std::max( elem_max_size, sizeof(ushort) ); break; } case 's': { elem_max_size = std::max( elem_max_size, sizeof(short ) ); break; } @@ -333,6 +334,10 @@ size_t base64::RawDataToBinaryConvertor::make_to_binary_funcs(const std::string size = sizeof(uchar); pack.func = to_binary; break; + case 'b': + size = sizeof(uchar); + pack.func = to_binary; + break; case 'w': case 's': size = sizeof(ushort); diff --git a/modules/core/src/persistence_base64_encoding.hpp b/modules/core/src/persistence_base64_encoding.hpp index 8b66e94095..f36a95e6bb 100644 --- a/modules/core/src/persistence_base64_encoding.hpp +++ b/modules/core/src/persistence_base64_encoding.hpp @@ -68,6 +68,11 @@ to_binary(_uint_t val, uchar * cur) return sizeof(_uint_t); } +template<> inline size_t to_binary(bool val, uchar * cur) +{ + return to_binary(static_cast(val), cur); +} + template<> inline size_t to_binary(double val, uchar * cur) { Cv64suf bit64; diff --git a/modules/core/test/test_io.cpp b/modules/core/test/test_io.cpp index dc3d4a5328..fc1e5da983 100644 --- a/modules/core/test/test_io.cpp +++ b/modules/core/test/test_io.cpp @@ -605,6 +605,7 @@ static void test_filestorage_basic(int write_flags, const char* suffix_name, boo cv::Mat _2d_out_u32, _2d_in_u32; cv::Mat _2d_out_i64, _2d_in_i64; cv::Mat _2d_out_u64, _2d_in_u64; + cv::Mat _2d_out_bool, _2d_in_bool; cv::Mat _nd_out, _nd_in; cv::Mat _rd_out(8, 16, CV_64FC1), _rd_in; @@ -639,6 +640,10 @@ static void test_filestorage_basic(int write_flags, const char* suffix_name, boo /* a random mat */ cv::randu(_rd_out, cv::Scalar(0.0), cv::Scalar(1.0)); + /* a normal mat bool */ + _2d_out_bool = Mat(10, 20, CV_BoolC3); + cv::randu(_2d_out_bool, 0U, 2U); + /* raw data */ for (int i = 0; i < (int)rawdata_N; i++) { data_t tmp; @@ -660,6 +665,7 @@ static void test_filestorage_basic(int write_flags, const char* suffix_name, boo fs << "normal_2d_mat_u32" << _2d_out_u32; fs << "normal_2d_mat_i64" << _2d_out_i64; fs << "normal_2d_mat_u64" << _2d_out_u64; + fs << "normal_2d_mat_bool" << _2d_out_bool; fs << "normal_nd_mat" << _nd_out; fs << "empty_2d_mat" << _em_out; fs << "random_mat" << _rd_out; @@ -702,7 +708,7 @@ 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)24000); + EXPECT_LE(sz, (size_t)25000); } { /* read */ cv::FileStorage fs(name, cv::FileStorage::READ + (useMemory ? cv::FileStorage::MEMORY : 0)); @@ -713,6 +719,7 @@ static void test_filestorage_basic(int write_flags, const char* suffix_name, boo fs["normal_2d_mat_u32"] >> _2d_in_u32; fs["normal_2d_mat_i64"] >> _2d_in_i64; fs["normal_2d_mat_u64"] >> _2d_in_u64; + fs["normal_2d_mat_bool"] >> _2d_in_bool; fs["normal_nd_mat"] >> _nd_in; fs["random_mat"] >> _rd_in; @@ -752,6 +759,7 @@ static void test_filestorage_basic(int write_flags, const char* suffix_name, boo EXPECT_MAT_NEAR(_2d_in_u32, _2d_out_u32, 0); EXPECT_MAT_NEAR(_2d_in_i64, _2d_out_i64, 0); EXPECT_MAT_NEAR(_2d_in_u64, _2d_out_u64, 0); + EXPECT_MAT_NEAR(_2d_in_bool, _2d_out_bool, 0); ASSERT_EQ(_nd_in.rows , _nd_out.rows); ASSERT_EQ(_nd_in.cols , _nd_out.cols); diff --git a/modules/python/test/test_filestorage_io.py b/modules/python/test/test_filestorage_io.py index 08e4d4e215..9af3204517 100644 --- a/modules/python/test/test_filestorage_io.py +++ b/modules/python/test/test_filestorage_io.py @@ -125,11 +125,17 @@ class filestorage_io_test(NewOpenCVTests): cn = 3 image = np.zeros((rows, cols, cn), dtype) - image[:] = (1, 2, 127) + if dtype != bool: + image[:] = (1, 2, 127) + else: + image[:] = (False, True, False) for i in range(rows): for j in range(cols): - image[i, j, 1] = (i + j) % 256 + if dtype != bool: + image[i, j, 1] = (i + j) % 256 + else: + image[i, j, 1] = (i + j) % 2 != 0 return image @@ -178,6 +184,7 @@ class filestorage_io_test(NewOpenCVTests): mats = {'normal_2d_mat_u8': self.get_normal_2d_mat(np.uint8), 'normal_2d_mat_u32': self.get_normal_2d_mat(np.uint32), + 'normal_2d_mat_bool': self.get_normal_2d_mat(bool), 'normal_nd_mat': self.get_normal_nd_mat(), 'empty_2d_mat': self.get_empty_2d_mat(), 'random_mat': self.get_random_mat()}