diff --git a/modules/imgcodecs/CMakeLists.txt b/modules/imgcodecs/CMakeLists.txt index 1468d4d73b..45b19da643 100644 --- a/modules/imgcodecs/CMakeLists.txt +++ b/modules/imgcodecs/CMakeLists.txt @@ -190,7 +190,7 @@ endif() if(TARGET opencv_test_imgcodecs AND HAVE_OPENEXR AND "$ENV{OPENCV_IO_ENABLE_OPENEXR}") ocv_target_compile_definitions(opencv_test_imgcodecs PRIVATE OPENCV_IMGCODECS_ENABLE_OPENEXR_TESTS=1) endif() -if(TARGET opencv_test_imgcodecs AND ((HAVE_PNG AND NOT (PNG_VERSION VERSION_LESS "1.6.31")) OR HAVE_SPNG)) +if(TARGET opencv_test_imgcodecs AND ((HAVE_PNG AND NOT (PNG_VERSION_STRING VERSION_LESS "1.6.31")) OR HAVE_SPNG)) # details: https://github.com/glennrp/libpng/commit/68cb0aaee3de6371b81a4613476d9b33e43e95b1 ocv_target_compile_definitions(opencv_test_imgcodecs PRIVATE OPENCV_IMGCODECS_PNG_WITH_EXIF=1) endif() diff --git a/modules/imgcodecs/src/loadsave.cpp b/modules/imgcodecs/src/loadsave.cpp index 31a0166d83..b057b35a9f 100644 --- a/modules/imgcodecs/src/loadsave.cpp +++ b/modules/imgcodecs/src/loadsave.cpp @@ -83,6 +83,9 @@ static Size validateInputImageSize(const Size& size) static inline int calcType(int type, int flags) { + if ( (flags & (IMREAD_COLOR | IMREAD_ANYCOLOR | IMREAD_ANYDEPTH)) == (IMREAD_COLOR | IMREAD_ANYCOLOR | IMREAD_ANYDEPTH)) + return type; + if( (flags & IMREAD_LOAD_GDAL) != IMREAD_LOAD_GDAL && flags != IMREAD_UNCHANGED ) { if( (flags & IMREAD_ANYDEPTH) == 0 ) diff --git a/modules/imgcodecs/test/test_avif.cpp b/modules/imgcodecs/test/test_avif.cpp index d94e5d458c..5b82452049 100644 --- a/modules/imgcodecs/test/test_avif.cpp +++ b/modules/imgcodecs/test/test_avif.cpp @@ -187,51 +187,6 @@ INSTANTIATE_TEST_CASE_P( //////////////////////////////////////////////////////////////////////////////// -typedef testing::TestWithParam Imgcodecs_AVIF_Exif; - -TEST_P(Imgcodecs_AVIF_Exif, exif_orientation) { - const string root = cvtest::TS::ptr()->get_data_path(); - const string filename = root + GetParam(); - const int colorThresholdHigh = 250; - const int colorThresholdLow = 5; - - Mat m_img = imread(filename); - ASSERT_FALSE(m_img.empty()); - Vec3b vec; - - // Checking the first quadrant (with supposed red) - vec = m_img.at(2, 2); // some point inside the square - EXPECT_LE(vec.val[0], colorThresholdLow); - EXPECT_LE(vec.val[1], colorThresholdLow); - EXPECT_GE(vec.val[2], colorThresholdHigh); - - // Checking the second quadrant (with supposed green) - vec = m_img.at(2, 7); // some point inside the square - EXPECT_LE(vec.val[0], colorThresholdLow); - EXPECT_GE(vec.val[1], colorThresholdHigh); - EXPECT_LE(vec.val[2], colorThresholdLow); - - // Checking the third quadrant (with supposed blue) - vec = m_img.at(7, 2); // some point inside the square - EXPECT_GE(vec.val[0], colorThresholdHigh); - EXPECT_LE(vec.val[1], colorThresholdLow); - EXPECT_LE(vec.val[2], colorThresholdLow); -} - -const string exif_files[] = {"readwrite/testExifOrientation_1.avif", - "readwrite/testExifOrientation_2.avif", - "readwrite/testExifOrientation_3.avif", - "readwrite/testExifOrientation_4.avif", - "readwrite/testExifOrientation_5.avif", - "readwrite/testExifOrientation_6.avif", - "readwrite/testExifOrientation_7.avif", - "readwrite/testExifOrientation_8.avif"}; - -INSTANTIATE_TEST_CASE_P(ExifFiles, Imgcodecs_AVIF_Exif, - testing::ValuesIn(exif_files)); - -//////////////////////////////////////////////////////////////////////////////// - class Imgcodecs_Avif_Animation_RoundTripSuite : public Imgcodecs_Avif_RoundTripSuite { public: diff --git a/modules/imgcodecs/test/test_exif.cpp b/modules/imgcodecs/test/test_exif.cpp new file mode 100644 index 0000000000..62cd471e23 --- /dev/null +++ b/modules/imgcodecs/test/test_exif.cpp @@ -0,0 +1,151 @@ +// 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" + +namespace opencv_test { namespace { + +/** + * Test to check whether the EXIF orientation tag was processed successfully or not. + * The test uses a set of 8 images named testExifOrientation_{1 to 8}.(extension). + * Each test image is a 10x10 square, divided into four smaller sub-squares: + * (R corresponds to Red, G to Green, B to Blue, W to White) + * --------- --------- + * | R | G | | G | R | + * |-------| - (tag 1) |-------| - (tag 2) + * | B | W | | W | B | + * --------- --------- + * + * --------- --------- + * | W | B | | B | W | + * |-------| - (tag 3) |-------| - (tag 4) + * | G | R | | R | G | + * --------- --------- + * + * --------- --------- + * | R | B | | G | W | + * |-------| - (tag 5) |-------| - (tag 6) + * | G | W | | R | B | + * --------- --------- + * + * --------- --------- + * | W | G | | B | R | + * |-------| - (tag 7) |-------| - (tag 8) + * | B | R | | W | G | + * --------- --------- + * + * + * Each image contains an EXIF field with an orientation tag (0x112). + * After reading each image and applying the orientation tag, + * the resulting image should be: + * --------- + * | R | G | + * |-------| + * | B | W | + * --------- + * + * Note: + * The flags parameter of the imread function is set as IMREAD_COLOR | IMREAD_ANYCOLOR | IMREAD_ANYDEPTH. + * Using this combination is an undocumented trick to load images similarly to the IMREAD_UNCHANGED flag, + * preserving the alpha channel (if present) while also applying the orientation. + */ + +typedef testing::TestWithParam Exif; + +TEST_P(Exif, exif_orientation) +{ + const string root = cvtest::TS::ptr()->get_data_path(); + const string filename = root + GetParam(); + const int colorThresholdHigh = 250; + const int colorThresholdLow = 5; + + // Refer to the note in the explanation above. + Mat m_img = imread(filename, IMREAD_COLOR | IMREAD_ANYCOLOR | IMREAD_ANYDEPTH); + ASSERT_FALSE(m_img.empty()); + + if (m_img.channels() == 3) + { + Vec3b vec; + + //Checking the first quadrant (with supposed red) + vec = m_img.at(2, 2); //some point inside the square + EXPECT_LE(vec.val[0], colorThresholdLow); + EXPECT_LE(vec.val[1], colorThresholdLow); + EXPECT_GE(vec.val[2], colorThresholdHigh); + + //Checking the second quadrant (with supposed green) + vec = m_img.at(2, 7); //some point inside the square + EXPECT_LE(vec.val[0], colorThresholdLow); + EXPECT_GE(vec.val[1], colorThresholdHigh); + EXPECT_LE(vec.val[2], colorThresholdLow); + + //Checking the third quadrant (with supposed blue) + vec = m_img.at(7, 2); //some point inside the square + EXPECT_GE(vec.val[0], colorThresholdHigh); + EXPECT_LE(vec.val[1], colorThresholdLow); + EXPECT_LE(vec.val[2], colorThresholdLow); + } + else + { + Vec4b vec; + + //Checking the first quadrant (with supposed red) + vec = m_img.at(2, 2); //some point inside the square + EXPECT_LE(vec.val[0], colorThresholdLow); + EXPECT_LE(vec.val[1], colorThresholdLow); + EXPECT_GE(vec.val[2], colorThresholdHigh); + + //Checking the second quadrant (with supposed green) + vec = m_img.at(2, 7); //some point inside the square + EXPECT_LE(vec.val[0], colorThresholdLow); + EXPECT_GE(vec.val[1], colorThresholdHigh); + EXPECT_LE(vec.val[2], colorThresholdLow); + + //Checking the third quadrant (with supposed blue) + vec = m_img.at(7, 2); //some point inside the square + EXPECT_GE(vec.val[0], colorThresholdHigh); + EXPECT_LE(vec.val[1], colorThresholdLow); + EXPECT_LE(vec.val[2], colorThresholdLow); + } +} + +const string exif_files[] = +{ +#ifdef HAVE_JPEG + "readwrite/testExifOrientation_1.jpg", + "readwrite/testExifOrientation_2.jpg", + "readwrite/testExifOrientation_3.jpg", + "readwrite/testExifOrientation_4.jpg", + "readwrite/testExifOrientation_5.jpg", + "readwrite/testExifOrientation_6.jpg", + "readwrite/testExifOrientation_7.jpg", + "readwrite/testExifOrientation_8.jpg", +#endif +#ifdef OPENCV_IMGCODECS_PNG_WITH_EXIF + "readwrite/testExifOrientation_1.png", + "readwrite/testExifOrientation_2.png", + "readwrite/testExifOrientation_3.png", + "readwrite/testExifOrientation_4.png", + "readwrite/testExifOrientation_5.png", + "readwrite/testExifOrientation_6.png", + "readwrite/testExifOrientation_7.png", + "readwrite/testExifOrientation_8.png", +#endif +#ifdef HAVE_AVIF + "readwrite/testExifOrientation_1.avif", + "readwrite/testExifOrientation_2.avif", + "readwrite/testExifOrientation_3.avif", + "readwrite/testExifOrientation_4.avif", + "readwrite/testExifOrientation_5.avif", + "readwrite/testExifOrientation_6.avif", + "readwrite/testExifOrientation_7.avif", + "readwrite/testExifOrientation_8.avif", +#endif +}; + +INSTANTIATE_TEST_CASE_P(Imgcodecs, Exif, + testing::ValuesIn(exif_files)); + +} +} diff --git a/modules/imgcodecs/test/test_jpeg.cpp b/modules/imgcodecs/test/test_jpeg.cpp index 503848068a..ca46ae751c 100644 --- a/modules/imgcodecs/test/test_jpeg.cpp +++ b/modules/imgcodecs/test/test_jpeg.cpp @@ -11,95 +11,6 @@ extern "C" { #include "jpeglib.h" } -/** - * Test for check whether reading exif orientation tag was processed successfully or not - * The test info is the set of 8 images named testExifRotate_{1 to 8}.jpg - * The test image is the square 10x10 points divided by four sub-squares: - * (R corresponds to Red, G to Green, B to Blue, W to white) - * --------- --------- - * | R | G | | G | R | - * |-------| - (tag 1) |-------| - (tag 2) - * | B | W | | W | B | - * --------- --------- - * - * --------- --------- - * | W | B | | B | W | - * |-------| - (tag 3) |-------| - (tag 4) - * | G | R | | R | G | - * --------- --------- - * - * --------- --------- - * | R | B | | G | W | - * |-------| - (tag 5) |-------| - (tag 6) - * | G | W | | R | B | - * --------- --------- - * - * --------- --------- - * | W | G | | B | R | - * |-------| - (tag 7) |-------| - (tag 8) - * | B | R | | W | G | - * --------- --------- - * - * - * Every image contains exif field with orientation tag (0x112) - * After reading each image the corresponding matrix must be read as - * --------- - * | R | G | - * |-------| - * | B | W | - * --------- - * - */ - -typedef testing::TestWithParam Imgcodecs_Jpeg_Exif; - -TEST_P(Imgcodecs_Jpeg_Exif, exif_orientation) -{ - const string root = cvtest::TS::ptr()->get_data_path(); - const string filename = root + GetParam(); - const int colorThresholdHigh = 250; - const int colorThresholdLow = 5; - - Mat m_img = imread(filename); - ASSERT_FALSE(m_img.empty()); - Vec3b vec; - - //Checking the first quadrant (with supposed red) - vec = m_img.at(2, 2); //some point inside the square - EXPECT_LE(vec.val[0], colorThresholdLow); - EXPECT_LE(vec.val[1], colorThresholdLow); - EXPECT_GE(vec.val[2], colorThresholdHigh); - - //Checking the second quadrant (with supposed green) - vec = m_img.at(2, 7); //some point inside the square - EXPECT_LE(vec.val[0], colorThresholdLow); - EXPECT_GE(vec.val[1], colorThresholdHigh); - EXPECT_LE(vec.val[2], colorThresholdLow); - - //Checking the third quadrant (with supposed blue) - vec = m_img.at(7, 2); //some point inside the square - EXPECT_GE(vec.val[0], colorThresholdHigh); - EXPECT_LE(vec.val[1], colorThresholdLow); - EXPECT_LE(vec.val[2], colorThresholdLow); -} - -const string exif_files[] = -{ - "readwrite/testExifOrientation_1.jpg", - "readwrite/testExifOrientation_2.jpg", - "readwrite/testExifOrientation_3.jpg", - "readwrite/testExifOrientation_4.jpg", - "readwrite/testExifOrientation_5.jpg", - "readwrite/testExifOrientation_6.jpg", - "readwrite/testExifOrientation_7.jpg", - "readwrite/testExifOrientation_8.jpg" -}; - -INSTANTIATE_TEST_CASE_P(ExifFiles, Imgcodecs_Jpeg_Exif, - testing::ValuesIn(exif_files)); - -//================================================================================================== - TEST(Imgcodecs_Jpeg, encode_empty) { cv::Mat img; diff --git a/modules/imgcodecs/test/test_png.cpp b/modules/imgcodecs/test/test_png.cpp index 13aca2e396..4cf0e0cd99 100644 --- a/modules/imgcodecs/test/test_png.cpp +++ b/modules/imgcodecs/test/test_png.cpp @@ -109,100 +109,6 @@ TEST(Imgcodecs_Png, read_color_palette_with_alpha) EXPECT_EQ(img.at(0, 1), Vec3b(255, 0, 0)); } -/** - * Test for check whether reading exif orientation tag was processed successfully or not - * The test info is the set of 8 images named testExifRotate_{1 to 8}.png - * The test image is the square 10x10 points divided by four sub-squares: - * (R corresponds to Red, G to Green, B to Blue, W to white) - * --------- --------- - * | R | G | | G | R | - * |-------| - (tag 1) |-------| - (tag 2) - * | B | W | | W | B | - * --------- --------- - * - * --------- --------- - * | W | B | | B | W | - * |-------| - (tag 3) |-------| - (tag 4) - * | G | R | | R | G | - * --------- --------- - * - * --------- --------- - * | R | B | | G | W | - * |-------| - (tag 5) |-------| - (tag 6) - * | G | W | | R | B | - * --------- --------- - * - * --------- --------- - * | W | G | | B | R | - * |-------| - (tag 7) |-------| - (tag 8) - * | B | R | | W | G | - * --------- --------- - * - * - * Every image contains exif field with orientation tag (0x112) - * After reading each image and applying the orientation tag, - * the resulting image should be: - * --------- - * | R | G | - * |-------| - * | B | W | - * --------- - * - */ - -typedef testing::TestWithParam Imgcodecs_PNG_Exif; - -// Solution to issue 16579: PNG read doesn't support Exif orientation data -#ifdef OPENCV_IMGCODECS_PNG_WITH_EXIF -TEST_P(Imgcodecs_PNG_Exif, exif_orientation) -#else -TEST_P(Imgcodecs_PNG_Exif, DISABLED_exif_orientation) -#endif -{ - const string root = cvtest::TS::ptr()->get_data_path(); - const string filename = root + GetParam(); - const int colorThresholdHigh = 250; - const int colorThresholdLow = 5; - - Mat m_img = imread(filename); - ASSERT_FALSE(m_img.empty()); - Vec3b vec; - - //Checking the first quadrant (with supposed red) - vec = m_img.at(2, 2); //some point inside the square - EXPECT_LE(vec.val[0], colorThresholdLow); - EXPECT_LE(vec.val[1], colorThresholdLow); - EXPECT_GE(vec.val[2], colorThresholdHigh); - - //Checking the second quadrant (with supposed green) - vec = m_img.at(2, 7); //some point inside the square - EXPECT_LE(vec.val[0], colorThresholdLow); - EXPECT_GE(vec.val[1], colorThresholdHigh); - EXPECT_LE(vec.val[2], colorThresholdLow); - - //Checking the third quadrant (with supposed blue) - vec = m_img.at(7, 2); //some point inside the square - EXPECT_GE(vec.val[0], colorThresholdHigh); - EXPECT_LE(vec.val[1], colorThresholdLow); - EXPECT_LE(vec.val[2], colorThresholdLow); -} - -const string exif_files[] = -{ - "readwrite/testExifOrientation_1.png", - "readwrite/testExifOrientation_2.png", - "readwrite/testExifOrientation_3.png", - "readwrite/testExifOrientation_4.png", - "readwrite/testExifOrientation_5.png", - "readwrite/testExifOrientation_6.png", - "readwrite/testExifOrientation_7.png", - "readwrite/testExifOrientation_8.png" -}; - -INSTANTIATE_TEST_CASE_P(ExifFiles, Imgcodecs_PNG_Exif, - testing::ValuesIn(exif_files)); - - typedef testing::TestWithParam Imgcodecs_Png_PngSuite; TEST_P(Imgcodecs_Png_PngSuite, decode)