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)