Skip to content

imgcodecs: gif: support IMREAD_UNCHANGE for 3ch data and IMREAD_GRAYSCALE #26858

@Kumataro

Description

@Kumataro

Describe the feature and motivation

In OpenCV 4.11, we have to update the channel handling for GIF Decoder.

IMREAD_UNCHANGED

It doesn't handle Transparent Color Flag bit in packed fields for readHeader().
When input GIF stream has 3ch RGB without alpha channels, 'm_type' should be CV_8UC3.
But now it is CV_8UC4 constantly. So imread(cv::IMREAD_UNCHANGED) cannot return CV_8UC3.

IMREAD_GRAYSCALE

GIF decoder expects that destination mat has 3 or 4 channels.
imread(cv::IMREAD_GRAYSCALE) request 1 channel image destination.
We have to fix it.

Additional context

diff --git a/modules/imgcodecs/test/test_gif.cpp b/modules/imgcodecs/test/test_gif.cpp
index b9c49c0bdb..ae0064f619 100644
--- a/modules/imgcodecs/test/test_gif.cpp
+++ b/modules/imgcodecs/test/test_gif.cpp
@@ -246,6 +246,7 @@ TEST(Imgcodecs_Gif, read_gif_special){
     cv::Mat png_img1;
     ASSERT_NO_THROW(png_img1 = cv::imread(png_filename1,IMREAD_UNCHANGED));
     ASSERT_FALSE(png_img1.empty());
+    cv::cvtColor(png_img1, png_img1, cv::COLOR_BGRA2BGR);
     EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), gif_img1, png_img1);
     cv::Mat gif_img2;
     ASSERT_NO_THROW(gif_img2 = cv::imread(gif_filename2,IMREAD_UNCHANGED));
@@ -253,6 +254,7 @@ TEST(Imgcodecs_Gif, read_gif_special){
     cv::Mat png_img2;
     ASSERT_NO_THROW(png_img2 = cv::imread(png_filename2,IMREAD_UNCHANGED));
     ASSERT_FALSE(png_img2.empty());
+    cv::cvtColor(png_img2, png_img2, cv::COLOR_BGRA2BGR);
     EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), gif_img2, png_img2);
 }

@@ -351,6 +353,21 @@ TEST(Imgcodecs_Gif, write_gif_multi) {
     EXPECT_EQ(0, remove(gif_filename.c_str()));
 }

+TEST(Imgcodecs_Gif, encode_IMREAD_GRAYSCALE) {
+    cv::Mat src;
+    cv::Mat decoded;
+    vector<uint8_t> buf;
+    vector<int> param;
+    bool ret = false;
+
+    src = cv::Mat(240,240,CV_8UC3,cv::Scalar(128,64,32));
+    EXPECT_NO_THROW(ret = imencode(".gif", src, buf, param));
+    EXPECT_TRUE(ret);
+    EXPECT_NO_THROW(decoded = imdecode(buf, cv::IMREAD_GRAYSCALE));
+    EXPECT_FALSE(decoded.empty());
+    EXPECT_EQ(decoded.channels(), 1);
+}
+
 }//opencv_test
 }//namespace

diff --git a/modules/imgcodecs/test/test_grfmt.cpp b/modules/imgcodecs/test/test_grfmt.cpp
index 947e560c81..f44e64ec7a 100644
--- a/modules/imgcodecs/test/test_grfmt.cpp
+++ b/modules/imgcodecs/test/test_grfmt.cpp
@@ -164,6 +164,8 @@ TEST_P(Imgcodecs_ExtSize, write_imageseq)
             continue;
         if (cn != 3 && ext == ".ppm")
             continue;
+        if (cn == 1 && ext == ".gif")
+            continue;
         string filename = cv::tempfile(format("%d%s", cn, ext.c_str()).c_str());

         Mat img_gt(size, CV_MAKETYPE(CV_8U, cn), Scalar::all(0));
@@ -179,8 +181,14 @@ TEST_P(Imgcodecs_ExtSize, write_imageseq)
         ASSERT_TRUE(imwrite(filename, img_gt, parameters));
         Mat img = imread(filename, IMREAD_UNCHANGED);
         ASSERT_FALSE(img.empty());
-        EXPECT_EQ(img.size(), img.size());
-        EXPECT_EQ(img.type(), img.type());
+        EXPECT_EQ(img_gt.size(), img.size());
+        EXPECT_EQ(img_gt.channels(), img.channels());
+        if (ext == ".pfm") {
+            EXPECT_EQ(img_gt.depth(), CV_8U);
+            EXPECT_EQ(img.depth(),    CV_32F);
+        } else {
+            EXPECT_EQ(img_gt.depth(), img.depth());
+        }
         EXPECT_EQ(cn, img.channels());


@@ -200,6 +208,14 @@ TEST_P(Imgcodecs_ExtSize, write_imageseq)
             EXPECT_LT(n, 1.);
             EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), img, img_gt);
         }
+        else if (ext == ".gif")
+        {
+            // GIF encoder will reduce the number of colors to 256.
+            // It is hard to compare image comparison by pixel unit.
+            double n = cvtest::norm(img, img_gt, NORM_L1);
+            double expected = 0.03 * img.size().area();
+            EXPECT_LT(n, expected);
+        }
         else
         {
             double n = cvtest::norm(img, img_gt, NORM_L2);
@@ -238,6 +254,9 @@ const string all_exts[] =
 #ifdef HAVE_IMGCODEC_PFM
     ".pfm",
 #endif
+#ifdef HAVE_IMGCODEC_GIF
+    ".gif",
+#endif
 };

 vector<Size> all_sizes()

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions