1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 07:43:03 +04:00

Merge branch 4.x

This commit is contained in:
Alexander Smorkalov
2025-04-28 22:13:51 +03:00
243 changed files with 12965 additions and 3216 deletions
+105
View File
@@ -588,6 +588,111 @@ INSTANTIATE_TEST_CASE_P(/**/,
Imgcodecs_ImageCollection,
testing::ValuesIn(exts_multi));
TEST(Imgcodecs_APNG, imdecode_animation)
{
Animation gt_animation, mem_animation;
// Set the path to the test image directory and filename for loading.
const string root = cvtest::TS::ptr()->get_data_path();
const string filename = root + "pngsuite/tp1n3p08.png";
EXPECT_TRUE(imreadanimation(filename, gt_animation));
EXPECT_EQ(1000, gt_animation.durations.back());
std::vector<unsigned char> buf;
readFileBytes(filename, buf);
EXPECT_TRUE(imdecodeanimation(buf, mem_animation));
EXPECT_EQ(mem_animation.frames.size(), gt_animation.frames.size());
EXPECT_EQ(mem_animation.bgcolor, gt_animation.bgcolor);
EXPECT_EQ(mem_animation.loop_count, gt_animation.loop_count);
for (size_t i = 0; i < gt_animation.frames.size(); i++)
{
EXPECT_EQ(0, cvtest::norm(mem_animation.frames[i], gt_animation.frames[i], NORM_INF));
EXPECT_EQ(mem_animation.durations[i], gt_animation.durations[i]);
}
}
TEST(Imgcodecs_APNG, imencode_animation)
{
Animation gt_animation, mem_animation;
// Set the path to the test image directory and filename for loading.
const string root = cvtest::TS::ptr()->get_data_path();
const string filename = root + "pngsuite/tp1n3p08.png";
EXPECT_TRUE(imreadanimation(filename, gt_animation));
EXPECT_EQ(1000, gt_animation.durations.back());
std::vector<unsigned char> buf;
EXPECT_TRUE(imencodeanimation(".png", gt_animation, buf));
EXPECT_TRUE(imdecodeanimation(buf, mem_animation));
EXPECT_EQ(mem_animation.frames.size(), gt_animation.frames.size());
EXPECT_EQ(mem_animation.bgcolor, gt_animation.bgcolor);
EXPECT_EQ(mem_animation.loop_count, gt_animation.loop_count);
for (size_t i = 0; i < gt_animation.frames.size(); i++)
{
EXPECT_EQ(0, cvtest::norm(mem_animation.frames[i], gt_animation.frames[i], NORM_INF));
EXPECT_EQ(mem_animation.durations[i], gt_animation.durations[i]);
}
}
#endif // HAVE_PNG
#if defined(HAVE_PNG) || defined(HAVE_SPNG)
TEST(Imgcodecs_APNG, imread_animation_16u)
{
// Set the path to the test image directory and filename for loading.
const string root = cvtest::TS::ptr()->get_data_path();
const string filename = root + "readwrite/033.png";
Mat img = imread(filename, IMREAD_UNCHANGED);
ASSERT_FALSE(img.empty());
EXPECT_TRUE(img.type() == CV_16UC4);
EXPECT_EQ(0, img.at<ushort>(0, 0));
EXPECT_EQ(0, img.at<ushort>(0, 1));
EXPECT_EQ(65280, img.at<ushort>(0, 2));
EXPECT_EQ(65535, img.at<ushort>(0, 3));
img = imread(filename, IMREAD_GRAYSCALE);
ASSERT_FALSE(img.empty());
EXPECT_TRUE(img.type() == CV_8UC1);
EXPECT_EQ(76, img.at<uchar>(0, 0));
img = imread(filename, IMREAD_COLOR);
ASSERT_FALSE(img.empty());
EXPECT_TRUE(img.type() == CV_8UC3);
EXPECT_EQ(0, img.at<uchar>(0, 0));
EXPECT_EQ(0, img.at<uchar>(0, 1));
EXPECT_EQ(255, img.at<uchar>(0, 2));
img = imread(filename, IMREAD_COLOR_RGB);
ASSERT_FALSE(img.empty());
EXPECT_TRUE(img.type() == CV_8UC3);
EXPECT_EQ(255, img.at<uchar>(0, 0));
EXPECT_EQ(0, img.at<uchar>(0, 1));
EXPECT_EQ(0, img.at<uchar>(0, 2));
img = imread(filename, IMREAD_ANYDEPTH);
ASSERT_FALSE(img.empty());
EXPECT_TRUE(img.type() == CV_16UC1);
EXPECT_EQ(19519, img.at<ushort>(0, 0));
img = imread(filename, IMREAD_COLOR | IMREAD_ANYDEPTH);
ASSERT_FALSE(img.empty());
EXPECT_TRUE(img.type() == CV_16UC3);
EXPECT_EQ(0, img.at<ushort>(0, 0));
EXPECT_EQ(0, img.at<ushort>(0, 1));
EXPECT_EQ(65280, img.at<ushort>(0, 2));
img = imread(filename, IMREAD_COLOR_RGB | IMREAD_ANYDEPTH);
ASSERT_FALSE(img.empty());
EXPECT_TRUE(img.type() == CV_16UC3);
EXPECT_EQ(65280, img.at<ushort>(0, 0));
EXPECT_EQ(0, img.at<ushort>(0, 1));
EXPECT_EQ(0, img.at<ushort>(0, 2));
}
#endif // HAVE_PNG || HAVE_SPNG
}} // namespace
+104
View File
@@ -414,6 +414,110 @@ TEST(Imgcodecs_Gif, decode_disposal_method)
}
}
// See https://github.com/opencv/opencv/issues/26970
typedef testing::TestWithParam<int> Imgcodecs_Gif_loop_count;
TEST_P(Imgcodecs_Gif_loop_count, imwriteanimation)
{
const string gif_filename = cv::tempfile(".gif");
int loopCount = GetParam();
cv::Animation anim(loopCount);
vector<cv::Mat> src;
for(int n = 1; n <= 5 ; n ++ )
{
cv::Mat frame(64, 64, CV_8UC3, cv::Scalar::all(0));
cv::putText(frame, cv::format("%d", n), cv::Point(0,64), cv::FONT_HERSHEY_PLAIN, 4.0, cv::Scalar::all(255));
anim.frames.push_back(frame);
anim.durations.push_back(1000 /* ms */);
}
bool ret = false;
#if 0
// To output gif image for test.
EXPECT_NO_THROW(ret = imwriteanimation(cv::format("gif_loop-%d.gif", loopCount), anim));
EXPECT_TRUE(ret);
#endif
EXPECT_NO_THROW(ret = imwriteanimation(gif_filename, anim));
EXPECT_TRUE(ret);
// Read raw GIF data.
std::ifstream ifs(gif_filename);
std::stringstream ss;
ss << ifs.rdbuf();
string tmp = ss.str();
std::vector<uint8_t> buf(tmp.begin(), tmp.end());
std::vector<uint8_t> netscape = {0x21, 0xFF, 0x0B, 'N','E','T','S','C','A','P','E','2','.','0'};
auto pos = std::search(buf.begin(), buf.end(), netscape.begin(), netscape.end());
if(loopCount == 1) {
EXPECT_EQ(pos, buf.end()) << "Netscape Application Block should not be included if Animation.loop_count == 1";
} else {
EXPECT_NE(pos, buf.end()) << "Netscape Application Block should be included if Animation.loop_count != 1";
}
remove(gif_filename.c_str());
}
INSTANTIATE_TEST_CASE_P(/*nothing*/,
Imgcodecs_Gif_loop_count,
testing::Values(
-1,
0, // Default, loop-forever
1,
2,
65534,
65535, // Maximum Limit
65536
)
);
typedef testing::TestWithParam<int> Imgcodecs_Gif_duration;
TEST_P(Imgcodecs_Gif_duration, imwriteanimation)
{
const string gif_filename = cv::tempfile(".gif");
cv::Animation anim;
int duration = GetParam();
vector<cv::Mat> src;
for(int n = 1; n <= 5 ; n ++ )
{
cv::Mat frame(64, 64, CV_8UC3, cv::Scalar::all(0));
cv::putText(frame, cv::format("%d", n), cv::Point(0,64), cv::FONT_HERSHEY_PLAIN, 4.0, cv::Scalar::all(255));
anim.frames.push_back(frame);
anim.durations.push_back(duration /* ms */);
}
bool ret = false;
#if 0
// To output gif image for test.
EXPECT_NO_THROW(ret = imwriteanimation(cv::format("gif_duration-%d.gif", duration), anim));
EXPECT_EQ(ret, ( (0 <= duration) && (duration <= 655350) ) );
#endif
EXPECT_NO_THROW(ret = imwriteanimation(gif_filename, anim));
EXPECT_EQ(ret, ( (0 <= duration) && (duration <= 655350) ) );
remove(gif_filename.c_str());
}
INSTANTIATE_TEST_CASE_P(/*nothing*/,
Imgcodecs_Gif_duration,
testing::Values(
-1, // Unsupported
0, // Undefined Behaviour
1,
9,
10,
50,
100, // 10 FPS
1000, // 1 FPS
655340,
655350, // Maximum Limit
655360 // Unsupported
)
);
}//opencv_test
}//namespace