test_animation.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. // This file is part of OpenCV project.
  2. // It is subject to the license terms in the LICENSE file found in the top-level directory
  3. // of this distribution and at http://opencv.org/license.html.
  4. #include "test_precomp.hpp"
  5. #include "test_common.hpp"
  6. namespace opencv_test { namespace {
  7. static bool fillFrames(Animation& animation, bool hasAlpha, int n = 14)
  8. {
  9. // Set the path to the test image directory and filename for loading.
  10. const string root = cvtest::TS::ptr()->get_data_path();
  11. const string filename = root + "pngsuite/tp1n3p08.png";
  12. EXPECT_TRUE(imreadanimation(filename, animation));
  13. EXPECT_EQ(1000, animation.durations.back());
  14. if (!hasAlpha)
  15. cvtColor(animation.frames[0], animation.frames[0], COLOR_BGRA2BGR);
  16. animation.loop_count = 0xffff; // 0xffff is the maximum value to set.
  17. // Add the first frame with a duration value of 400 milliseconds.
  18. int duration = 80;
  19. animation.durations[0] = duration * 5;
  20. Mat image = animation.frames[0].clone();
  21. putText(animation.frames[0], "0", Point(5, 28), FONT_HERSHEY_SIMPLEX, .5, Scalar(100, 255, 0, 255), 2);
  22. // Define a region of interest (ROI)
  23. Rect roi(2, 16, 26, 16);
  24. // Modify the ROI in n iterations to simulate slight changes in animation frames.
  25. for (int i = 1; i < n; i++)
  26. {
  27. roi.x++;
  28. roi.width -= 2;
  29. RNG rng = theRNG();
  30. for (int x = roi.x; x < roi.x + roi.width; x++)
  31. for (int y = roi.y; y < roi.y + roi.height; y++)
  32. {
  33. if (hasAlpha)
  34. {
  35. Vec4b& pixel = image.at<Vec4b>(y, x);
  36. if (pixel[3] > 0)
  37. {
  38. if (pixel[0] > 10) pixel[0] -= (uchar)rng.uniform(2, 5);
  39. if (pixel[1] > 10) pixel[1] -= (uchar)rng.uniform(2, 5);
  40. if (pixel[2] > 10) pixel[2] -= (uchar)rng.uniform(2, 5);
  41. pixel[3] -= (uchar)rng.uniform(2, 5);
  42. }
  43. }
  44. else
  45. {
  46. Vec3b& pixel = image.at<Vec3b>(y, x);
  47. if (pixel[0] > 50) pixel[0] -= (uchar)rng.uniform(2, 5);
  48. if (pixel[1] > 50) pixel[1] -= (uchar)rng.uniform(2, 5);
  49. if (pixel[2] > 50) pixel[2] -= (uchar)rng.uniform(2, 5);
  50. }
  51. }
  52. // Update the duration and add the modified frame to the animation.
  53. duration += rng.uniform(2, 10); // Increase duration with random value (to be sure different duration values saved correctly).
  54. animation.frames.push_back(image.clone());
  55. putText(animation.frames[i], format("%d", i), Point(5, 28), FONT_HERSHEY_SIMPLEX, .5, Scalar(100, 255, 0, 255), 2);
  56. animation.durations.push_back(duration);
  57. }
  58. // Add two identical frames with the same duration.
  59. if (animation.frames.size() > 1 && animation.frames.size() < 20)
  60. {
  61. animation.durations.push_back(++duration);
  62. animation.frames.push_back(animation.frames.back());
  63. animation.durations.push_back(++duration);
  64. animation.frames.push_back(animation.frames.back());
  65. }
  66. return true;
  67. }
  68. #ifdef HAVE_IMGCODEC_GIF
  69. TEST(Imgcodecs_Gif, imwriteanimation_rgba)
  70. {
  71. Animation s_animation, l_animation;
  72. EXPECT_TRUE(fillFrames(s_animation, true));
  73. s_animation.bgcolor = Scalar(0, 0, 0, 0); // TO DO not implemented yet.
  74. // Create a temporary output filename for saving the animation.
  75. string output = cv::tempfile(".gif");
  76. // Write the animation to a .webp file and verify success.
  77. EXPECT_TRUE(imwriteanimation(output, s_animation));
  78. // Read the animation back and compare with the original.
  79. EXPECT_TRUE(imreadanimation(output, l_animation));
  80. size_t expected_frame_count = s_animation.frames.size();
  81. // Verify that the number of frames matches the expected count.
  82. EXPECT_EQ(expected_frame_count, imcount(output));
  83. EXPECT_EQ(expected_frame_count, l_animation.frames.size());
  84. // Check that the background color and loop count match between saved and loaded animations.
  85. EXPECT_EQ(l_animation.bgcolor, s_animation.bgcolor); // written as BGRA order
  86. EXPECT_EQ(l_animation.loop_count, s_animation.loop_count);
  87. // Verify that the durations of frames match.
  88. for (size_t i = 0; i < l_animation.frames.size() - 1; i++)
  89. EXPECT_EQ(cvRound(s_animation.durations[i] / 10), cvRound(l_animation.durations[i] / 10));
  90. EXPECT_TRUE(imreadanimation(output, l_animation, 5, 3));
  91. EXPECT_EQ(expected_frame_count + 3, l_animation.frames.size());
  92. EXPECT_EQ(l_animation.frames.size(), l_animation.durations.size());
  93. EXPECT_EQ(0, cvtest::norm(l_animation.frames[5], l_animation.frames[16], NORM_INF));
  94. EXPECT_EQ(0, cvtest::norm(l_animation.frames[6], l_animation.frames[17], NORM_INF));
  95. EXPECT_EQ(0, cvtest::norm(l_animation.frames[7], l_animation.frames[18], NORM_INF));
  96. // Verify whether the imread function successfully loads the first frame
  97. Mat frame = imread(output, IMREAD_UNCHANGED);
  98. EXPECT_EQ(0, cvtest::norm(l_animation.frames[0], frame, NORM_INF));
  99. std::vector<uchar> buf;
  100. readFileBytes(output, buf);
  101. vector<Mat> webp_frames;
  102. EXPECT_TRUE(imdecodemulti(buf, IMREAD_UNCHANGED, webp_frames));
  103. EXPECT_EQ(expected_frame_count, webp_frames.size());
  104. // Clean up by removing the temporary file.
  105. EXPECT_EQ(0, remove(output.c_str()));
  106. }
  107. #endif // HAVE_IMGCODEC_GIF
  108. #ifdef HAVE_WEBP
  109. TEST(Imgcodecs_WebP, imwriteanimation_rgba)
  110. {
  111. Animation s_animation, l_animation;
  112. EXPECT_TRUE(fillFrames(s_animation, true));
  113. s_animation.bgcolor = Scalar(50, 100, 150, 128); // different values for test purpose.
  114. // Create a temporary output filename for saving the animation.
  115. string output = cv::tempfile(".webp");
  116. // Write the animation to a .webp file and verify success.
  117. EXPECT_TRUE(imwriteanimation(output, s_animation));
  118. // Read the animation back and compare with the original.
  119. EXPECT_TRUE(imreadanimation(output, l_animation));
  120. // Since the last frames are identical, WebP optimizes by storing only one of them,
  121. // and the duration value for the last frame is handled by libwebp.
  122. size_t expected_frame_count = s_animation.frames.size() - 2;
  123. // Verify that the number of frames matches the expected count.
  124. EXPECT_EQ(expected_frame_count, imcount(output));
  125. EXPECT_EQ(expected_frame_count, l_animation.frames.size());
  126. // Check that the background color and loop count match between saved and loaded animations.
  127. EXPECT_EQ(l_animation.bgcolor, s_animation.bgcolor); // written as BGRA order
  128. EXPECT_EQ(l_animation.loop_count, s_animation.loop_count);
  129. // Verify that the durations of frames match.
  130. for (size_t i = 0; i < l_animation.frames.size() - 1; i++)
  131. EXPECT_EQ(s_animation.durations[i], l_animation.durations[i]);
  132. EXPECT_TRUE(imreadanimation(output, l_animation, 5, 3));
  133. EXPECT_EQ(expected_frame_count + 3, l_animation.frames.size());
  134. EXPECT_EQ(l_animation.frames.size(), l_animation.durations.size());
  135. EXPECT_EQ(0, cvtest::norm(l_animation.frames[5], l_animation.frames[14], NORM_INF));
  136. EXPECT_EQ(0, cvtest::norm(l_animation.frames[6], l_animation.frames[15], NORM_INF));
  137. EXPECT_EQ(0, cvtest::norm(l_animation.frames[7], l_animation.frames[16], NORM_INF));
  138. // Verify whether the imread function successfully loads the first frame
  139. Mat frame = imread(output, IMREAD_UNCHANGED);
  140. EXPECT_EQ(0, cvtest::norm(l_animation.frames[0], frame, NORM_INF));
  141. std::vector<uchar> buf;
  142. readFileBytes(output, buf);
  143. vector<Mat> webp_frames;
  144. EXPECT_TRUE(imdecodemulti(buf, IMREAD_UNCHANGED, webp_frames));
  145. EXPECT_EQ(expected_frame_count, webp_frames.size());
  146. // Clean up by removing the temporary file.
  147. EXPECT_EQ(0, remove(output.c_str()));
  148. }
  149. TEST(Imgcodecs_WebP, imwriteanimation_rgb)
  150. {
  151. Animation s_animation, l_animation;
  152. EXPECT_TRUE(fillFrames(s_animation, false));
  153. // Create a temporary output filename for saving the animation.
  154. string output = cv::tempfile(".webp");
  155. // Write the animation to a .webp file and verify success.
  156. EXPECT_TRUE(imwriteanimation(output, s_animation));
  157. // Read the animation back and compare with the original.
  158. EXPECT_TRUE(imreadanimation(output, l_animation));
  159. // Since the last frames are identical, WebP optimizes by storing only one of them,
  160. // and the duration value for the last frame is handled by libwebp.
  161. size_t expected_frame_count = s_animation.frames.size() - 2;
  162. // Verify that the number of frames matches the expected count.
  163. EXPECT_EQ(expected_frame_count, imcount(output));
  164. EXPECT_EQ(expected_frame_count, l_animation.frames.size());
  165. // Verify that the durations of frames match.
  166. for (size_t i = 0; i < l_animation.frames.size() - 1; i++)
  167. EXPECT_EQ(s_animation.durations[i], l_animation.durations[i]);
  168. EXPECT_TRUE(imreadanimation(output, l_animation, 5, 3));
  169. EXPECT_EQ(expected_frame_count + 3, l_animation.frames.size());
  170. EXPECT_EQ(l_animation.frames.size(), l_animation.durations.size());
  171. EXPECT_TRUE(cvtest::norm(l_animation.frames[5], l_animation.frames[14], NORM_INF) == 0);
  172. EXPECT_TRUE(cvtest::norm(l_animation.frames[6], l_animation.frames[15], NORM_INF) == 0);
  173. EXPECT_TRUE(cvtest::norm(l_animation.frames[7], l_animation.frames[16], NORM_INF) == 0);
  174. // Verify whether the imread function successfully loads the first frame
  175. Mat frame = imread(output, IMREAD_COLOR);
  176. EXPECT_TRUE(cvtest::norm(l_animation.frames[0], frame, NORM_INF) == 0);
  177. std::vector<uchar> buf;
  178. readFileBytes(output, buf);
  179. vector<Mat> webp_frames;
  180. EXPECT_TRUE(imdecodemulti(buf, IMREAD_UNCHANGED, webp_frames));
  181. EXPECT_EQ(expected_frame_count,webp_frames.size());
  182. // Clean up by removing the temporary file.
  183. EXPECT_EQ(0, remove(output.c_str()));
  184. }
  185. TEST(Imgcodecs_WebP, imwritemulti_rgba)
  186. {
  187. Animation s_animation;
  188. EXPECT_TRUE(fillFrames(s_animation, true));
  189. string output = cv::tempfile(".webp");
  190. ASSERT_TRUE(imwrite(output, s_animation.frames));
  191. vector<Mat> read_frames;
  192. ASSERT_TRUE(imreadmulti(output, read_frames, IMREAD_UNCHANGED));
  193. EXPECT_EQ(s_animation.frames.size() - 2, read_frames.size());
  194. EXPECT_EQ(4, s_animation.frames[0].channels());
  195. EXPECT_EQ(0, remove(output.c_str()));
  196. }
  197. TEST(Imgcodecs_WebP, imwritemulti_rgb)
  198. {
  199. Animation s_animation;
  200. EXPECT_TRUE(fillFrames(s_animation, false));
  201. string output = cv::tempfile(".webp");
  202. ASSERT_TRUE(imwrite(output, s_animation.frames));
  203. vector<Mat> read_frames;
  204. ASSERT_TRUE(imreadmulti(output, read_frames));
  205. EXPECT_EQ(s_animation.frames.size() - 2, read_frames.size());
  206. EXPECT_EQ(0, remove(output.c_str()));
  207. }
  208. TEST(Imgcodecs_WebP, imencode_rgba)
  209. {
  210. Animation s_animation;
  211. EXPECT_TRUE(fillFrames(s_animation, true, 3));
  212. std::vector<uchar> buf;
  213. vector<Mat> apng_frames;
  214. // Test encoding and decoding the images in memory (without saving to disk).
  215. EXPECT_TRUE(imencode(".webp", s_animation.frames, buf));
  216. EXPECT_TRUE(imdecodemulti(buf, IMREAD_UNCHANGED, apng_frames));
  217. EXPECT_EQ(s_animation.frames.size() - 2, apng_frames.size());
  218. }
  219. #endif // HAVE_WEBP
  220. #ifdef HAVE_PNG
  221. TEST(Imgcodecs_APNG, imwriteanimation_rgba)
  222. {
  223. Animation s_animation, l_animation;
  224. EXPECT_TRUE(fillFrames(s_animation, true));
  225. // Create a temporary output filename for saving the animation.
  226. string output = cv::tempfile(".png");
  227. // Write the animation to a .png file and verify success.
  228. EXPECT_TRUE(imwriteanimation(output, s_animation));
  229. // Read the animation back and compare with the original.
  230. EXPECT_TRUE(imreadanimation(output, l_animation));
  231. size_t expected_frame_count = s_animation.frames.size() - 2;
  232. // Verify that the number of frames matches the expected count.
  233. EXPECT_EQ(expected_frame_count, imcount(output));
  234. EXPECT_EQ(expected_frame_count, l_animation.frames.size());
  235. for (size_t i = 0; i < l_animation.frames.size() - 1; i++)
  236. {
  237. EXPECT_EQ(s_animation.durations[i], l_animation.durations[i]);
  238. EXPECT_EQ(0, cvtest::norm(s_animation.frames[i], l_animation.frames[i], NORM_INF));
  239. }
  240. EXPECT_TRUE(imreadanimation(output, l_animation, 5, 3));
  241. EXPECT_EQ(expected_frame_count + 3, l_animation.frames.size());
  242. EXPECT_EQ(l_animation.frames.size(), l_animation.durations.size());
  243. EXPECT_EQ(0, cvtest::norm(l_animation.frames[5], l_animation.frames[14], NORM_INF));
  244. EXPECT_EQ(0, cvtest::norm(l_animation.frames[6], l_animation.frames[15], NORM_INF));
  245. EXPECT_EQ(0, cvtest::norm(l_animation.frames[7], l_animation.frames[16], NORM_INF));
  246. // Verify whether the imread function successfully loads the first frame
  247. Mat frame = imread(output, IMREAD_UNCHANGED);
  248. EXPECT_EQ(0, cvtest::norm(l_animation.frames[0], frame, NORM_INF));
  249. std::vector<uchar> buf;
  250. readFileBytes(output, buf);
  251. vector<Mat> apng_frames;
  252. EXPECT_TRUE(imdecodemulti(buf, IMREAD_UNCHANGED, apng_frames));
  253. EXPECT_EQ(expected_frame_count, apng_frames.size());
  254. apng_frames.clear();
  255. // Test saving the animation frames as individual still images.
  256. EXPECT_TRUE(imwrite(output, s_animation.frames));
  257. // Read back the still images into a vector of Mats.
  258. EXPECT_TRUE(imreadmulti(output, apng_frames));
  259. // Expect all frames written as multi-page image
  260. EXPECT_EQ(expected_frame_count, apng_frames.size());
  261. // Clean up by removing the temporary file.
  262. EXPECT_EQ(0, remove(output.c_str()));
  263. }
  264. TEST(Imgcodecs_APNG, imwriteanimation_rgba16u)
  265. {
  266. Animation s_animation, l_animation;
  267. EXPECT_TRUE(fillFrames(s_animation, true));
  268. for (size_t i = 0; i < s_animation.frames.size(); i++)
  269. {
  270. s_animation.frames[i].convertTo(s_animation.frames[i], CV_16U, 255);
  271. }
  272. // Create a temporary output filename for saving the animation.
  273. string output = cv::tempfile(".png");
  274. // Write the animation to a .png file and verify success.
  275. EXPECT_TRUE(imwriteanimation(output, s_animation));
  276. // Read the animation back and compare with the original.
  277. EXPECT_TRUE(imreadanimation(output, l_animation));
  278. size_t expected_frame_count = s_animation.frames.size() - 2;
  279. // Verify that the number of frames matches the expected count.
  280. EXPECT_EQ(expected_frame_count, imcount(output));
  281. EXPECT_EQ(expected_frame_count, l_animation.frames.size());
  282. std::vector<uchar> buf;
  283. readFileBytes(output, buf);
  284. vector<Mat> apng_frames;
  285. EXPECT_TRUE(imdecodemulti(buf, IMREAD_UNCHANGED, apng_frames));
  286. EXPECT_EQ(expected_frame_count, apng_frames.size());
  287. apng_frames.clear();
  288. // Test saving the animation frames as individual still images.
  289. EXPECT_TRUE(imwrite(output, s_animation.frames));
  290. // Read back the still images into a vector of Mats.
  291. EXPECT_TRUE(imreadmulti(output, apng_frames));
  292. // Expect all frames written as multi-page image
  293. EXPECT_EQ(expected_frame_count, apng_frames.size());
  294. // Clean up by removing the temporary file.
  295. EXPECT_EQ(0, remove(output.c_str()));
  296. }
  297. TEST(Imgcodecs_APNG, imwriteanimation_rgb)
  298. {
  299. Animation s_animation, l_animation;
  300. EXPECT_TRUE(fillFrames(s_animation, false));
  301. string output = cv::tempfile(".png");
  302. // Write the animation to a .png file and verify success.
  303. EXPECT_TRUE(imwriteanimation(output, s_animation));
  304. // Read the animation back and compare with the original.
  305. EXPECT_TRUE(imreadanimation(output, l_animation));
  306. EXPECT_EQ(l_animation.frames.size(), s_animation.frames.size() - 2);
  307. for (size_t i = 0; i < l_animation.frames.size() - 1; i++)
  308. {
  309. EXPECT_EQ(0, cvtest::norm(s_animation.frames[i], l_animation.frames[i], NORM_INF));
  310. }
  311. EXPECT_EQ(0, remove(output.c_str()));
  312. }
  313. TEST(Imgcodecs_APNG, imwriteanimation_gray)
  314. {
  315. Animation s_animation, l_animation;
  316. EXPECT_TRUE(fillFrames(s_animation, false));
  317. for (size_t i = 0; i < s_animation.frames.size(); i++)
  318. {
  319. cvtColor(s_animation.frames[i], s_animation.frames[i], COLOR_BGR2GRAY);
  320. }
  321. s_animation.bgcolor = Scalar(50, 100, 150);
  322. string output = cv::tempfile(".png");
  323. // Write the animation to a .png file and verify success.
  324. EXPECT_TRUE(imwriteanimation(output, s_animation));
  325. // Read the animation back and compare with the original.
  326. EXPECT_TRUE(imreadanimation(output, l_animation));
  327. EXPECT_EQ(Scalar(), l_animation.bgcolor);
  328. size_t expected_frame_count = s_animation.frames.size() - 2;
  329. // Verify that the number of frames matches the expected count.
  330. EXPECT_EQ(expected_frame_count, imcount(output));
  331. EXPECT_EQ(expected_frame_count, l_animation.frames.size());
  332. EXPECT_EQ(0, remove(output.c_str()));
  333. for (size_t i = 0; i < l_animation.frames.size(); i++)
  334. {
  335. EXPECT_EQ(0, cvtest::norm(s_animation.frames[i], l_animation.frames[i], NORM_INF));
  336. }
  337. }
  338. TEST(Imgcodecs_APNG, imwritemulti_rgba)
  339. {
  340. Animation s_animation;
  341. EXPECT_TRUE(fillFrames(s_animation, true));
  342. string output = cv::tempfile(".png");
  343. EXPECT_EQ(true, imwrite(output, s_animation.frames));
  344. vector<Mat> read_frames;
  345. EXPECT_EQ(true, imreadmulti(output, read_frames, IMREAD_UNCHANGED));
  346. EXPECT_EQ(read_frames.size(), s_animation.frames.size() - 2);
  347. EXPECT_EQ(imcount(output), read_frames.size());
  348. EXPECT_EQ(0, remove(output.c_str()));
  349. }
  350. TEST(Imgcodecs_APNG, imwritemulti_rgb)
  351. {
  352. Animation s_animation;
  353. EXPECT_TRUE(fillFrames(s_animation, false));
  354. string output = cv::tempfile(".png");
  355. ASSERT_TRUE(imwrite(output, s_animation.frames));
  356. vector<Mat> read_frames;
  357. ASSERT_TRUE(imreadmulti(output, read_frames));
  358. EXPECT_EQ(read_frames.size(), s_animation.frames.size() - 2);
  359. EXPECT_EQ(0, remove(output.c_str()));
  360. for (size_t i = 0; i < read_frames.size(); i++)
  361. {
  362. EXPECT_EQ(0, cvtest::norm(s_animation.frames[i], read_frames[i], NORM_INF));
  363. }
  364. }
  365. TEST(Imgcodecs_APNG, imwritemulti_gray)
  366. {
  367. Animation s_animation;
  368. EXPECT_TRUE(fillFrames(s_animation, false));
  369. for (size_t i = 0; i < s_animation.frames.size(); i++)
  370. {
  371. cvtColor(s_animation.frames[i], s_animation.frames[i], COLOR_BGR2GRAY);
  372. }
  373. string output = cv::tempfile(".png");
  374. EXPECT_TRUE(imwrite(output, s_animation.frames));
  375. vector<Mat> read_frames;
  376. EXPECT_TRUE(imreadmulti(output, read_frames));
  377. EXPECT_EQ(1, read_frames[0].channels());
  378. read_frames.clear();
  379. EXPECT_TRUE(imreadmulti(output, read_frames, IMREAD_UNCHANGED));
  380. EXPECT_EQ(1, read_frames[0].channels());
  381. read_frames.clear();
  382. EXPECT_TRUE(imreadmulti(output, read_frames, IMREAD_COLOR));
  383. EXPECT_EQ(3, read_frames[0].channels());
  384. read_frames.clear();
  385. EXPECT_TRUE(imreadmulti(output, read_frames, IMREAD_GRAYSCALE));
  386. EXPECT_EQ(0, remove(output.c_str()));
  387. for (size_t i = 0; i < read_frames.size(); i++)
  388. {
  389. EXPECT_EQ(0, cvtest::norm(s_animation.frames[i], read_frames[i], NORM_INF));
  390. }
  391. }
  392. TEST(Imgcodecs_APNG, imwriteanimation_bgcolor)
  393. {
  394. Animation s_animation, l_animation;
  395. EXPECT_TRUE(fillFrames(s_animation, true, 2));
  396. s_animation.bgcolor = Scalar(50, 100, 150); // will be written in bKGD chunk as RGB.
  397. // Create a temporary output filename for saving the animation.
  398. string output = cv::tempfile(".png");
  399. // Write the animation to a .png file and verify success.
  400. EXPECT_TRUE(imwriteanimation(output, s_animation));
  401. // Read the animation back and compare with the original.
  402. EXPECT_TRUE(imreadanimation(output, l_animation));
  403. // Check that the background color match between saved and loaded animations.
  404. EXPECT_EQ(l_animation.bgcolor, s_animation.bgcolor);
  405. EXPECT_EQ(0, remove(output.c_str()));
  406. EXPECT_TRUE(fillFrames(s_animation, true, 2));
  407. s_animation.bgcolor = Scalar();
  408. output = cv::tempfile(".png");
  409. EXPECT_TRUE(imwriteanimation(output, s_animation));
  410. EXPECT_TRUE(imreadanimation(output, l_animation));
  411. EXPECT_EQ(l_animation.bgcolor, s_animation.bgcolor);
  412. EXPECT_EQ(0, remove(output.c_str()));
  413. }
  414. TEST(Imgcodecs_APNG, imencode_rgba)
  415. {
  416. Animation s_animation;
  417. EXPECT_TRUE(fillFrames(s_animation, true, 3));
  418. std::vector<uchar> buf;
  419. vector<Mat> read_frames;
  420. // Test encoding and decoding the images in memory (without saving to disk).
  421. EXPECT_TRUE(imencode(".png", s_animation.frames, buf));
  422. EXPECT_TRUE(imdecodemulti(buf, IMREAD_UNCHANGED, read_frames));
  423. EXPECT_EQ(read_frames.size(), s_animation.frames.size() - 2);
  424. }
  425. typedef testing::TestWithParam<string> Imgcodecs_ImageCollection;
  426. const string exts_multi[] = {
  427. #ifdef HAVE_AVIF
  428. ".avif",
  429. #endif
  430. #ifdef HAVE_IMGCODEC_GIF
  431. ".gif",
  432. #endif
  433. ".png",
  434. #ifdef HAVE_TIFF
  435. ".tiff",
  436. #endif
  437. #ifdef HAVE_WEBP
  438. ".webp",
  439. #endif
  440. };
  441. TEST_P(Imgcodecs_ImageCollection, animations)
  442. {
  443. Animation s_animation;
  444. EXPECT_TRUE(fillFrames(s_animation, false));
  445. string output = cv::tempfile(GetParam().c_str());
  446. ASSERT_TRUE(imwritemulti(output, s_animation.frames));
  447. vector<Mat> read_frames;
  448. ASSERT_TRUE(imreadmulti(output, read_frames, IMREAD_UNCHANGED));
  449. {
  450. ImageCollection collection(output, IMREAD_UNCHANGED);
  451. EXPECT_EQ(read_frames.size(), collection.size());
  452. int i = 0;
  453. for (auto&& frame : collection)
  454. {
  455. EXPECT_EQ(0, cvtest::norm(frame, read_frames[i], NORM_INF));
  456. ++i;
  457. }
  458. }
  459. EXPECT_EQ(0, remove(output.c_str()));
  460. }
  461. INSTANTIATE_TEST_CASE_P(/**/,
  462. Imgcodecs_ImageCollection,
  463. testing::ValuesIn(exts_multi));
  464. TEST(Imgcodecs_APNG, imdecode_animation)
  465. {
  466. Animation gt_animation, mem_animation;
  467. // Set the path to the test image directory and filename for loading.
  468. const string root = cvtest::TS::ptr()->get_data_path();
  469. const string filename = root + "pngsuite/tp1n3p08.png";
  470. EXPECT_TRUE(imreadanimation(filename, gt_animation));
  471. EXPECT_EQ(1000, gt_animation.durations.back());
  472. std::vector<unsigned char> buf;
  473. readFileBytes(filename, buf);
  474. EXPECT_TRUE(imdecodeanimation(buf, mem_animation));
  475. EXPECT_EQ(mem_animation.frames.size(), gt_animation.frames.size());
  476. EXPECT_EQ(mem_animation.bgcolor, gt_animation.bgcolor);
  477. EXPECT_EQ(mem_animation.loop_count, gt_animation.loop_count);
  478. for (size_t i = 0; i < gt_animation.frames.size(); i++)
  479. {
  480. EXPECT_EQ(0, cvtest::norm(mem_animation.frames[i], gt_animation.frames[i], NORM_INF));
  481. EXPECT_EQ(mem_animation.durations[i], gt_animation.durations[i]);
  482. }
  483. }
  484. TEST(Imgcodecs_APNG, imencode_animation)
  485. {
  486. Animation gt_animation, mem_animation;
  487. // Set the path to the test image directory and filename for loading.
  488. const string root = cvtest::TS::ptr()->get_data_path();
  489. const string filename = root + "pngsuite/tp1n3p08.png";
  490. EXPECT_TRUE(imreadanimation(filename, gt_animation));
  491. EXPECT_EQ(1000, gt_animation.durations.back());
  492. std::vector<unsigned char> buf;
  493. EXPECT_TRUE(imencodeanimation(".png", gt_animation, buf));
  494. EXPECT_TRUE(imdecodeanimation(buf, mem_animation));
  495. EXPECT_EQ(mem_animation.frames.size(), gt_animation.frames.size());
  496. EXPECT_EQ(mem_animation.bgcolor, gt_animation.bgcolor);
  497. EXPECT_EQ(mem_animation.loop_count, gt_animation.loop_count);
  498. for (size_t i = 0; i < gt_animation.frames.size(); i++)
  499. {
  500. EXPECT_EQ(0, cvtest::norm(mem_animation.frames[i], gt_animation.frames[i], NORM_INF));
  501. EXPECT_EQ(mem_animation.durations[i], gt_animation.durations[i]);
  502. }
  503. }
  504. TEST(Imgcodecs_APNG, animation_has_hidden_frame)
  505. {
  506. // Set the path to the test image directory and filename for loading.
  507. const string root = cvtest::TS::ptr()->get_data_path();
  508. const string filename = root + "readwrite/033.png";
  509. Animation animation1, animation2, animation3;
  510. imreadanimation(filename, animation1);
  511. EXPECT_FALSE(animation1.still_image.empty());
  512. EXPECT_EQ((size_t)2, animation1.frames.size());
  513. std::vector<unsigned char> buf;
  514. EXPECT_TRUE(imencodeanimation(".png", animation1, buf));
  515. EXPECT_TRUE(imdecodeanimation(buf, animation2));
  516. EXPECT_FALSE(animation2.still_image.empty());
  517. EXPECT_EQ(animation1.frames.size(), animation2.frames.size());
  518. animation1.frames.erase(animation1.frames.begin());
  519. animation1.durations.erase(animation1.durations.begin());
  520. EXPECT_TRUE(imencodeanimation(".png", animation1, buf));
  521. EXPECT_TRUE(imdecodeanimation(buf, animation3));
  522. EXPECT_FALSE(animation1.still_image.empty());
  523. EXPECT_TRUE(animation3.still_image.empty());
  524. EXPECT_EQ((size_t)1, animation3.frames.size());
  525. }
  526. TEST(Imgcodecs_APNG, animation_imread_preview)
  527. {
  528. // Set the path to the test image directory and filename for loading.
  529. const string root = cvtest::TS::ptr()->get_data_path();
  530. const string filename = root + "readwrite/034.png";
  531. cv::Mat imread_result;
  532. cv::imread(filename, imread_result, cv::IMREAD_UNCHANGED);
  533. EXPECT_FALSE(imread_result.empty());
  534. Animation animation;
  535. ASSERT_TRUE(imreadanimation(filename, animation));
  536. EXPECT_FALSE(animation.still_image.empty());
  537. EXPECT_EQ((size_t)2, animation.frames.size());
  538. EXPECT_EQ(0, cv::norm(animation.still_image, imread_result, cv::NORM_INF));
  539. }
  540. #endif // HAVE_PNG
  541. #if defined(HAVE_PNG) || defined(HAVE_SPNG)
  542. TEST(Imgcodecs_APNG, imread_animation_16u)
  543. {
  544. // Set the path to the test image directory and filename for loading.
  545. const string root = cvtest::TS::ptr()->get_data_path();
  546. const string filename = root + "readwrite/033.png";
  547. Mat img = imread(filename, IMREAD_UNCHANGED);
  548. ASSERT_FALSE(img.empty());
  549. EXPECT_TRUE(img.type() == CV_16UC4);
  550. EXPECT_EQ(0, img.at<ushort>(0, 0));
  551. EXPECT_EQ(0, img.at<ushort>(0, 1));
  552. EXPECT_EQ(65280, img.at<ushort>(0, 2));
  553. EXPECT_EQ(65535, img.at<ushort>(0, 3));
  554. img = imread(filename, IMREAD_GRAYSCALE);
  555. ASSERT_FALSE(img.empty());
  556. EXPECT_TRUE(img.type() == CV_8UC1);
  557. EXPECT_EQ(76, img.at<uchar>(0, 0));
  558. img = imread(filename, IMREAD_COLOR);
  559. ASSERT_FALSE(img.empty());
  560. EXPECT_TRUE(img.type() == CV_8UC3);
  561. EXPECT_EQ(0, img.at<uchar>(0, 0));
  562. EXPECT_EQ(0, img.at<uchar>(0, 1));
  563. EXPECT_EQ(255, img.at<uchar>(0, 2));
  564. img = imread(filename, IMREAD_COLOR_RGB);
  565. ASSERT_FALSE(img.empty());
  566. EXPECT_TRUE(img.type() == CV_8UC3);
  567. EXPECT_EQ(255, img.at<uchar>(0, 0));
  568. EXPECT_EQ(0, img.at<uchar>(0, 1));
  569. EXPECT_EQ(0, img.at<uchar>(0, 2));
  570. img = imread(filename, IMREAD_ANYDEPTH);
  571. ASSERT_FALSE(img.empty());
  572. EXPECT_TRUE(img.type() == CV_16UC1);
  573. EXPECT_EQ(19517, img.at<ushort>(0, 0));
  574. img = imread(filename, IMREAD_COLOR | IMREAD_ANYDEPTH);
  575. ASSERT_FALSE(img.empty());
  576. EXPECT_TRUE(img.type() == CV_16UC3);
  577. EXPECT_EQ(0, img.at<ushort>(0, 0));
  578. EXPECT_EQ(0, img.at<ushort>(0, 1));
  579. EXPECT_EQ(65280, img.at<ushort>(0, 2));
  580. img = imread(filename, IMREAD_COLOR_RGB | IMREAD_ANYDEPTH);
  581. ASSERT_FALSE(img.empty());
  582. EXPECT_TRUE(img.type() == CV_16UC3);
  583. EXPECT_EQ(65280, img.at<ushort>(0, 0));
  584. EXPECT_EQ(0, img.at<ushort>(0, 1));
  585. EXPECT_EQ(0, img.at<ushort>(0, 2));
  586. }
  587. #endif // HAVE_PNG || HAVE_SPNG
  588. }} // namespace