Merge pull request #19540 from asmorkalov:as/openexr_comression_options

OpenEXR compression options

* Adding possibility to select the compression type for the OpenEXR format.

There are compression modes other than the default that are more suited for certain data. Mainly grainy/noisy data.

* Code review fixes.

Co-authored-by: Daniel Rydstrom <daniel.rydstrom@sick.se>
This commit is contained in:
Alexander Smorkalov 2021-02-20 19:28:08 +03:00 committed by GitHub
parent ca7518c13b
commit c131c12fd7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 90 additions and 1 deletions

View File

@ -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.

View File

@ -589,7 +589,45 @@ bool ExrEncoder::write( const Mat& img, const std::vector<int>& 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");
}
}
}

View File

@ -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<int> 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