diff --git a/modules/imgcodecs/perf/perf_decode_encode.cpp b/modules/imgcodecs/perf/perf_decode_encode.cpp index 5f675f7a44..bdef7882ee 100644 --- a/modules/imgcodecs/perf/perf_decode_encode.cpp +++ b/modules/imgcodecs/perf/perf_decode_encode.cpp @@ -7,10 +7,82 @@ namespace opencv_test { -#ifdef HAVE_PNG - using namespace perf; +static Animation makeCirclesAnimation(Size size = Size(320, 240), int type = CV_8UC4, int nbits = 8, int frameCount = 40) +{ + struct AnimatedCircle { + cv::Point2f pos; + cv::Point2f velocity; + float radius; + float radius_speed; + cv::Scalar color; + cv::Scalar border_color; + }; + + const int numCircles = 80; + const int maxval = (1 << nbits) - 1; + + cv::RNG rng = theRNG(); + std::vector circles; + Animation animation; + + // Initialize animated circles + for (int i = 0; i < numCircles; ++i) { + AnimatedCircle c; + c.pos = cv::Point2f(rng.uniform(0.f, (float)size.width), + rng.uniform(0.f, (float)size.height)); + c.velocity = cv::Point2f(rng.uniform(-2.f, 2.f), + rng.uniform(-2.f, 2.f)); + c.radius = rng.uniform(10.f, 40.f); + c.radius_speed = rng.uniform(-0.5f, 0.5f); + c.color = cv::Scalar(rng.uniform(0, maxval), + rng.uniform(0, maxval), + rng.uniform(0, maxval), + rng.uniform(230, maxval)); + c.border_color = c.color; + circles.push_back(c); + } + + // Generate frames + for (int frame = 0; frame < frameCount; ++frame) { + cv::Mat img(size, type, cv::Scalar(20, 0, 10, 128)); + + for (size_t i = 0; i < circles.size(); ++i) { + AnimatedCircle& c = circles[i]; + + // Update position + c.pos += c.velocity; + + // Bounce on edges + if (c.pos.x < 0 || c.pos.x > size.width) c.velocity.x *= -1; + if (c.pos.y < 0 || c.pos.y > size.height) c.velocity.y *= -1; + + // Update radius + c.radius += c.radius_speed; + if (c.radius < 10.f || c.radius > 80.f) { + c.radius_speed *= -1; + c.radius = std::max(10.f, std::min(c.radius, 80.f)); + } + + c.color = c.color - Scalar(c.velocity.x, 0, c.velocity.y, rng.uniform(1, 4)); + + // Draw + cv::circle(img, c.pos, (int)c.radius, c.color, cv::FILLED, cv::LINE_AA); + cv::circle(img, c.pos, (int)c.radius, c.border_color, 1, cv::LINE_AA); + } + + animation.frames.push_back(img); + animation.durations.push_back(20); // milliseconds + } + + for (int i = (int)animation.frames.size() - 1; i >= 0; --i) { + animation.frames.push_back(animation.frames[i].clone()); + animation.durations.push_back(15); + } + return animation; +} + typedef perf::TestBaseWithParam Decode; typedef perf::TestBaseWithParam Encode; @@ -32,7 +104,9 @@ const string exts[] = { #ifdef HAVE_JPEGXL ".jxl", #endif +#ifdef HAVE_PNG ".png", +#endif #ifdef HAVE_IMGCODEC_PXM ".ppm", #endif @@ -54,7 +128,9 @@ const string exts_multi[] = { #ifdef HAVE_IMGCODEC_GIF ".gif", #endif +#ifdef HAVE_PNG ".png", +#endif #ifdef HAVE_TIFF ".tiff", #endif @@ -63,6 +139,23 @@ const string exts_multi[] = { #endif }; +const string exts_anim[] = { +#ifdef HAVE_AVIF + ".avif", +#endif +#ifdef HAVE_IMGCODEC_GIF + ".gif", +#endif +#ifdef HAVE_PNG + ".png", +#endif +#ifdef HAVE_WEBP + ".webp", +#endif +}; + +#ifdef HAVE_PNG + PERF_TEST_P(Decode, bgr, testing::ValuesIn(exts)) { String filename = getDataPath("perf/1920x1080.png"); @@ -126,6 +219,63 @@ PERF_TEST_P(Encode, multi, testing::ValuesIn(exts_multi)) SANITY_CHECK_NOTHING(); } + #endif // HAVE_PNG +PERF_TEST_P(Encode, animation, testing::ValuesIn(exts_anim)) +{ + Animation animation = makeCirclesAnimation(); + + TEST_CYCLE() + { + vector buf; + EXPECT_TRUE(imencodeanimation(GetParam().c_str(), animation, buf)); + } + + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(Encode, multi_page, testing::ValuesIn(exts_multi)) +{ + Animation animation = makeCirclesAnimation(); + + TEST_CYCLE() + { + vector buf; + EXPECT_TRUE(imencodemulti(GetParam().c_str(), animation.frames, buf)); + } + + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(Decode, animation, testing::ValuesIn(exts_anim)) +{ + Animation animation = makeCirclesAnimation(); + vector buf; + ASSERT_TRUE(imencodeanimation(GetParam().c_str(), animation, buf)); + + TEST_CYCLE() + { + Animation tmp_animation; + EXPECT_TRUE(imdecodeanimation(buf, tmp_animation)); + } + + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P(Decode, multi_page, testing::ValuesIn(exts_multi)) +{ + Animation animation = makeCirclesAnimation(); + vector buf; + ASSERT_TRUE(imencodemulti(GetParam().c_str(), animation.frames, buf)); + + TEST_CYCLE() + { + vector tmp_frames; + EXPECT_TRUE(imdecodemulti(buf, IMREAD_UNCHANGED, tmp_frames)); + } + + SANITY_CHECK_NOTHING(); +} + } // namespace