| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- // 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 {
- #ifdef HAVE_JPEGXL
- #include <jxl/version.h> // For JPEGXL_MAJOR_VERSION and JPEGXL_MINOR_VERSION
- typedef tuple<perf::MatType, int> MatType_and_Distance;
- typedef testing::TestWithParam<MatType_and_Distance> Imgcodecs_JpegXL_MatType;
- TEST_P(Imgcodecs_JpegXL_MatType, write_read)
- {
- const int matType = get<0>(GetParam());
- const int distanceParam = get<1>(GetParam());
- cv::Scalar col;
- // Jpeg XL supports lossy and lossless compressions.
- // Lossy compression may be small differences in decoding results by environments.
- double th;
- switch( CV_MAT_DEPTH(matType) )
- {
- case CV_16U:
- col = cv::Scalar(124 * 256, 76 * 256, 42 * 256, 192 * 256 );
- th = 656; // = 65535 / 100;
- break;
- case CV_32F:
- col = cv::Scalar(0.486, 0.298, 0.165, 0.75);
- th = 1.0 / 100.0;
- break;
- default:
- case CV_8U:
- col = cv::Scalar(124, 76, 42, 192);
- th = 3; // = 255 / 100 (1%);
- break;
- }
- // If increasing distanceParam, threshold should be increased.
- th *= (distanceParam >= 25) ? 5 : (distanceParam > 2) ? 3 : distanceParam;
- bool ret = false;
- string tmp_fname = cv::tempfile(".jxl");
- Mat img_org(320, 480, matType, col);
- vector<int> param;
- param.push_back(IMWRITE_JPEGXL_DISTANCE);
- param.push_back(distanceParam);
- EXPECT_NO_THROW(ret = imwrite(tmp_fname, img_org, param));
- EXPECT_TRUE(ret);
- Mat img_decoded;
- EXPECT_NO_THROW(img_decoded = imread(tmp_fname, IMREAD_UNCHANGED));
- EXPECT_FALSE(img_decoded.empty());
- EXPECT_LE(cvtest::norm(img_org, img_decoded, NORM_INF), th);
- EXPECT_EQ(0, remove(tmp_fname.c_str()));
- }
- TEST_P(Imgcodecs_JpegXL_MatType, encode_decode)
- {
- const int matType = get<0>(GetParam());
- const int distanceParam = get<1>(GetParam());
- cv::Scalar col;
- // Jpeg XL supports lossy and lossless compressions.
- // Lossy compression may be small differences in decoding results by environments.
- double th;
- // If alpha=0, libjxl modify color channels(BGR). So do not set it.
- switch( CV_MAT_DEPTH(matType) )
- {
- case CV_16U:
- col = cv::Scalar(124 * 256, 76 * 256, 42 * 256, 192 * 256 );
- th = 656; // = 65535 / 100;
- break;
- case CV_32F:
- col = cv::Scalar(0.486, 0.298, 0.165, 0.75);
- th = 1.0 / 100.0;
- break;
- default:
- case CV_8U:
- col = cv::Scalar(124, 76, 42, 192);
- th = 3; // = 255 / 100 (1%);
- break;
- }
- // If increasing distanceParam, threshold should be increased.
- th *= (distanceParam >= 25) ? 5 : (distanceParam > 2) ? 3 : distanceParam;
- bool ret = false;
- vector<uchar> buff;
- Mat img_org(320, 480, matType, col);
- vector<int> param;
- param.push_back(IMWRITE_JPEGXL_DISTANCE);
- param.push_back(distanceParam);
- EXPECT_NO_THROW(ret = imencode(".jxl", img_org, buff, param));
- EXPECT_TRUE(ret);
- Mat img_decoded;
- EXPECT_NO_THROW(img_decoded = imdecode(buff, IMREAD_UNCHANGED));
- EXPECT_FALSE(img_decoded.empty());
- EXPECT_LE(cvtest::norm(img_org, img_decoded, NORM_INF), th);
- }
- INSTANTIATE_TEST_CASE_P(
- /**/,
- Imgcodecs_JpegXL_MatType,
- testing::Combine(
- testing::Values(
- CV_8UC1, CV_8UC3, CV_8UC4,
- CV_16UC1, CV_16UC3, CV_16UC4,
- CV_32FC1, CV_32FC3, CV_32FC4
- ),
- testing::Values( // Distance
- 0, // Lossless
- 1, // Default
- 3, // Recomended Lossy Max
- 25 // Specification Max
- )
- ) );
- typedef tuple<int, int> Effort_and_Decoding_speed;
- typedef testing::TestWithParam<Effort_and_Decoding_speed> Imgcodecs_JpegXL_Effort_DecodingSpeed;
- TEST_P(Imgcodecs_JpegXL_Effort_DecodingSpeed, encode_decode)
- {
- const int effort = get<0>(GetParam());
- const int speed = get<1>(GetParam());
- cv::Scalar col = cv::Scalar(124,76,42);
- // Jpeg XL supports lossy and lossless compression.
- // Lossy compression may be small differences in decoding results by environments.
- double th = 3; // = 255 / 100 (1%);
- bool ret = false;
- vector<uchar> buff;
- Mat img_org(320, 480, CV_8UC3, col);
- vector<int> param;
- param.push_back(IMWRITE_JPEGXL_EFFORT);
- param.push_back(effort);
- param.push_back(IMWRITE_JPEGXL_DECODING_SPEED);
- param.push_back(speed);
- EXPECT_NO_THROW(ret = imencode(".jxl", img_org, buff, param));
- EXPECT_TRUE(ret);
- Mat img_decoded;
- EXPECT_NO_THROW(img_decoded = imdecode(buff, IMREAD_UNCHANGED));
- EXPECT_FALSE(img_decoded.empty());
- EXPECT_LE(cvtest::norm(img_org, img_decoded, NORM_INF), th);
- }
- INSTANTIATE_TEST_CASE_P(
- /**/,
- Imgcodecs_JpegXL_Effort_DecodingSpeed,
- testing::Combine(
- testing::Values( // Effort
- 1, // fastest
- 7, // default
- 9 // slowest
- ),
- testing::Values( // Decoding Speed
- 0, // default, slowest, and best quality/density
- 2,
- 4 // fastest, at the cost of some qulity/density
- )
- ) );
- TEST(Imgcodecs_JpegXL, encode_from_uncontinued_image)
- {
- cv::Mat src(100, 100, CV_8UC1, Scalar(40,50,10));
- cv::Mat roi = src(cv::Rect(10,20,30,50));
- EXPECT_FALSE(roi.isContinuous()); // uncontinued image
- vector<uint8_t> buff;
- vector<int> param;
- bool ret = false;
- EXPECT_NO_THROW(ret = cv::imencode(".jxl", roi, buff, param));
- EXPECT_TRUE(ret);
- }
- // See https://github.com/opencv/opencv/issues/26767
- typedef tuple<perf::MatType, ImreadModes> MatType_and_ImreadFlag;
- typedef testing::TestWithParam<MatType_and_ImreadFlag> Imgcodecs_JpegXL_MatType_ImreadFlag;
- TEST_P(Imgcodecs_JpegXL_MatType_ImreadFlag, all_imreadFlags)
- {
- string tmp_fname = cv::tempfile(".jxl");
- const int matType = get<0>(GetParam());
- const int imreadFlag = get<1>(GetParam());
- Mat img(240, 320, matType);
- randu(img, Scalar(0, 0, 0, 255), Scalar(255, 255, 255, 255));
- vector<int> param;
- param.push_back(IMWRITE_JPEGXL_DISTANCE);
- param.push_back(0 /* Lossless */);
- EXPECT_NO_THROW(imwrite(tmp_fname, img, param));
- Mat img_decoded;
- EXPECT_NO_THROW(img_decoded = imread(tmp_fname, imreadFlag));
- EXPECT_FALSE(img_decoded.empty());
- switch( imreadFlag )
- {
- case IMREAD_UNCHANGED:
- EXPECT_EQ( img.type(), img_decoded.type() );
- break;
- case IMREAD_GRAYSCALE:
- EXPECT_EQ( img_decoded.depth(), CV_8U );
- EXPECT_EQ( img_decoded.channels(), 1 );
- break;
- case IMREAD_COLOR:
- case IMREAD_COLOR_RGB:
- EXPECT_EQ( img_decoded.depth(), CV_8U );
- EXPECT_EQ( img_decoded.channels(), 3 );
- break;
- case IMREAD_ANYDEPTH:
- EXPECT_EQ( img_decoded.depth(), img.depth() );
- EXPECT_EQ( img_decoded.channels(), 1 );
- break;
- case IMREAD_ANYCOLOR:
- EXPECT_EQ( img_decoded.depth(), CV_8U ) ;
- EXPECT_EQ( img_decoded.channels(), img.channels() == 1 ? 1 : 3 ); // Alpha channel will be dropped.
- break;
- }
- remove(tmp_fname.c_str());
- }
- INSTANTIATE_TEST_CASE_P(
- /**/,
- Imgcodecs_JpegXL_MatType_ImreadFlag,
- testing::Combine(
- testing::Values(
- CV_8UC1, CV_8UC3, CV_8UC4,
- CV_16UC1, CV_16UC3, CV_16UC4,
- CV_32FC1, CV_32FC3, CV_32FC4
- ),
- testing::Values(
- IMREAD_UNCHANGED,
- IMREAD_GRAYSCALE,
- IMREAD_COLOR,
- IMREAD_COLOR_RGB,
- IMREAD_ANYDEPTH,
- IMREAD_ANYCOLOR
- )
- ) );
- TEST(Imgcodecs_JpegXL, imdecode_truncated_stream)
- {
- cv::Mat src(100, 100, CV_8UC1, Scalar(40,50,10));
- vector<uint8_t> buff;
- vector<int> param;
- bool ret = false;
- EXPECT_NO_THROW(ret = cv::imencode(".jxl", src, buff, param));
- EXPECT_TRUE(ret);
- // Try to decode non-truncated image.
- cv::Mat decoded;
- EXPECT_NO_THROW(decoded = cv::imdecode(buff, cv::IMREAD_COLOR));
- EXPECT_FALSE(decoded.empty());
- // Try to decode truncated image.
- buff.resize(buff.size() - 1 );
- EXPECT_NO_THROW(decoded = cv::imdecode(buff, cv::IMREAD_COLOR));
- EXPECT_TRUE(decoded.empty());
- }
- TEST(Imgcodecs_JpegXL, imread_truncated_stream)
- {
- string tmp_fname = cv::tempfile(".jxl");
- cv::Mat src(100, 100, CV_8UC1, Scalar(40,50,10));
- vector<uint8_t> buff;
- vector<int> param;
- bool ret = false;
- EXPECT_NO_THROW(ret = cv::imencode(".jxl", src, buff, param));
- EXPECT_TRUE(ret);
- // Try to decode non-truncated image.
- FILE *fp = nullptr;
- fp = fopen(tmp_fname.c_str(), "wb");
- EXPECT_TRUE(fp != nullptr);
- fwrite(&buff[0], sizeof(uint8_t), buff.size(), fp);
- fclose(fp);
- cv::Mat decoded;
- EXPECT_NO_THROW(decoded = cv::imread(tmp_fname, cv::IMREAD_COLOR));
- EXPECT_FALSE(decoded.empty());
- // Try to decode truncated image.
- fp = fopen(tmp_fname.c_str(), "wb");
- EXPECT_TRUE(fp != nullptr);
- fwrite(&buff[0], sizeof(uint8_t), buff.size() - 1, fp);
- fclose(fp);
- EXPECT_NO_THROW(decoded = cv::imread(tmp_fname, cv::IMREAD_COLOR));
- EXPECT_TRUE(decoded.empty());
- // Delete temporary file
- remove(tmp_fname.c_str());
- }
- // See https://github.com/opencv/opencv/issues/27382
- TEST(Imgcodecs_JpegXL, imencode_regression27382)
- {
- cv::Mat image(1024, 1024, CV_16U);
- cv::RNG rng(1024);
- rng.fill(image, cv::RNG::NORMAL, 0, 65535);
- std::vector<unsigned char> buffer;
- std::vector<int> params = {cv::IMWRITE_JPEGXL_DISTANCE, 0}; // lossless
- EXPECT_NO_THROW(cv::imencode(".jxl", image, buffer, params));
- cv::Mat decoded;
- EXPECT_NO_THROW(decoded = cv::imdecode(buffer, cv::IMREAD_UNCHANGED));
- EXPECT_FALSE(decoded.empty());
- cv::Mat diff;
- cv::absdiff(image, decoded, diff);
- double max_diff = 0.0;
- cv::minMaxLoc(diff, nullptr, &max_diff);
- EXPECT_EQ(max_diff, 0 );
- }
- TEST(Imgcodecs_JpegXL, imencode_regression27382_2)
- {
- cv::Mat image(1024, 1024, CV_16U);
- cv::RNG rng(1024);
- rng.fill(image, cv::RNG::NORMAL, 0, 65535);
- std::vector<unsigned char> buffer;
- std::vector<int> params = {cv::IMWRITE_JPEGXL_QUALITY, 100}; // lossless
- EXPECT_NO_THROW(cv::imencode(".jxl", image, buffer, params));
- cv::Mat decoded;
- EXPECT_NO_THROW(decoded = cv::imdecode(buffer, cv::IMREAD_UNCHANGED));
- EXPECT_FALSE(decoded.empty());
- cv::Mat diff;
- cv::absdiff(image, decoded, diff);
- double max_diff = 0.0;
- cv::minMaxLoc(diff, nullptr, &max_diff);
- #if JPEGXL_MAJOR_VERSION > 0 || JPEGXL_MINOR_VERSION >= 10
- // Quality parameter is supported with libjxl v0.10.0 or later
- EXPECT_EQ(max_diff, 0); // Lossless
- #else
- EXPECT_NE(max_diff, 0); // Lossy
- #endif
- }
- #endif // HAVE_JPEGXL
- } // namespace
- } // namespace opencv_test
|