chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,648 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
#include "test_precomp.hpp"
|
||||
#include "test_common.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
#if defined(HAVE_PNG) || defined(HAVE_SPNG)
|
||||
|
||||
// See https://github.com/opencv/opencv/pull/28615
|
||||
// Precision differences in 16-bit grayscale conversion between old and modern libpng versions
|
||||
#define OPENCV_IMGCODECS_PNG_EPS_DEFAULT (4)
|
||||
#ifndef OPENCV_IMGCODECS_PNG_EPS_16BIT_GRAY
|
||||
#define OPENCV_IMGCODECS_PNG_EPS_16BIT_GRAY (OPENCV_IMGCODECS_PNG_EPS_DEFAULT)
|
||||
#endif
|
||||
|
||||
TEST(Imgcodecs_Png, write_big)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + "readwrite/read.png";
|
||||
Mat img;
|
||||
ASSERT_NO_THROW(img = imread(filename));
|
||||
ASSERT_FALSE(img.empty());
|
||||
EXPECT_EQ(13043, img.cols);
|
||||
EXPECT_EQ(13917, img.rows);
|
||||
|
||||
vector<uchar> buff;
|
||||
bool status = false;
|
||||
ASSERT_NO_THROW(status = imencode(".png", img, buff, { IMWRITE_PNG_ZLIBBUFFER_SIZE, 1024*1024 }));
|
||||
ASSERT_TRUE(status);
|
||||
#ifdef HAVE_PNG
|
||||
EXPECT_EQ((size_t)816219, buff.size());
|
||||
#else
|
||||
EXPECT_EQ((size_t)817407, buff.size());
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Png, encode)
|
||||
{
|
||||
vector<uchar> buff;
|
||||
Mat img_gt = Mat::zeros(1000, 1000, CV_8U);
|
||||
vector<int> param;
|
||||
param.push_back(IMWRITE_PNG_COMPRESSION);
|
||||
param.push_back(3); //default(3) 0-9.
|
||||
bool status = false;
|
||||
EXPECT_NO_THROW(status = imencode(".png", img_gt, buff, param));
|
||||
ASSERT_TRUE(status);
|
||||
Mat img;
|
||||
EXPECT_NO_THROW(img = imdecode(buff, IMREAD_ANYDEPTH)); // hang
|
||||
EXPECT_FALSE(img.empty());
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), img, img_gt);
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Png, regression_ImreadVSCvtColor)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string imgName = root + "../cv/shared/lena.png";
|
||||
Mat original_image = imread(imgName);
|
||||
Mat gray_by_codec = imread(imgName, IMREAD_GRAYSCALE);
|
||||
Mat gray_by_cvt;
|
||||
cvtColor(original_image, gray_by_cvt, COLOR_BGR2GRAY);
|
||||
|
||||
Mat diff;
|
||||
absdiff(gray_by_codec, gray_by_cvt, diff);
|
||||
EXPECT_LT(cvtest::mean(diff)[0], 1.);
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(10, 0), gray_by_codec, gray_by_cvt);
|
||||
}
|
||||
|
||||
// Test OpenCV issue 3075 is solved
|
||||
TEST(Imgcodecs_Png, read_color_palette_with_alpha)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
Mat img;
|
||||
|
||||
// First Test : Read PNG with alpha, imread flag -1
|
||||
img = imread(root + "readwrite/color_palette_alpha.png", IMREAD_UNCHANGED);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_TRUE(img.channels() == 4);
|
||||
|
||||
// pixel is red in BGRA
|
||||
EXPECT_EQ(img.at<Vec4b>(0, 0), Vec4b(0, 0, 255, 255));
|
||||
EXPECT_EQ(img.at<Vec4b>(0, 1), Vec4b(0, 0, 255, 255));
|
||||
|
||||
// Second Test : Read PNG without alpha, imread flag -1
|
||||
img = imread(root + "readwrite/color_palette_no_alpha.png", IMREAD_UNCHANGED);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_TRUE(img.channels() == 3);
|
||||
|
||||
// pixel is red in BGR
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 0), Vec3b(0, 0, 255));
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 1), Vec3b(0, 0, 255));
|
||||
|
||||
// Third Test : Read PNG with alpha, imread flag 1
|
||||
img = imread(root + "readwrite/color_palette_alpha.png", IMREAD_COLOR);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_TRUE(img.channels() == 3);
|
||||
|
||||
// pixel is red in BGR
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 0), Vec3b(0, 0, 255));
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 1), Vec3b(0, 0, 255));
|
||||
|
||||
img = imread(root + "readwrite/color_palette_alpha.png", IMREAD_COLOR_RGB);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_TRUE(img.channels() == 3);
|
||||
|
||||
// pixel is red in RGB
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 0), Vec3b(255, 0, 0));
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 1), Vec3b(255, 0, 0));
|
||||
|
||||
// Fourth Test : Read PNG without alpha, imread flag 1
|
||||
img = imread(root + "readwrite/color_palette_no_alpha.png", IMREAD_COLOR);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_TRUE(img.channels() == 3);
|
||||
|
||||
// pixel is red in BGR
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 0), Vec3b(0, 0, 255));
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 1), Vec3b(0, 0, 255));
|
||||
|
||||
img = imread(root + "readwrite/color_palette_no_alpha.png", IMREAD_COLOR_RGB);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_TRUE(img.channels() == 3);
|
||||
|
||||
// pixel is red in RGB
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 0), Vec3b(255, 0, 0));
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 1), Vec3b(255, 0, 0));
|
||||
}
|
||||
|
||||
// IHDR shall be first.
|
||||
// See https://github.com/opencv/opencv/issues/27295
|
||||
TEST(Imgcodecs_Png, decode_regression27295)
|
||||
{
|
||||
vector<uchar> buff;
|
||||
Mat src = Mat::zeros(240, 180, CV_8UC3);
|
||||
vector<int> param;
|
||||
EXPECT_NO_THROW(imencode(".png", src, buff, param));
|
||||
|
||||
Mat img;
|
||||
|
||||
// If IHDR chunk found as the first chunk, output shall not be empty.
|
||||
// 8 means PNG signature length.
|
||||
// 4 means length field(uint32_t).
|
||||
EXPECT_EQ(buff[8+4+0], 'I');
|
||||
EXPECT_EQ(buff[8+4+1], 'H');
|
||||
EXPECT_EQ(buff[8+4+2], 'D');
|
||||
EXPECT_EQ(buff[8+4+3], 'R');
|
||||
EXPECT_NO_THROW(img = imdecode(buff, IMREAD_COLOR));
|
||||
EXPECT_FALSE(img.empty());
|
||||
|
||||
// If Non-IHDR chunk found as the first chunk, output shall be empty.
|
||||
buff[8+4+0] = 'i'; // Not 'I'
|
||||
buff[8+4+1] = 'H';
|
||||
buff[8+4+2] = 'D';
|
||||
buff[8+4+3] = 'R';
|
||||
EXPECT_NO_THROW(img = imdecode(buff, IMREAD_COLOR));
|
||||
EXPECT_TRUE(img.empty());
|
||||
|
||||
// If CgBI chunk (Apple private) found as the first chunk, output shall be empty with special message.
|
||||
buff[8+4+0] = 'C';
|
||||
buff[8+4+1] = 'g';
|
||||
buff[8+4+2] = 'B';
|
||||
buff[8+4+3] = 'I';
|
||||
EXPECT_NO_THROW(img = imdecode(buff, IMREAD_COLOR));
|
||||
EXPECT_TRUE(img.empty());
|
||||
}
|
||||
|
||||
// The program must not crash even when decoding a corrupted APNG image.
|
||||
// See https://github.com/opencv/opencv/issues/27744
|
||||
#if defined(HAVE_PNG) // APNG is supported only with using libpng
|
||||
TEST(Imgcodecs_Png, decode_regression27744)
|
||||
{
|
||||
// Create APNG stream
|
||||
Animation anim;
|
||||
for(size_t i = 0 ; i < 3 ; i++) {
|
||||
Mat frame(120, 120, CV_8UC3, Scalar(0,0,0));
|
||||
putText(frame, cv::format("%d", static_cast<int>(i)), Point(5, 28), FONT_HERSHEY_SIMPLEX, .5, Scalar(100, 255, 0, 255), 2);
|
||||
anim.frames.push_back(frame);
|
||||
anim.durations.push_back(30);
|
||||
}
|
||||
bool ret = false;
|
||||
vector<uchar> buff;
|
||||
EXPECT_NO_THROW(ret = imencodeanimation(".png", anim, buff));
|
||||
ASSERT_TRUE(ret) << "imencodeanimation() returns false";
|
||||
|
||||
// Find IDAT chunk
|
||||
const vector<uchar> IDAT = {'I', 'D', 'A', 'T' };
|
||||
std::vector<uchar>::iterator it = std::search(buff.begin(), buff.end(), IDAT.begin(), IDAT.end());
|
||||
ASSERT_FALSE(it == buff.end()) << "IDAT chunk not found";
|
||||
|
||||
// Determine the range to test
|
||||
// APNG stream contains as { len0, len1, len2, len3, 'I', 'D', 'A' 'T', ... }
|
||||
size_t idx = std::distance(buff.begin(), it); // 'I' position
|
||||
size_t len = (buff[idx-4] << 24) + (buff[idx-3] << 16) +
|
||||
(buff[idx-2] << 8) + (buff[idx-1]); // IDAT chunk length
|
||||
idx = idx + 4; // Move to IDAT body
|
||||
|
||||
// Test
|
||||
for(size_t i = 0; i < len; i++, idx++) {
|
||||
vector<uint8_t> work = buff;
|
||||
work[idx] = static_cast<uint8_t>((static_cast<uint32_t>(work[idx]) + 1) & 0xff);
|
||||
|
||||
Mat dst;
|
||||
EXPECT_NO_THROW(dst = imdecode(work, cv::IMREAD_COLOR));
|
||||
if(dst.empty()) {
|
||||
// libpng detects some error, but the program is not crashed. Test is passed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef testing::TestWithParam<string> Imgcodecs_Png_PngSuite;
|
||||
|
||||
// Parameterized test for decoding PNG files from the PNGSuite test set
|
||||
TEST_P(Imgcodecs_Png_PngSuite, decode)
|
||||
{
|
||||
// Construct full paths for the PNG image and corresponding ground truth XML file
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + "pngsuite/" + GetParam() + ".png";
|
||||
const string xml_filename = root + "pngsuite/" + GetParam() + ".xml";
|
||||
|
||||
// Load the XML file containing the ground truth data
|
||||
FileStorage fs(xml_filename, FileStorage::READ);
|
||||
ASSERT_TRUE(fs.isOpened()); // Ensure the file was opened successfully
|
||||
|
||||
// Load the image using IMREAD_UNCHANGED to preserve original format
|
||||
Mat src = imread(filename, IMREAD_UNCHANGED);
|
||||
ASSERT_FALSE(src.empty()); // Ensure the image was loaded successfully
|
||||
|
||||
// Load the ground truth matrix from XML
|
||||
Mat gt;
|
||||
fs.getFirstTopLevelNode() >> gt;
|
||||
|
||||
// Compare the image loaded with IMREAD_UNCHANGED to the ground truth
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), src, gt);
|
||||
|
||||
// Declare matrices for ground truth in different imread flag combinations
|
||||
Mat gt_0, gt_1, gt_2, gt_3, gt_256, gt_258;
|
||||
|
||||
// Handle grayscale 8-bit and 16-bit images
|
||||
if (gt.channels() == 1)
|
||||
{
|
||||
gt.copyTo(gt_2); // For IMREAD_ANYDEPTH
|
||||
if (gt.depth() == CV_16U)
|
||||
gt_2.convertTo(gt_0, CV_8U, 1. / 256);
|
||||
else
|
||||
gt_0 = gt_2; // For IMREAD_GRAYSCALE
|
||||
|
||||
cvtColor(gt_2, gt_3, COLOR_GRAY2BGR); // For IMREAD_COLOR | IMREAD_ANYDEPTH
|
||||
|
||||
if (gt.depth() == CV_16U)
|
||||
gt_3.convertTo(gt_1, CV_8U, 1. / 256);
|
||||
else
|
||||
gt_1 = gt_3; // For IMREAD_COLOR
|
||||
|
||||
gt_256 = gt_1; // For IMREAD_COLOR_RGB
|
||||
gt_258 = gt_3; // For IMREAD_COLOR_RGB | IMREAD_ANYDEPTH
|
||||
}
|
||||
|
||||
// Handle color images (3 or 4 channels) with 8-bit and 16-bit depth
|
||||
if (gt.channels() > 1)
|
||||
{
|
||||
// Convert to grayscale
|
||||
cvtColor(gt, gt_2, COLOR_BGRA2GRAY);
|
||||
if (gt.depth() == CV_16U)
|
||||
gt_2.convertTo(gt_0, CV_8U, 1. / 256);
|
||||
else
|
||||
gt_0 = gt_2;
|
||||
|
||||
// Convert to 3-channel BGR
|
||||
if (gt.channels() == 3)
|
||||
gt.copyTo(gt_3);
|
||||
else
|
||||
cvtColor(gt, gt_3, COLOR_BGRA2BGR);
|
||||
|
||||
if (gt.depth() == CV_16U)
|
||||
gt_3.convertTo(gt_1, CV_8U, 1. / 256);
|
||||
else
|
||||
gt_1 = gt_3;
|
||||
|
||||
// Convert to RGB for IMREAD_COLOR_RGB variants
|
||||
cvtColor(gt_1, gt_256, COLOR_BGR2RGB);
|
||||
cvtColor(gt_3, gt_258, COLOR_BGR2RGB);
|
||||
}
|
||||
|
||||
const double epsGrayAnydepth = ((gt.depth() == CV_16U) && (gt.channels() > 1)) ? OPENCV_IMGCODECS_PNG_EPS_16BIT_GRAY: OPENCV_IMGCODECS_PNG_EPS_DEFAULT;
|
||||
|
||||
// Perform comparisons with different imread flags
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(1, 0), imread(filename, IMREAD_GRAYSCALE), gt_0);
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(1, 0), imread(filename, IMREAD_COLOR), gt_1);
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(epsGrayAnydepth, 0), imread(filename, IMREAD_ANYDEPTH), gt_2); // IMREAD_GRAYSCALE is used.
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), imread(filename, IMREAD_COLOR | IMREAD_ANYDEPTH), gt_3);
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(1, 0), imread(filename, IMREAD_COLOR_RGB), gt_256);
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), imread(filename, IMREAD_COLOR_RGB | IMREAD_ANYDEPTH), gt_258);
|
||||
|
||||
// Uncomment this block to write out the decoded images for visual/manual inspection
|
||||
// or for regenerating expected ground truth PNGs (for example, after changing decoder logic).
|
||||
#if 0
|
||||
imwrite(filename + "_0.png", imread(filename, IMREAD_GRAYSCALE));
|
||||
imwrite(filename + "_1.png", imread(filename, IMREAD_COLOR));
|
||||
imwrite(filename + "_2.png", imread(filename, IMREAD_ANYDEPTH));
|
||||
imwrite(filename + "_3.png", imread(filename, IMREAD_COLOR | IMREAD_ANYDEPTH));
|
||||
imwrite(filename + "_256.png", imread(filename, IMREAD_COLOR_RGB));
|
||||
imwrite(filename + "_258.png", imread(filename, IMREAD_COLOR_RGB | IMREAD_ANYDEPTH));
|
||||
#endif
|
||||
|
||||
// Uncomment this block to verify that saved images (from above) load identically
|
||||
// when read back with IMREAD_UNCHANGED. Helps ensure write-read symmetry.
|
||||
#if 0
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), imread(filename, IMREAD_GRAYSCALE), imread(filename + "_0.png", IMREAD_UNCHANGED));
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), imread(filename, IMREAD_COLOR), imread(filename + "_1.png", IMREAD_UNCHANGED));
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), imread(filename, IMREAD_ANYDEPTH), imread(filename + "_2.png", IMREAD_UNCHANGED));
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), imread(filename, IMREAD_COLOR | IMREAD_ANYDEPTH), imread(filename + "_3.png", IMREAD_UNCHANGED));
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), imread(filename, IMREAD_COLOR_RGB), imread(filename + "_256.png", IMREAD_UNCHANGED));
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), imread(filename, IMREAD_COLOR_RGB | IMREAD_ANYDEPTH), imread(filename + "_258.png", IMREAD_UNCHANGED));
|
||||
#endif
|
||||
}
|
||||
|
||||
const string pngsuite_files[] =
|
||||
{
|
||||
"basi0g01",
|
||||
"basi0g02",
|
||||
"basi0g04",
|
||||
"basi0g08",
|
||||
"basi0g16",
|
||||
"basi2c08",
|
||||
"basi2c16",
|
||||
"basi3p01",
|
||||
"basi3p02",
|
||||
"basi3p04",
|
||||
"basi3p08",
|
||||
"basi4a08",
|
||||
"basi4a16",
|
||||
"basi6a08",
|
||||
"basi6a16",
|
||||
"basn0g01",
|
||||
"basn0g02",
|
||||
"basn0g04",
|
||||
"basn0g08",
|
||||
"basn0g16",
|
||||
"basn2c08",
|
||||
"basn2c16",
|
||||
"basn3p01",
|
||||
"basn3p02",
|
||||
"basn3p04",
|
||||
"basn3p08",
|
||||
"basn4a08",
|
||||
"basn4a16",
|
||||
"basn6a08",
|
||||
"basn6a16",
|
||||
"bgai4a08",
|
||||
"bgai4a16",
|
||||
"bgan6a08",
|
||||
"bgan6a16",
|
||||
"bgbn4a08",
|
||||
"bggn4a16",
|
||||
"bgwn6a08",
|
||||
"bgyn6a16",
|
||||
"ccwn2c08",
|
||||
"ccwn3p08",
|
||||
"cdfn2c08",
|
||||
"cdhn2c08",
|
||||
"cdsn2c08",
|
||||
"cdun2c08",
|
||||
"ch1n3p04",
|
||||
"ch2n3p08",
|
||||
"cm0n0g04",
|
||||
"cm7n0g04",
|
||||
"cm9n0g04",
|
||||
"cs3n2c16",
|
||||
"cs3n3p08",
|
||||
"cs5n2c08",
|
||||
"cs5n3p08",
|
||||
"cs8n2c08",
|
||||
"cs8n3p08",
|
||||
"ct0n0g04",
|
||||
"ct1n0g04",
|
||||
"cten0g04",
|
||||
"ctfn0g04",
|
||||
"ctgn0g04",
|
||||
"cthn0g04",
|
||||
"ctjn0g04",
|
||||
"ctzn0g04",
|
||||
"exif2c08",
|
||||
"f00n0g08",
|
||||
"f00n2c08",
|
||||
"f01n0g08",
|
||||
"f01n2c08",
|
||||
"f02n0g08",
|
||||
"f02n2c08",
|
||||
"f03n0g08",
|
||||
"f03n2c08",
|
||||
"f04n0g08",
|
||||
"f04n2c08",
|
||||
"f99n0g04",
|
||||
"g03n0g16",
|
||||
"g04n0g16",
|
||||
"g05n0g16",
|
||||
"g07n0g16",
|
||||
"g10n0g16",
|
||||
"g10n2c08",
|
||||
"g10n3p04",
|
||||
"g25n0g16",
|
||||
"oi1n0g16",
|
||||
"oi1n2c16",
|
||||
"oi2n0g16",
|
||||
"oi2n2c16",
|
||||
"oi4n0g16",
|
||||
"oi4n2c16",
|
||||
"oi9n0g16",
|
||||
"oi9n2c16",
|
||||
"pp0n2c16",
|
||||
"pp0n6a08",
|
||||
"ps1n0g08",
|
||||
"ps1n2c16",
|
||||
"ps2n0g08",
|
||||
"ps2n2c16",
|
||||
"s01i3p01",
|
||||
"s01n3p01",
|
||||
"s02i3p01",
|
||||
"s02n3p01",
|
||||
"s03i3p01",
|
||||
"s03n3p01",
|
||||
"s04i3p01",
|
||||
"s04n3p01",
|
||||
"s05i3p02",
|
||||
"s05n3p02",
|
||||
"s06i3p02",
|
||||
"s06n3p02",
|
||||
"s07i3p02",
|
||||
"s07n3p02",
|
||||
"s08i3p02",
|
||||
"s08n3p02",
|
||||
"s09i3p02",
|
||||
"s09n3p02",
|
||||
"s32i3p04",
|
||||
"s32n3p04",
|
||||
"s33i3p04",
|
||||
"s33n3p04",
|
||||
"s34i3p04",
|
||||
"s34n3p04",
|
||||
"s35i3p04",
|
||||
"s35n3p04",
|
||||
"s36i3p04",
|
||||
"s36n3p04",
|
||||
"s37i3p04",
|
||||
"s37n3p04",
|
||||
"s38i3p04",
|
||||
"s38n3p04",
|
||||
"s39i3p04",
|
||||
"s39n3p04",
|
||||
"s40i3p04",
|
||||
"s40n3p04",
|
||||
"tbbn0g04",
|
||||
"tbbn2c16",
|
||||
"tbbn3p08",
|
||||
"tbgn2c16",
|
||||
"tbgn3p08",
|
||||
"tbrn2c08",
|
||||
"tbwn0g16",
|
||||
"tbwn3p08",
|
||||
"tbyn3p08",
|
||||
"tm3n3p02",
|
||||
"tp0n0g08",
|
||||
"tp0n2c08",
|
||||
"tp0n3p08",
|
||||
"tp1n3p08",
|
||||
"z00n2c08",
|
||||
"z03n2c08",
|
||||
"z06n2c08",
|
||||
"z09n2c08",
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/*nothing*/, Imgcodecs_Png_PngSuite,
|
||||
testing::ValuesIn(pngsuite_files));
|
||||
|
||||
typedef testing::TestWithParam<string> Imgcodecs_Png_PngSuite_Gamma;
|
||||
|
||||
// Parameterized test for decoding PNG files from the PNGSuite test set
|
||||
TEST_P(Imgcodecs_Png_PngSuite_Gamma, decode)
|
||||
{
|
||||
// Construct full paths for the PNG image and corresponding ground truth XML file
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + "pngsuite/" + GetParam() + ".png";
|
||||
const string xml_filename = root + "pngsuite/" + GetParam() + ".xml";
|
||||
|
||||
// Load the XML file containing the ground truth data
|
||||
FileStorage fs(xml_filename, FileStorage::READ);
|
||||
ASSERT_TRUE(fs.isOpened()); // Ensure the file was opened successfully
|
||||
|
||||
// Load the image using IMREAD_UNCHANGED to preserve original format
|
||||
Mat src = imread(filename, IMREAD_UNCHANGED);
|
||||
ASSERT_FALSE(src.empty()); // Ensure the image was loaded successfully
|
||||
|
||||
// Load the ground truth matrix from XML
|
||||
Mat gt;
|
||||
fs.getFirstTopLevelNode() >> gt;
|
||||
|
||||
// Compare the image loaded with IMREAD_UNCHANGED to the ground truth
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), src, gt);
|
||||
}
|
||||
|
||||
const string pngsuite_files_gamma[] =
|
||||
{
|
||||
"g03n2c08",
|
||||
"g03n3p04",
|
||||
"g04n2c08",
|
||||
"g04n3p04",
|
||||
"g05n2c08",
|
||||
"g05n3p04",
|
||||
"g07n2c08",
|
||||
"g07n3p04",
|
||||
"g25n2c08",
|
||||
"g25n3p04"
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/*nothing*/, Imgcodecs_Png_PngSuite_Gamma,
|
||||
testing::ValuesIn(pngsuite_files_gamma));
|
||||
|
||||
typedef testing::TestWithParam<string> Imgcodecs_Png_PngSuite_Corrupted;
|
||||
|
||||
TEST_P(Imgcodecs_Png_PngSuite_Corrupted, decode)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + "pngsuite/" + GetParam() + ".png";
|
||||
|
||||
Mat src = imread(filename, IMREAD_UNCHANGED);
|
||||
|
||||
// Corrupted files should not be read
|
||||
EXPECT_TRUE(src.empty());
|
||||
}
|
||||
|
||||
const string pngsuite_files_corrupted[] = {
|
||||
"xc1n0g08",
|
||||
"xc9n2c08",
|
||||
"xcrn0g04",
|
||||
"xcsn0g01",
|
||||
"xd0n2c08",
|
||||
"xd3n2c08",
|
||||
"xd9n2c08",
|
||||
"xdtn0g01",
|
||||
"xhdn0g08",
|
||||
"xlfn0g04",
|
||||
"xs1n0g01",
|
||||
"xs2n0g01",
|
||||
"xs4n0g01",
|
||||
"xs7n0g01",
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/*nothing*/, Imgcodecs_Png_PngSuite_Corrupted,
|
||||
testing::ValuesIn(pngsuite_files_corrupted));
|
||||
|
||||
CV_ENUM(PNGStrategy, IMWRITE_PNG_STRATEGY_DEFAULT, IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY, IMWRITE_PNG_STRATEGY_RLE, IMWRITE_PNG_STRATEGY_FIXED);
|
||||
CV_ENUM(PNGFilters, IMWRITE_PNG_FILTER_NONE, IMWRITE_PNG_FILTER_SUB, IMWRITE_PNG_FILTER_UP, IMWRITE_PNG_FILTER_AVG, IMWRITE_PNG_FILTER_PAETH, IMWRITE_PNG_FAST_FILTERS, IMWRITE_PNG_ALL_FILTERS);
|
||||
|
||||
typedef testing::TestWithParam<testing::tuple<string, PNGStrategy, PNGFilters, int>> Imgcodecs_Png_Encode;
|
||||
|
||||
TEST_P(Imgcodecs_Png_Encode, params)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + "pngsuite/" + get<0>(GetParam());
|
||||
|
||||
const int strategy = get<1>(GetParam());
|
||||
const int filter = get<2>(GetParam());
|
||||
const int compression_level = get<3>(GetParam());
|
||||
|
||||
std::vector<uchar> file_buf;
|
||||
readFileBytes(filename, file_buf);
|
||||
Mat src = imdecode(file_buf, IMREAD_UNCHANGED);
|
||||
EXPECT_FALSE(src.empty()) << "Cannot decode test image " << filename;
|
||||
|
||||
vector<uchar> buf;
|
||||
imencode(".png", src, buf, { IMWRITE_PNG_COMPRESSION, compression_level, IMWRITE_PNG_STRATEGY, strategy, IMWRITE_PNG_FILTER, filter });
|
||||
EXPECT_EQ(buf.size(), file_buf.size());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/,
|
||||
Imgcodecs_Png_Encode,
|
||||
testing::Values(
|
||||
make_tuple("f00n0g08.png", IMWRITE_PNG_STRATEGY_DEFAULT, IMWRITE_PNG_FILTER_NONE, 6),
|
||||
make_tuple("f00n2c08.png", IMWRITE_PNG_STRATEGY_DEFAULT, IMWRITE_PNG_FILTER_NONE, 6),
|
||||
make_tuple("f01n0g08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_FILTER_SUB, 6),
|
||||
make_tuple("f01n2c08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_FILTER_SUB, 6),
|
||||
make_tuple("f02n0g08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_FILTER_UP, 6),
|
||||
make_tuple("f02n2c08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_FILTER_UP, 6),
|
||||
make_tuple("f03n0g08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_FILTER_AVG, 6),
|
||||
make_tuple("f03n2c08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_FILTER_AVG, 6),
|
||||
make_tuple("f04n0g08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_FILTER_PAETH, 6),
|
||||
make_tuple("f04n2c08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_FILTER_PAETH, 6),
|
||||
make_tuple("z03n2c08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_ALL_FILTERS, 3),
|
||||
make_tuple("z06n2c08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_ALL_FILTERS, 6),
|
||||
make_tuple("z09n2c08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_ALL_FILTERS, 9)));
|
||||
|
||||
typedef testing::TestWithParam<testing::tuple<string, int, size_t>> Imgcodecs_Png_ImwriteFlags;
|
||||
|
||||
TEST_P(Imgcodecs_Png_ImwriteFlags, compression_level)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + get<0>(GetParam());
|
||||
|
||||
const int compression_level = get<1>(GetParam());
|
||||
const size_t compression_level_output_size = get<2>(GetParam());
|
||||
|
||||
Mat src = imread(filename, IMREAD_UNCHANGED);
|
||||
EXPECT_FALSE(src.empty()) << "Cannot read test image " << filename;
|
||||
|
||||
vector<uchar> buf;
|
||||
imencode(".png", src, buf, { IMWRITE_PNG_COMPRESSION, compression_level });
|
||||
EXPECT_EQ(buf.size(), compression_level_output_size);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/,
|
||||
Imgcodecs_Png_ImwriteFlags,
|
||||
testing::Values(
|
||||
make_tuple("../perf/512x512.png", 0, 788279),
|
||||
make_tuple("../perf/512x512.png", 1, 179503),
|
||||
make_tuple("../perf/512x512.png", 2, 176007),
|
||||
make_tuple("../perf/512x512.png", 3, 170497),
|
||||
make_tuple("../perf/512x512.png", 4, 163357),
|
||||
make_tuple("../perf/512x512.png", 5, 159190),
|
||||
make_tuple("../perf/512x512.png", 6, 156621),
|
||||
make_tuple("../perf/512x512.png", 7, 155696),
|
||||
make_tuple("../perf/512x512.png", 8, 153708),
|
||||
make_tuple("../perf/512x512.png", 9, 152181)));
|
||||
|
||||
// See https://github.com/opencv/opencv/issues/27614
|
||||
typedef testing::TestWithParam<int> Imgcodecs_Png_ZLIBBUFFER_SIZE;
|
||||
TEST_P(Imgcodecs_Png_ZLIBBUFFER_SIZE, encode_regression_27614)
|
||||
{
|
||||
Mat img(320,240,CV_8UC3,cv::Scalar(64,76,43));
|
||||
vector<uint8_t> buff;
|
||||
bool status = false;
|
||||
ASSERT_NO_THROW(status = imencode(".png", img, buff, { IMWRITE_PNG_ZLIBBUFFER_SIZE, GetParam() }));
|
||||
ASSERT_TRUE(status);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/*nothing*/, Imgcodecs_Png_ZLIBBUFFER_SIZE,
|
||||
testing::Values(5,
|
||||
6, // Minimum limit
|
||||
8192, // Default value
|
||||
131072, // 128 KiB
|
||||
262144, // 256 KiB
|
||||
1048576, // Maximum limit
|
||||
1048577));
|
||||
|
||||
#endif // HAVE_PNG
|
||||
|
||||
}} // namespace
|
||||
Reference in New Issue
Block a user