diff --git a/modules/core/include/opencv2/core/persistence.hpp b/modules/core/include/opencv2/core/persistence.hpp index c6ddf6f0ca..26ec13831f 100644 --- a/modules/core/include/opencv2/core/persistence.hpp +++ b/modules/core/include/opencv2/core/persistence.hpp @@ -273,6 +273,7 @@ public: FORMAT_XML = (1<<3), //!< flag, XML format FORMAT_YAML = (2<<3), //!< flag, YAML format FORMAT_JSON = (3<<3), //!< flag, JSON format + FORMAT_YAML_1_0 = (4<<3), //!< flag, Legacy YAML 1.0 format (strict headers, booleans as ints) BASE64 = 64, //!< flag, write rawdata in Base64 by default. (consider using WRITE_BASE64) WRITE_BASE64 = BASE64 | WRITE, //!< flag, enable both WRITE and BASE64 @@ -365,6 +366,8 @@ public: */ CV_WRAP void write(const String& name, int val); /// @overload + CV_WRAP void write(const String& name, bool val); + CV_WRAP void write(const String& name, int64_t val); /// @overload CV_WRAP void write(const String& name, double val); @@ -658,6 +661,7 @@ protected: /////////////////// XML & YAML I/O implementation ////////////////// CV_EXPORTS void write( FileStorage& fs, const String& name, int value ); +CV_EXPORTS void write( FileStorage& fs, const String& name, bool value ); CV_EXPORTS void write( FileStorage& fs, const String& name, int64_t value ); CV_EXPORTS void write( FileStorage& fs, const String& name, float value ); CV_EXPORTS void write( FileStorage& fs, const String& name, double value ); diff --git a/modules/core/src/persistence.cpp b/modules/core/src/persistence.cpp index 4f0cf2868a..a449783781 100644 --- a/modules/core/src/persistence.cpp +++ b/modules/core/src/persistence.cpp @@ -695,9 +695,13 @@ bool FileStorage::Impl::open(const char *filename_or_buf, int _flags, const char } emitter_do_not_use_direct_dereference = createXMLEmitter(this); - } else if (fmt == FileStorage::FORMAT_YAML) { - if (!append) - puts("%YAML:1.0\n---\n"); + } else if (fmt == FileStorage::FORMAT_YAML || fmt == FileStorage::FORMAT_YAML_1_0) { + if (!append) { + if (fmt == FileStorage::FORMAT_YAML_1_0) + puts("%YAML:1.0\n---\n"); // Legacy Flag -> Legacy Header + else + puts("%YAML 1.2\n---\n"); // Default -> Modern Header + } else puts("...\n---\n"); @@ -750,16 +754,15 @@ bool FileStorage::Impl::open(const char *filename_or_buf, int _flags, const char char *bufPtr = cv_skip_BOM(buf); size_t bufOffset = bufPtr - buf; + // NOTE: Yaml 1.2 allows to skip header. Data without type signature is read as YAML if (strncmp(bufPtr, yaml_signature, strlen(yaml_signature)) == 0) fmt = FileStorage::FORMAT_YAML; else if (strncmp(bufPtr, json_signature, strlen(json_signature)) == 0) fmt = FileStorage::FORMAT_JSON; else if (strncmp(bufPtr, xml_signature, strlen(xml_signature)) == 0) fmt = FileStorage::FORMAT_XML; - else if (strbufsize == bufOffset) - CV_Error(cv::Error::StsBadArg, "Input file is invalid"); else - CV_Error(cv::Error::StsBadArg, "Unsupported file storage format"); + fmt = FileStorage::FORMAT_YAML; rewind(); strbufpos = bufOffset; @@ -782,6 +785,7 @@ bool FileStorage::Impl::open(const char *filename_or_buf, int _flags, const char parser_do_not_use_direct_dereference = createXMLParser(this); break; case FileStorage::FORMAT_YAML: + case FileStorage::FORMAT_YAML_1_0: parser_do_not_use_direct_dereference = createYAMLParser(this); break; case FileStorage::FORMAT_JSON: @@ -2156,7 +2160,13 @@ void write( FileStorage& fs, const String& name, const String& value ) fs.p->write(name, value); } +void write( FileStorage& fs, const String& name, bool value ) +{ + fs.p->write(name, value); +} + void FileStorage::write(const String& name, int val) { p->write(name, val); } +void FileStorage::write(const String& name, bool val) { p->write(name, val); } void FileStorage::write(const String& name, int64_t val) { p->write(name, val); } void FileStorage::write(const String& name, double val) { p->write(name, val); } void FileStorage::write(const String& name, const String& val) { p->write(name, val); } @@ -2894,6 +2904,21 @@ void read(const FileNode& node, std::string& val, const std::string& default_val val = (std::string)node; } } +void FileStorage::Impl::write(const String &key, bool value) +{ + CV_Assert(write_mode); + // [SWAP LOGIC] + if (fmt == FileStorage::FORMAT_YAML_1_0) + { + // Legacy behavior: Write as integer 1 or 0 + getEmitter().write(key.c_str(), (int)value); + } + else + { + // Default/Modern behavior: Write as "true" or "false" + getEmitter().write(key.c_str(), value ? "true" : "false", false); + } +} FileStorage_API::~FileStorage_API() {} diff --git a/modules/core/src/persistence.hpp b/modules/core/src/persistence.hpp index 55ccd51254..6dca4adad8 100644 --- a/modules/core/src/persistence.hpp +++ b/modules/core/src/persistence.hpp @@ -137,6 +137,8 @@ public: virtual ~FileStorage_API(); virtual FileStorage* getFS() = 0; + virtual int getFormat() const = 0; + virtual void puts( const char* str ) = 0; virtual char* gets() = 0; virtual bool eof() = 0; diff --git a/modules/core/src/persistence_impl.hpp b/modules/core/src/persistence_impl.hpp index 11a83f2253..b1c922e082 100644 --- a/modules/core/src/persistence_impl.hpp +++ b/modules/core/src/persistence_impl.hpp @@ -69,6 +69,8 @@ public: void write( const String& key, int value ); + void write( const String& key, bool value ); + void write( const String& key, int64_t value ); void write( const String& key, double value ); @@ -97,7 +99,7 @@ public: FileNode operator[](const char* /*nodename*/) const; - int getFormat() const; + virtual int getFormat() const CV_OVERRIDE; char* bufferPtr() const; char* bufferStart() const; diff --git a/modules/core/src/persistence_yml.cpp b/modules/core/src/persistence_yml.cpp index d926fd0b2e..d78ea6b438 100644 --- a/modules/core/src/persistence_yml.cpp +++ b/modules/core/src/persistence_yml.cpp @@ -728,10 +728,30 @@ public: if( is_parent_flow || c != ':' ) { char* str_end = endptr; - // strip spaces in the end of string do c = *--str_end; while( str_end > ptr && c == ' ' ); str_end++; + if ((fs->getFormat() & FileStorage::FORMAT_MASK) != FileStorage::FORMAT_YAML_1_0) + { + size_t llen = str_end - ptr; + if (llen == 4 && memcmp(ptr, "true", 4) == 0) { + int64_t ival = 1; + node.setValue(FileNode::INT, &ival); + ptr = endptr; + return ptr; + } + else if (llen == 5 && memcmp(ptr, "false", 5) == 0) { + int64_t ival = 0; + node.setValue(FileNode::INT, &ival); + ptr = endptr; + return ptr; + } + else if (llen == 4 && memcmp(ptr, "null", 4) == 0) { + ptr = endptr; + return ptr; + } + } + node.setValue(FileNode::STRING, ptr, (int)(str_end - ptr)); ptr = endptr; return ptr; @@ -806,7 +826,10 @@ public: if( memcmp( ptr, "%YAML", 5 ) == 0 && memcmp( ptr, "%YAML:1.", 8 ) != 0 && memcmp( ptr, "%YAML 1.", 8 ) != 0) - CV_PARSE_ERROR_CPP( "Unsupported YAML version (it must be 1.x)" ); + { + if ((fs->getFormat() & FileStorage::FORMAT_MASK) == FileStorage::FORMAT_YAML_1_0) + CV_PARSE_ERROR_CPP( "Unsupported YAML version (it must be 1.x)" ); + } *ptr = '\0'; } else if( *ptr == '-' ) diff --git a/modules/core/test/test_io.cpp b/modules/core/test/test_io.cpp index b0aeda4025..1edc72f187 100644 --- a/modules/core/test/test_io.cpp +++ b/modules/core/test/test_io.cpp @@ -499,7 +499,7 @@ TEST(Core_InputOutput, FileStorageKey) EXPECT_NO_THROW(f << "key1" << "value1"); EXPECT_NO_THROW(f << "_key2" << "value2"); EXPECT_NO_THROW(f << "key_3" << "value3"); - const std::string expected = "%YAML:1.0\n---\nkey1: value1\n_key2: value2\nkey_3: value3\n"; + const std::string expected = "%YAML 1.2\n---\nkey1: value1\n_key2: value2\nkey_3: value3\n"; ASSERT_STREQ(f.releaseAndGetString().c_str(), expected.c_str()); } @@ -1199,7 +1199,7 @@ TEST(Core_InputOutput, FileStorage_DMatch) EXPECT_NO_THROW(fs << "d" << d); cv::String fs_result = fs.releaseAndGetString(); - EXPECT_STREQ(fs_result.c_str(), "%YAML:1.0\n---\nd: [ 1, 2, 3, -1.5 ]\n"); + EXPECT_STREQ(fs_result.c_str(), "%YAML 1.2\n---\nd: [ 1, 2, 3, -1.5 ]\n"); cv::FileStorage fs_read(fs_result, cv::FileStorage::READ | cv::FileStorage::MEMORY); @@ -1227,7 +1227,7 @@ TEST(Core_InputOutput, FileStorage_DMatch_vector) EXPECT_NO_THROW(fs << "dv" << dv); cv::String fs_result = fs.releaseAndGetString(); EXPECT_STREQ(fs_result.c_str(), -"%YAML:1.0\n" +"%YAML 1.2\n" "---\n" "dv:\n" " - [ 1, 2, 3, -1.5 ]\n" @@ -1274,7 +1274,7 @@ TEST(Core_InputOutput, FileStorage_DMatch_vector_vector) cv::String fs_result = fs.releaseAndGetString(); #ifndef OPENCV_TRAITS_ENABLE_DEPRECATED EXPECT_STREQ(fs_result.c_str(), -"%YAML:1.0\n" +"%YAML 1.2\n" "---\n" "dvv:\n" " -\n" @@ -2278,4 +2278,50 @@ INSTANTIATE_TEST_CASE_P(Core_InputOutput, FileStorage_exact_type, Values(".yml", ".xml", ".json") ); +TEST(Core_InputOutput, YAML_Compatibility) +{ + string filename = cv::tempfile(".yaml"); + + // 1. Write using DEFAULT (should be 1.2 compatible now) + { + FileStorage fs(filename, FileStorage::WRITE | FileStorage::FORMAT_YAML); + ASSERT_TRUE(fs.isOpened()); + fs << "bool_true" << true; + fs << "bool_false" << false; + fs.release(); + } + + // 2. Verify Default is Modern (Literals + No Legacy Header) + { + std::ifstream file(filename.c_str()); + std::stringstream buffer; + buffer << file.rdbuf(); + std::string content = buffer.str(); + + EXPECT_NE(content.find("bool_true: true"), std::string::npos); // Found 'true' + EXPECT_EQ(content.find("%YAML:1.0"), std::string::npos); // No 1.0 Header + } + + // 3. Write using LEGACY flag + { + FileStorage fs(filename, FileStorage::WRITE | FileStorage::FORMAT_YAML_1_0); + ASSERT_TRUE(fs.isOpened()); + fs << "bool_true" << true; + fs.release(); + } + + // 4. Verify Legacy (Integers + Strict Header) + { + std::ifstream file(filename.c_str()); + std::stringstream buffer; + buffer << file.rdbuf(); + std::string content = buffer.str(); + + EXPECT_NE(content.find("bool_true: 1"), std::string::npos); // Found '1' + EXPECT_NE(content.find("%YAML:1.0"), std::string::npos); // Found 1.0 Header + } + + remove(filename.c_str()); +} + }} // namespace diff --git a/modules/features/misc/java/test/BruteForceDescriptorMatcherTest.java b/modules/features/misc/java/test/BruteForceDescriptorMatcherTest.java index 8031490dd9..10021358af 100644 --- a/modules/features/misc/java/test/BruteForceDescriptorMatcherTest.java +++ b/modules/features/misc/java/test/BruteForceDescriptorMatcherTest.java @@ -297,7 +297,7 @@ public class BruteForceDescriptorMatcherTest extends OpenCVTestCase { matcher.write(filename); - String truth = "%YAML:1.0\n---\n"; + String truth = "%YAML 1.2\n---\n"; assertEquals(truth, readFile(filename)); } diff --git a/modules/features/misc/java/test/BruteForceHammingDescriptorMatcherTest.java b/modules/features/misc/java/test/BruteForceHammingDescriptorMatcherTest.java index 83f03b34e9..63d2e88aee 100644 --- a/modules/features/misc/java/test/BruteForceHammingDescriptorMatcherTest.java +++ b/modules/features/misc/java/test/BruteForceHammingDescriptorMatcherTest.java @@ -255,7 +255,7 @@ public class BruteForceHammingDescriptorMatcherTest extends OpenCVTestCase { matcher.write(filename); - String truth = "%YAML:1.0\n---\n"; + String truth = "%YAML 1.2\n---\n"; assertEquals(truth, readFile(filename)); } diff --git a/modules/features/misc/java/test/BruteForceHammingLUTDescriptorMatcherTest.java b/modules/features/misc/java/test/BruteForceHammingLUTDescriptorMatcherTest.java index 6940103a99..0ff616be19 100644 --- a/modules/features/misc/java/test/BruteForceHammingLUTDescriptorMatcherTest.java +++ b/modules/features/misc/java/test/BruteForceHammingLUTDescriptorMatcherTest.java @@ -250,7 +250,7 @@ public class BruteForceHammingLUTDescriptorMatcherTest extends OpenCVTestCase { matcher.write(filename); - String truth = "%YAML:1.0\n---\n"; + String truth = "%YAML 1.2\n---\n"; assertEquals(truth, readFile(filename)); } diff --git a/modules/features/misc/java/test/BruteForceL1DescriptorMatcherTest.java b/modules/features/misc/java/test/BruteForceL1DescriptorMatcherTest.java index 49c5f728e4..2363df9071 100644 --- a/modules/features/misc/java/test/BruteForceL1DescriptorMatcherTest.java +++ b/modules/features/misc/java/test/BruteForceL1DescriptorMatcherTest.java @@ -261,7 +261,7 @@ public class BruteForceL1DescriptorMatcherTest extends OpenCVTestCase { matcher.write(filename); - String truth = "%YAML:1.0\n---\n"; + String truth = "%YAML 1.2\n---\n"; assertEquals(truth, readFile(filename)); } diff --git a/modules/features/misc/java/test/BruteForceSL2DescriptorMatcherTest.java b/modules/features/misc/java/test/BruteForceSL2DescriptorMatcherTest.java index 93b7b97868..bba4fd2fb4 100644 --- a/modules/features/misc/java/test/BruteForceSL2DescriptorMatcherTest.java +++ b/modules/features/misc/java/test/BruteForceSL2DescriptorMatcherTest.java @@ -273,7 +273,7 @@ public class BruteForceSL2DescriptorMatcherTest extends OpenCVTestCase { matcher.write(filename); - String truth = "%YAML:1.0\n---\n"; + String truth = "%YAML 1.2\n---\n"; assertEquals(truth, readFile(filename)); } diff --git a/modules/features/misc/java/test/FASTFeatureDetectorTest.java b/modules/features/misc/java/test/FASTFeatureDetectorTest.java index 8ef67dd46f..7d8cf1685f 100644 --- a/modules/features/misc/java/test/FASTFeatureDetectorTest.java +++ b/modules/features/misc/java/test/FASTFeatureDetectorTest.java @@ -133,7 +133,7 @@ public class FASTFeatureDetectorTest extends OpenCVTestCase { detector.write(filename); - String truth = "%YAML:1.0\n---\nname: \"Feature2D.FastFeatureDetector\"\nthreshold: 10\nnonmaxSuppression: 1\ntype: 2\n"; + String truth = "%YAML 1.2\n---\nname: \"Feature2D.FastFeatureDetector\"\nthreshold: 10\nnonmaxSuppression: true\ntype: 2\n"; String data = readFile(filename); assertEquals(truth, data); diff --git a/modules/features/misc/java/test/FlannBasedDescriptorMatcherTest.java b/modules/features/misc/java/test/FlannBasedDescriptorMatcherTest.java index c45b460ad4..d4fbb4be02 100644 --- a/modules/features/misc/java/test/FlannBasedDescriptorMatcherTest.java +++ b/modules/features/misc/java/test/FlannBasedDescriptorMatcherTest.java @@ -51,7 +51,7 @@ public class FlannBasedDescriptorMatcherTest extends OpenCVTestCase { + " 8\n" // FLANN_INDEX_TYPE_BOOL + " 1\n" + "\n"; - static final String ymlParamsDefault = "%YAML:1.0\n---\n" + static final String ymlParamsDefault = "%YAML 1.2\n---\n" + "format: 3\n" + "indexParams:\n" + " -\n" @@ -79,7 +79,7 @@ public class FlannBasedDescriptorMatcherTest extends OpenCVTestCase { + " name: sorted\n" + " type: 8\n" // FLANN_INDEX_TYPE_BOOL + " value: 1\n"; - static final String ymlParamsModified = "%YAML:1.0\n---\n" + static final String ymlParamsModified = "%YAML 1.2\n---\n" + "format: 3\n" + "indexParams:\n" + " -\n" diff --git a/modules/features/misc/java/test/GFTTFeatureDetectorTest.java b/modules/features/misc/java/test/GFTTFeatureDetectorTest.java index 248c62e1c6..2dddeea716 100644 --- a/modules/features/misc/java/test/GFTTFeatureDetectorTest.java +++ b/modules/features/misc/java/test/GFTTFeatureDetectorTest.java @@ -58,7 +58,7 @@ public class GFTTFeatureDetectorTest extends OpenCVTestCase { detector.write(filename); - String truth = "%YAML:1.0\n---\nname: \"Feature2D.GFTTDetector\"\nnfeatures: 1000\nqualityLevel: 0.01\nminDistance: 1.\nblockSize: 3\ngradSize: 3\nuseHarrisDetector: 0\nk: 0.040000000000000001\n"; + String truth = "%YAML 1.2\n---\nname: \"Feature2D.GFTTDetector\"\nnfeatures: 1000\nqualityLevel: 0.01\nminDistance: 1.\nblockSize: 3\ngradSize: 3\nuseHarrisDetector: false\nk: 0.040000000000000001\n"; String actual = readFile(filename); actual = actual.replaceAll("e([+-])0(\\d\\d)", "e$1$2"); // NOTE: workaround for different platforms double representation assertEquals(truth, actual); diff --git a/modules/features/misc/java/test/MSERFeatureDetectorTest.java b/modules/features/misc/java/test/MSERFeatureDetectorTest.java index 4b3baa1b42..aa23618f08 100644 --- a/modules/features/misc/java/test/MSERFeatureDetectorTest.java +++ b/modules/features/misc/java/test/MSERFeatureDetectorTest.java @@ -61,7 +61,7 @@ public class MSERFeatureDetectorTest extends OpenCVTestCase { detector.write(filename); - String truth = "%YAML:1.0\n---\nname: \"Feature2D.MSER\"\ndelta: 5\nminArea: 60\nmaxArea: 14400\nmaxVariation: 0.25\nminDiversity: 0.20000000000000001\nmaxEvolution: 200\nareaThreshold: 1.01\nminMargin: 0.0030000000000000001\nedgeBlurSize: 5\npass2Only: 0\n"; + String truth = "%YAML 1.2\n---\nname: \"Feature2D.MSER\"\ndelta: 5\nminArea: 60\nmaxArea: 14400\nmaxVariation: 0.25\nminDiversity: 0.20000000000000001\nmaxEvolution: 200\nareaThreshold: 1.01\nminMargin: 0.0030000000000000001\nedgeBlurSize: 5\npass2Only: false\n"; String actual = readFile(filename); actual = actual.replaceAll("e([+-])0(\\d\\d)", "e$1$2"); // NOTE: workaround for different platforms double representation assertEquals(truth, actual); diff --git a/modules/features/misc/java/test/ORBDescriptorExtractorTest.java b/modules/features/misc/java/test/ORBDescriptorExtractorTest.java index d4b58149f9..1d452975d7 100644 --- a/modules/features/misc/java/test/ORBDescriptorExtractorTest.java +++ b/modules/features/misc/java/test/ORBDescriptorExtractorTest.java @@ -111,7 +111,7 @@ public class ORBDescriptorExtractorTest extends OpenCVTestCase { extractor.write(filename); - String truth = "%YAML:1.0\n---\nname: \"Feature2D.ORB\"\nnfeatures: 500\nscaleFactor: 1.2000000476837158\nnlevels: 8\nedgeThreshold: 31\nfirstLevel: 0\nwta_k: 2\nscoreType: 0\npatchSize: 31\nfastThreshold: 20\n"; + String truth = "%YAML 1.2\n---\nname: \"Feature2D.ORB\"\nnfeatures: 500\nscaleFactor: 1.2000000476837158\nnlevels: 8\nedgeThreshold: 31\nfirstLevel: 0\nwta_k: 2\nscoreType: 0\npatchSize: 31\nfastThreshold: 20\n"; // String truth = "%YAML:1.0\n---\n"; String actual = readFile(filename); actual = actual.replaceAll("e\\+000", "e+00"); // NOTE: workaround for different platforms double representation diff --git a/modules/features/misc/java/test/SIFTDescriptorExtractorTest.java b/modules/features/misc/java/test/SIFTDescriptorExtractorTest.java index 0dbb932181..da86fdad9c 100644 --- a/modules/features/misc/java/test/SIFTDescriptorExtractorTest.java +++ b/modules/features/misc/java/test/SIFTDescriptorExtractorTest.java @@ -100,7 +100,7 @@ public class SIFTDescriptorExtractorTest extends OpenCVTestCase { extractor.write(filename); - String truth = "%YAML:1.0\n---\nname: \"Feature2D.SIFT\"\nnfeatures: 0\nnOctaveLayers: 3\ncontrastThreshold: 0.040000000000000001\nedgeThreshold: 10.\nsigma: 1.6000000000000001\ndescriptorType: 5\n"; + String truth = "%YAML 1.2\n---\nname: \"Feature2D.SIFT\"\nnfeatures: 0\nnOctaveLayers: 3\ncontrastThreshold: 0.040000000000000001\nedgeThreshold: 10.\nsigma: 1.6000000000000001\ndescriptorType: 5\n"; String actual = readFile(filename); actual = actual.replaceAll("e([+-])0(\\d\\d)", "e$1$2"); // NOTE: workaround for different platforms double representation assertEquals(truth, actual); diff --git a/modules/features/test/test_matchers_algorithmic.cpp b/modules/features/test/test_matchers_algorithmic.cpp index 317b15beee..e573425bed 100644 --- a/modules/features/test/test_matchers_algorithmic.cpp +++ b/modules/features/test/test_matchers_algorithmic.cpp @@ -558,7 +558,7 @@ TEST( Features2d_DMatch, read_write ) #ifdef HAVE_OPENCV_FLANN TEST( Features2d_FlannBasedMatcher, read_write ) { - static const char* ymlfile = "%YAML:1.0\n---\n" + static const char* ymlfile = "%YAML 1.2\n---\n" "format: 3\n" "indexParams:\n" " -\n" diff --git a/modules/python/test/requirements.txt b/modules/python/test/requirements.txt new file mode 100644 index 0000000000..5209eeef20 --- /dev/null +++ b/modules/python/test/requirements.txt @@ -0,0 +1,2 @@ +pyyml +numpy \ No newline at end of file diff --git a/modules/python/test/test_persistence.py b/modules/python/test/test_persistence.py index cfa4225ebe..2fb846678f 100644 --- a/modules/python/test/test_persistence.py +++ b/modules/python/test/test_persistence.py @@ -4,7 +4,7 @@ import tempfile import os import cv2 as cv import numpy as np -from tests_common import NewOpenCVTests +from tests_common import NewOpenCVTests, unittest class persistence_test(NewOpenCVTests): @@ -42,3 +42,46 @@ class persistence_test(NewOpenCVTests): fs.release() os.remove(fname) + + def test_yml_python_interop(self): + try: + import yaml + except: + raise unittest.SkipTest('Pyyml is not available for interop test') + + ref_data = { + 'int_value': 42, + "bool_value": True, + "float_value": 3.1415926, + "int64_value": 2147483647 + 1024, # C++ INT_MAX + 1024 + "string_value": "opencv" + } + + fd, test_file_name = tempfile.mkstemp(prefix="opencv_python_persistence_", suffix=".yml") + os.close(fd) + + with open(test_file_name, 'w') as ff: + yaml.dump(ref_data, ff) + + # Notice: no cv.FileStorage_FORMAT_YAML flag needed now thanks to the C++ fix! + fs = cv.FileStorage(test_file_name, cv.FILE_STORAGE_READ) + self.assertTrue(fs.isOpened()) + + node = fs.getNode('int_value') + self.assertTrue(node.isInt()) + self.assertEqual(42, int(node.real())) + + node = fs.getNode('int64_value') + self.assertTrue(node.isInt()) + self.assertEqual(2147483647 + 1024, int(node.real())) + + node = fs.getNode('float_value') + self.assertTrue(node.isReal()) + self.assertEqual(3.1415926, node.real()) + + node = fs.getNode('string_value') + self.assertTrue(node.isString()) + self.assertEqual("opencv", node.string()) + + fs.release() + os.remove(test_file_name)