diff --git a/modules/imgcodecs/include/opencv2/imgcodecs.hpp b/modules/imgcodecs/include/opencv2/imgcodecs.hpp index 25c678d89d..6a389fd471 100644 --- a/modules/imgcodecs/include/opencv2/imgcodecs.hpp +++ b/modules/imgcodecs/include/opencv2/imgcodecs.hpp @@ -95,6 +95,7 @@ enum ImwriteFlags { IMWRITE_PNG_BILEVEL = 18, //!< Binary level PNG, 0 or 1, default is 0. IMWRITE_PXM_BINARY = 32, //!< For PPM, PGM, or PBM, it can be a binary format flag, 0 or 1. Default value is 1. IMWRITE_EXR_TYPE = (3 << 4) + 0, /* 48 */ //!< override EXR storage type (FLOAT (FP32) is default) + IMWRITE_EXR_COMPRESSION = (3 << 4) + 1, /* 49 */ //!< override EXR compression type (ZIP_COMPRESSION = 3 is default) IMWRITE_WEBP_QUALITY = 64, //!< For WEBP, it can be a quality from 1 to 100 (the higher is the better). By default (without any parameter) and for quality above 100 the lossless compression is used. IMWRITE_PAM_TUPLETYPE = 128,//!< For PAM, sets the TUPLETYPE field to the corresponding string value that is defined for the format IMWRITE_TIFF_RESUNIT = 256,//!< For TIFF, use to specify which DPI resolution unit to set; see libtiff documentation for valid values @@ -110,6 +111,19 @@ enum ImwriteEXRTypeFlags { IMWRITE_EXR_TYPE_FLOAT = 2 //!< store as FP32 (default) }; +enum ImwriteEXRCompressionFlags { + IMWRITE_EXR_COMPRESSION_NO = 0, //!< no compression + IMWRITE_EXR_COMPRESSION_RLE = 1, //!< run length encoding + IMWRITE_EXR_COMPRESSION_ZIPS = 2, //!< zlib compression, one scan line at a time + IMWRITE_EXR_COMPRESSION_ZIP = 3, //!< zlib compression, in blocks of 16 scan lines + IMWRITE_EXR_COMPRESSION_PIZ = 4, //!< piz-based wavelet compression + IMWRITE_EXR_COMPRESSION_PXR24 = 5, //!< lossy 24-bit float compression + IMWRITE_EXR_COMPRESSION_B44 = 6, //!< lossy 4-by-4 pixel block compression, fixed compression rate + IMWRITE_EXR_COMPRESSION_B44A = 7, //!< lossy 4-by-4 pixel block compression, flat fields are compressed more + IMWRITE_EXR_COMPRESSION_DWAA = 8, //!< lossy DCT based compression, in blocks of 32 scanlines. More efficient for partial buffer access. + IMWRITE_EXR_COMPRESSION_DWAB = 9, //!< lossy DCT based compression, in blocks of 256 scanlines. More efficient space wise and faster to decode full frames than DWAA_COMPRESSION. + }; + //! Imwrite PNG specific flags used to tune the compression algorithm. /** These flags will be modify the way of PNG image compression and will be passed to the underlying zlib processing stage. diff --git a/modules/imgcodecs/src/grfmt_exr.cpp b/modules/imgcodecs/src/grfmt_exr.cpp index 1eceb4f5cd..cb6ac88476 100644 --- a/modules/imgcodecs/src/grfmt_exr.cpp +++ b/modules/imgcodecs/src/grfmt_exr.cpp @@ -589,7 +589,45 @@ bool ExrEncoder::write( const Mat& img, const std::vector& params ) type = FLOAT; break; default: - throw std::runtime_error( "IMWRITE_EXR_TYPE is invalid or not supported" ); + CV_Error(Error::StsBadArg, "IMWRITE_EXR_TYPE is invalid or not supported"); + } + } + if ( params[i] == IMWRITE_EXR_COMPRESSION ) + { + switch ( params[i + 1] ) + { + case IMWRITE_EXR_COMPRESSION_NO: + header.compression() = NO_COMPRESSION; + break; + case IMWRITE_EXR_COMPRESSION_RLE: + header.compression() = RLE_COMPRESSION; + break; + case IMWRITE_EXR_COMPRESSION_ZIPS: + header.compression() = ZIPS_COMPRESSION; + break; + case IMWRITE_EXR_COMPRESSION_ZIP: + header.compression() = ZIP_COMPRESSION; + break; + case IMWRITE_EXR_COMPRESSION_PIZ: + header.compression() = PIZ_COMPRESSION; + break; + case IMWRITE_EXR_COMPRESSION_PXR24: + header.compression() = PXR24_COMPRESSION; + break; + case IMWRITE_EXR_COMPRESSION_B44: + header.compression() = B44_COMPRESSION; + break; + case IMWRITE_EXR_COMPRESSION_B44A: + header.compression() = B44A_COMPRESSION; + break; + case IMWRITE_EXR_COMPRESSION_DWAA: + header.compression() = DWAA_COMPRESSION; + break; + case IMWRITE_EXR_COMPRESSION_DWAB: + header.compression() = DWAB_COMPRESSION; + break; + default: + CV_Error(Error::StsBadArg, "IMWRITE_EXR_COMPRESSION is invalid or not supported"); } } } diff --git a/modules/imgcodecs/test/test_exr.impl.hpp b/modules/imgcodecs/test/test_exr.impl.hpp index 1f78a8f38f..1953719699 100644 --- a/modules/imgcodecs/test/test_exr.impl.hpp +++ b/modules/imgcodecs/test/test_exr.impl.hpp @@ -6,6 +6,17 @@ namespace opencv_test { namespace { +size_t getFileSize(const string& filename) +{ + std::ifstream ifs(filename.c_str(), std::ios::in | std::ios::binary); + if (ifs.is_open()) + { + ifs.seekg(0, std::ios::end); + return ifs.tellg(); + } + return 0; +} + TEST(Imgcodecs_EXR, readWrite_32FC1) { const string root = cvtest::TS::ptr()->get_data_path(); @@ -23,6 +34,8 @@ TEST(Imgcodecs_EXR, readWrite_32FC1) ASSERT_EQ(CV_32FC1,img.type()); ASSERT_TRUE(cv::imwrite(filenameOutput, img)); + // Check generated file size to ensure that it's compressed with proper options + ASSERT_EQ(396u, getFileSize(filenameOutput)); const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED); ASSERT_EQ(img2.type(), img.type()); ASSERT_EQ(img2.size(), img.size()); @@ -113,5 +126,29 @@ TEST(Imgcodecs_EXR, readWrite_32FC3_half) EXPECT_EQ(0, remove(filenameOutput.c_str())); } +TEST(Imgcodecs_EXR, readWrite_32FC1_PIZ) +{ + const string root = cvtest::TS::ptr()->get_data_path(); + const string filenameInput = root + "readwrite/test32FC1.exr"; + const string filenameOutput = cv::tempfile(".exr"); + + + const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED); + ASSERT_FALSE(img.empty()); + ASSERT_EQ(CV_32FC1, img.type()); + + std::vector params; + params.push_back(IMWRITE_EXR_COMPRESSION); + params.push_back(IMWRITE_EXR_COMPRESSION_PIZ); + ASSERT_TRUE(cv::imwrite(filenameOutput, img, params)); + // Check generated file size to ensure that it's compressed with proper options + ASSERT_EQ(849u, getFileSize(filenameOutput)); + const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED); + ASSERT_EQ(img2.type(), img.type()); + ASSERT_EQ(img2.size(), img.size()); + EXPECT_LE(cvtest::norm(img, img2, NORM_INF | NORM_RELATIVE), 1e-3); + EXPECT_EQ(0, remove(filenameOutput.c_str())); +} + }} // namespace