core(persistence): fix types format handling, fix 16F support
authorAlexander Alekhin <alexander.a.alekhin@gmail.com>
Tue, 29 Jun 2021 09:00:10 +0000 (09:00 +0000)
committerAlexander Alekhin <alexander.a.alekhin@gmail.com>
Tue, 29 Jun 2021 11:26:57 +0000 (11:26 +0000)
modules/core/src/persistence.cpp
modules/core/test/test_io.cpp

index 4bf52a3..3232836 100644 (file)
@@ -143,17 +143,17 @@ static const char symbols[9] = "ucwsifdh";
 static char typeSymbol(int depth)
 {
     CV_StaticAssert(CV_64F == 6, "");
-    CV_Assert(depth >=0 && depth <= CV_64F);
+    CV_CheckDepth(depth, depth >=0 && depth <= CV_16F, "");
     return symbols[depth];
 }
 
 static int symbolToType(char c)
 {
+    if (c == 'r')
+        return CV_SEQ_ELTYPE_PTR;
     const char* pos = strchr( symbols, c );
     if( !pos )
         CV_Error( CV_StsBadArg, "Invalid data type specification" );
-    if (c == 'r')
-        return CV_SEQ_ELTYPE_PTR;
     return static_cast<int>(pos - symbols);
 }
 
@@ -245,8 +245,12 @@ int calcStructSize( const char* dt, int initial_size )
 {
     int size = calcElemSize( dt, initial_size );
     size_t elem_max_size = 0;
-    for ( const char * type = dt; *type != '\0'; type++ ) {
-        switch ( *type )
+    for ( const char * type = dt; *type != '\0'; type++ )
+    {
+        char v = *type;
+        if (v >= '0' && v <= '9')
+            continue;  // skip vector size
+        switch (v)
         {
         case 'u': { elem_max_size = std::max( elem_max_size, sizeof(uchar ) ); break; }
         case 'c': { elem_max_size = std::max( elem_max_size, sizeof(schar ) ); break; }
@@ -255,7 +259,9 @@ int calcStructSize( 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; }
-        default: break;
+        case 'h': { elem_max_size = std::max(elem_max_size, sizeof(float16_t)); break; }
+        default:
+            CV_Error_(Error::StsNotImplemented, ("Unknown type identifier: '%c' in '%s'", (char)(*type), dt));
         }
     }
     size = cvAlign( size, static_cast<int>(elem_max_size) );
@@ -1054,6 +1060,7 @@ public:
         CV_Assert(write_mode);
 
         size_t elemSize = fs::calcStructSize(dt.c_str(), 0);
+        CV_Assert(elemSize);
         CV_Assert( len % elemSize == 0 );
         len /= elemSize;
 
index d30c485..82bd053 100644 (file)
@@ -1837,4 +1837,69 @@ TEST(Core_InputOutput, FileStorage_copy_constructor_17412_heap)
     EXPECT_EQ(0, remove(fname.c_str()));
 }
 
+
+static void test_20279(FileStorage& fs)
+{
+    Mat m32fc1(5, 10, CV_32FC1, Scalar::all(0));
+    for (size_t i = 0; i < m32fc1.total(); i++)
+    {
+        float v = (float)i;
+        m32fc1.at<float>((int)i) = v * 0.5f;
+    }
+    Mat m16fc1;
+    // produces CV_16S output: convertFp16(m32fc1, m16fc1);
+    m32fc1.convertTo(m16fc1, CV_16FC1);
+    EXPECT_EQ(CV_16FC1, m16fc1.type()) << typeToString(m16fc1.type());
+    //std::cout << m16fc1 << std::endl;
+
+    Mat m32fc3(4, 3, CV_32FC3, Scalar::all(0));
+    for (size_t i = 0; i < m32fc3.total(); i++)
+    {
+        float v = (float)i;
+        m32fc3.at<Vec3f>((int)i) = Vec3f(v, v * 0.2f, -v);
+    }
+    Mat m16fc3;
+    m32fc3.convertTo(m16fc3, CV_16FC3);
+    EXPECT_EQ(CV_16FC3, m16fc3.type()) << typeToString(m16fc3.type());
+    //std::cout << m16fc3 << std::endl;
+
+    fs << "m16fc1" << m16fc1;
+    fs << "m16fc3" << m16fc3;
+
+    string content = fs.releaseAndGetString();
+    if (cvtest::debugLevel > 0) std::cout << content << std::endl;
+
+    FileStorage fs_read(content, FileStorage::READ + FileStorage::MEMORY);
+    Mat m16fc1_result;
+    Mat m16fc3_result;
+    fs_read["m16fc1"] >> m16fc1_result;
+    ASSERT_FALSE(m16fc1_result.empty());
+    EXPECT_EQ(CV_16FC1, m16fc1_result.type()) << typeToString(m16fc1_result.type());
+    EXPECT_LE(cvtest::norm(m16fc1_result, m16fc1, NORM_INF), 1e-2);
+
+    fs_read["m16fc3"] >> m16fc3_result;
+    ASSERT_FALSE(m16fc3_result.empty());
+    EXPECT_EQ(CV_16FC3, m16fc3_result.type()) << typeToString(m16fc3_result.type());
+    EXPECT_LE(cvtest::norm(m16fc3_result, m16fc3, NORM_INF), 1e-2);
+}
+
+TEST(Core_InputOutput, FileStorage_16F_xml)
+{
+    FileStorage fs("test.xml", cv::FileStorage::WRITE | cv::FileStorage::MEMORY);
+    test_20279(fs);
+}
+
+TEST(Core_InputOutput, FileStorage_16F_yml)
+{
+    FileStorage fs("test.yml", cv::FileStorage::WRITE | cv::FileStorage::MEMORY);
+    test_20279(fs);
+}
+
+TEST(Core_InputOutput, FileStorage_16F_json)
+{
+    FileStorage fs("test.json", cv::FileStorage::WRITE | cv::FileStorage::MEMORY);
+    test_20279(fs);
+}
+
+
 }} // namespace