Merge pull request #19655 from raaldrid:EXR_rw_alpha_support_16115

pull/19686/head^2
Alexander Alekhin 4 years ago committed by GitHub
commit a1e2c4f338
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 180
      modules/imgcodecs/src/grfmt_exr.cpp
  2. 4
      modules/imgcodecs/src/grfmt_exr.hpp
  3. 158
      modules/imgcodecs/test/test_exr.impl.hpp

@ -84,12 +84,13 @@ ExrDecoder::ExrDecoder()
{ {
m_signature = "\x76\x2f\x31\x01"; m_signature = "\x76\x2f\x31\x01";
m_file = 0; m_file = 0;
m_red = m_green = m_blue = 0; m_red = m_green = m_blue = m_alpha = 0;
m_type = ((Imf::PixelType)0); m_type = ((Imf::PixelType)0);
m_iscolor = false; m_iscolor = false;
m_bit_depth = 0; m_bit_depth = 0;
m_isfloat = false; m_isfloat = false;
m_ischroma = false; m_ischroma = false;
m_hasalpha = false;
m_native_depth = false; m_native_depth = false;
} }
@ -113,7 +114,7 @@ void ExrDecoder::close()
int ExrDecoder::type() const int ExrDecoder::type() const
{ {
return CV_MAKETYPE((m_isfloat ? CV_32F : CV_32S), m_iscolor ? 3 : 1); return CV_MAKETYPE((m_isfloat ? CV_32F : CV_32S), ((m_iscolor && m_hasalpha) ? 4 : m_iscolor ? 3 : m_hasalpha ? 2 : 1));
} }
@ -141,6 +142,11 @@ bool ExrDecoder::readHeader()
m_red = channels.findChannel( "R" ); m_red = channels.findChannel( "R" );
m_green = channels.findChannel( "G" ); m_green = channels.findChannel( "G" );
m_blue = channels.findChannel( "B" ); m_blue = channels.findChannel( "B" );
m_alpha = channels.findChannel( "A" );
if( m_alpha ) // alpha channel supported in RGB, Y, and YC scenarios
m_hasalpha = true;
if( m_red || m_green || m_blue ) if( m_red || m_green || m_blue )
{ {
m_iscolor = true; m_iscolor = true;
@ -178,7 +184,8 @@ bool ExrDecoder::readHeader()
bool ExrDecoder::readData( Mat& img ) bool ExrDecoder::readData( Mat& img )
{ {
m_native_depth = CV_MAT_DEPTH(type()) == img.depth(); m_native_depth = CV_MAT_DEPTH(type()) == img.depth();
bool color = img.channels() > 1; bool color = img.channels() > 2; // output mat has 3+ channels; Y or YA are the 1 and 2 channel scenario
bool alphasupported = ( img.channels() % 2 == 0 ); // even number of channels indicates alpha
int channels = 0; int channels = 0;
uchar* data = img.ptr(); uchar* data = img.ptr();
size_t step = img.step; size_t step = img.step;
@ -187,18 +194,22 @@ bool ExrDecoder::readData( Mat& img )
bool rgbtogray = ( !m_ischroma && m_iscolor && !color ); bool rgbtogray = ( !m_ischroma && m_iscolor && !color );
bool result = true; bool result = true;
FrameBuffer frame; FrameBuffer frame;
int xsample[3] = {1, 1, 1}; const int defaultchannels = 3;
int xsample[defaultchannels] = {1, 1, 1};
char *buffer; char *buffer;
size_t xstep = 0; CV_Assert(m_type == FLOAT);
const size_t floatsize = sizeof(float);
size_t xstep = m_native_depth ? floatsize : 1; // 4 bytes if native depth (FLOAT), otherwise converting to 1 byte U8 depth
size_t ystep = 0; size_t ystep = 0;
const int channelstoread = ( (m_iscolor && alphasupported) ? 4 :
xstep = m_native_depth ? 4 : 1; ( (m_iscolor && !m_ischroma) || color) ? 3 : alphasupported ? 2 : 1 ); // number of channels to read may exceed channels in output img
size_t xStride = floatsize * channelstoread;
AutoBuffer<char> copy_buffer; AutoBuffer<char> copy_buffer;
if( !justcopy ) if( !justcopy )
{ {
copy_buffer.allocate(sizeof(float) * m_width * 3); copy_buffer.allocate(floatsize * m_width * defaultchannels);
buffer = copy_buffer.data(); buffer = copy_buffer.data();
ystep = 0; ystep = 0;
} }
@ -215,49 +226,49 @@ bool ExrDecoder::readData( Mat& img )
if( m_blue ) if( m_blue )
{ {
frame.insert( "BY", Slice( m_type, frame.insert( "BY", Slice( m_type,
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep, buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep,
12, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 )); xStride, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 ));
xsample[0] = m_blue->ySampling; xsample[0] = m_blue->xSampling;
} }
else else
{ {
frame.insert( "BY", Slice( m_type, frame.insert( "BY", Slice( m_type,
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep, buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep,
12, ystep, 1, 1, 0.0 )); xStride, ystep, 1, 1, 0.0 ));
} }
if( m_green ) if( m_green )
{ {
frame.insert( "Y", Slice( m_type, frame.insert( "Y", Slice( m_type,
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4, buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep + floatsize,
12, ystep, m_green->xSampling, m_green->ySampling, 0.0 )); xStride, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
xsample[1] = m_green->ySampling; xsample[1] = m_green->xSampling;
} }
else else
{ {
frame.insert( "Y", Slice( m_type, frame.insert( "Y", Slice( m_type,
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4, buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep + floatsize,
12, ystep, 1, 1, 0.0 )); xStride, ystep, 1, 1, 0.0 ));
} }
if( m_red ) if( m_red )
{ {
frame.insert( "RY", Slice( m_type, frame.insert( "RY", Slice( m_type,
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8, buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep + (floatsize * 2),
12, ystep, m_red->xSampling, m_red->ySampling, 0.0 )); xStride, ystep, m_red->xSampling, m_red->ySampling, 0.0 ));
xsample[2] = m_red->ySampling; xsample[2] = m_red->xSampling;
} }
else else
{ {
frame.insert( "RY", Slice( m_type, frame.insert( "RY", Slice( m_type,
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8, buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep + (floatsize * 2),
12, ystep, 1, 1, 0.0 )); xStride, ystep, 1, 1, 0.0 ));
} }
} }
else else
{ {
frame.insert( "Y", Slice( m_type, frame.insert( "Y", Slice( m_type,
buffer - m_datawindow.min.x * 4 - m_datawindow.min.y * ystep, buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep,
4, ystep, m_green->xSampling, m_green->ySampling, 0.0 )); xStride, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
xsample[0] = m_green->ySampling; xsample[0] = m_green->xSampling;
} }
} }
else else
@ -265,67 +276,85 @@ bool ExrDecoder::readData( Mat& img )
if( m_blue ) if( m_blue )
{ {
frame.insert( "B", Slice( m_type, frame.insert( "B", Slice( m_type,
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep, buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep,
12, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 )); xStride, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 ));
xsample[0] = m_blue->ySampling; xsample[0] = m_blue->xSampling;
} }
else else
{ {
frame.insert( "B", Slice( m_type, frame.insert( "B", Slice( m_type,
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep, buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep,
12, ystep, 1, 1, 0.0 )); xStride, ystep, 1, 1, 0.0 ));
} }
if( m_green ) if( m_green )
{ {
frame.insert( "G", Slice( m_type, frame.insert( "G", Slice( m_type,
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4, buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep + floatsize,
12, ystep, m_green->xSampling, m_green->ySampling, 0.0 )); xStride, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
xsample[1] = m_green->ySampling; xsample[1] = m_green->xSampling;
} }
else else
{ {
frame.insert( "G", Slice( m_type, frame.insert( "G", Slice( m_type,
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4, buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep + floatsize,
12, ystep, 1, 1, 0.0 )); xStride, ystep, 1, 1, 0.0 ));
} }
if( m_red ) if( m_red )
{ {
frame.insert( "R", Slice( m_type, frame.insert( "R", Slice( m_type,
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8, buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep + (floatsize * 2),
12, ystep, m_red->xSampling, m_red->ySampling, 0.0 )); xStride, ystep, m_red->xSampling, m_red->ySampling, 0.0 ));
xsample[2] = m_red->ySampling; xsample[2] = m_red->xSampling;
} }
else else
{ {
frame.insert( "R", Slice( m_type, frame.insert( "R", Slice( m_type,
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8, buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep + (floatsize * 2),
12, ystep, 1, 1, 0.0 )); xStride, ystep, 1, 1, 0.0 ));
}
} }
if( justcopy && m_hasalpha && alphasupported )
{ // alpha preserved only in justcopy scenario where alpha is desired (alphasupported)
// and present in original file (m_hasalpha)
CV_Assert(channelstoread == img.channels());
int offset = (channelstoread - 1) * floatsize;
frame.insert( "A", Slice( m_type,
buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep + offset,
xStride, ystep, m_alpha->xSampling, m_alpha->ySampling, 0.0 ));
} }
for (FrameBuffer::Iterator it = frame.begin(); it != frame.end(); it++) { for (FrameBuffer::Iterator it = frame.begin(); it != frame.end(); it++) {
channels++; channels++;
} }
CV_Assert(channels == channelstoread);
if( (channels != channelstoread) || (!justcopy && channels > defaultchannels) )
{ // safety checking what ought to be true here
close();
return false;
}
m_file->setFrameBuffer( frame ); m_file->setFrameBuffer( frame );
if( justcopy ) if( justcopy )
{ {
m_file->readPixels( m_datawindow.min.y, m_datawindow.max.y ); m_file->readPixels( m_datawindow.min.y, m_datawindow.max.y );
if( color ) if( m_iscolor )
{ {
if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) ) if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )
UpSample( data, 3, step / xstep, xsample[0], m_blue->ySampling ); UpSample( data, channelstoread, step / xstep, m_blue->xSampling, m_blue->ySampling );
if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) ) if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
UpSample( data + xstep, 3, step / xstep, xsample[1], m_green->ySampling ); UpSample( data + xstep, channelstoread, step / xstep, m_green->xSampling, m_green->ySampling );
if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) ) if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
UpSample( data + 2 * xstep, 3, step / xstep, xsample[2], m_red->ySampling ); UpSample( data + 2 * xstep, channelstoread, step / xstep, m_red->xSampling, m_red->ySampling );
} }
else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) ) else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
UpSample( data, 1, step / xstep, xsample[0], m_green->ySampling ); UpSample( data, channelstoread, step / xstep, m_green->xSampling, m_green->ySampling );
if( chromatorgb ) if( chromatorgb )
ChromaToBGR( (float *)data, m_height, step / xstep ); ChromaToBGR( (float *)data, m_height, channelstoread, step / xstep );
} }
else else
{ {
@ -347,7 +376,7 @@ bool ExrDecoder::readData( Mat& img )
else else
{ {
if( chromatorgb ) if( chromatorgb )
ChromaToBGR( (float *)buffer, 1, step ); ChromaToBGR( (float *)buffer, 1, defaultchannels, step );
if( m_type == FLOAT ) if( m_type == FLOAT )
{ {
@ -372,11 +401,11 @@ bool ExrDecoder::readData( Mat& img )
if( color ) if( color )
{ {
if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) ) if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )
UpSampleY( data, 3, step / xstep, m_blue->ySampling ); UpSampleY( data, defaultchannels, step / xstep, m_blue->ySampling );
if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) ) if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
UpSampleY( data + xstep, 3, step / xstep, m_green->ySampling ); UpSampleY( data + xstep, defaultchannels, step / xstep, m_green->ySampling );
if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) ) if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
UpSampleY( data + 2 * xstep, 3, step / xstep, m_red->ySampling ); UpSampleY( data + 2 * xstep, defaultchannels, step / xstep, m_red->ySampling );
} }
else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) ) else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
UpSampleY( data, 1, step / xstep, m_green->ySampling ); UpSampleY( data, 1, step / xstep, m_green->ySampling );
@ -457,7 +486,7 @@ void ExrDecoder::UpSampleY( uchar *data, int xstep, int ystep, int ysample )
/** /**
// algorithm from ImfRgbaYca.cpp // algorithm from ImfRgbaYca.cpp
*/ */
void ExrDecoder::ChromaToBGR( float *data, int numlines, int step ) void ExrDecoder::ChromaToBGR( float *data, int numlines, int xstep, int ystep )
{ {
for( int y = 0; y < numlines; y++ ) for( int y = 0; y < numlines; y++ )
{ {
@ -466,15 +495,15 @@ void ExrDecoder::ChromaToBGR( float *data, int numlines, int step )
double b, Y, r; double b, Y, r;
if( m_type == FLOAT ) if( m_type == FLOAT )
{ {
b = data[y * step + x * 3]; b = data[y * ystep + x * xstep];
Y = data[y * step + x * 3 + 1]; Y = data[y * ystep + x * xstep + 1];
r = data[y * step + x * 3 + 2]; r = data[y * ystep + x * xstep + 2];
} }
else else
{ {
b = ((unsigned *)data)[y * step + x * 3]; b = ((unsigned *)data)[y * ystep + x * xstep];
Y = ((unsigned *)data)[y * step + x * 3 + 1]; Y = ((unsigned *)data)[y * ystep + x * xstep + 1];
r = ((unsigned *)data)[y * step + x * 3 + 2]; r = ((unsigned *)data)[y * ystep + x * xstep + 2];
} }
r = (r + 1) * Y; r = (r + 1) * Y;
b = (b + 1) * Y; b = (b + 1) * Y;
@ -482,18 +511,18 @@ void ExrDecoder::ChromaToBGR( float *data, int numlines, int step )
if( m_type == FLOAT ) if( m_type == FLOAT )
{ {
data[y * step + x * 3] = (float)b; data[y * ystep + x * xstep] = (float)b;
data[y * step + x * 3 + 1] = (float)Y; data[y * ystep + x * xstep + 1] = (float)Y;
data[y * step + x * 3 + 2] = (float)r; data[y * ystep + x * xstep + 2] = (float)r;
} }
else else
{ {
int t = cvRound(b); int t = cvRound(b);
((unsigned *)data)[y * step + x * 3 + 0] = (unsigned)MAX(t, 0); ((unsigned *)data)[y * ystep + x * xstep + 0] = (unsigned)MAX(t, 0);
t = cvRound(Y); t = cvRound(Y);
((unsigned *)data)[y * step + x * 3 + 1] = (unsigned)MAX(t, 0); ((unsigned *)data)[y * ystep + x * xstep + 1] = (unsigned)MAX(t, 0);
t = cvRound(r); t = cvRound(r);
((unsigned *)data)[y * step + x * 3 + 2] = (unsigned)MAX(t, 0); ((unsigned *)data)[y * ystep + x * xstep + 2] = (unsigned)MAX(t, 0);
} }
} }
} }
@ -571,7 +600,6 @@ bool ExrEncoder::write( const Mat& img, const std::vector<int>& params )
int depth = img.depth(); int depth = img.depth();
CV_Assert( depth == CV_32F ); CV_Assert( depth == CV_32F );
int channels = img.channels(); int channels = img.channels();
CV_Assert( channels == 3 || channels == 1 );
bool result = false; bool result = false;
Header header( width, height ); Header header( width, height );
Imf::PixelType type = FLOAT; Imf::PixelType type = FLOAT;
@ -594,7 +622,7 @@ bool ExrEncoder::write( const Mat& img, const std::vector<int>& params )
} }
} }
if( channels == 3 ) if( channels == 3 || channels == 4 )
{ {
header.channels().insert( "R", Channel( type ) ); header.channels().insert( "R", Channel( type ) );
header.channels().insert( "G", Channel( type ) ); header.channels().insert( "G", Channel( type ) );
@ -607,6 +635,11 @@ bool ExrEncoder::write( const Mat& img, const std::vector<int>& params )
//printf("gray\n"); //printf("gray\n");
} }
if( channels % 2 == 0 )
{ // even number of channels indicates Alpha
header.channels().insert( "A", Channel( type ) );
}
OutputFile file( m_filename.c_str(), header ); OutputFile file( m_filename.c_str(), header );
FrameBuffer frame; FrameBuffer frame;
@ -629,14 +662,19 @@ bool ExrEncoder::write( const Mat& img, const std::vector<int>& params )
size = 4; size = 4;
} }
if( channels == 3 ) if( channels == 3 || channels == 4 )
{ {
frame.insert( "B", Slice( type, buffer, size * 3, bufferstep )); frame.insert( "B", Slice( type, buffer, size * channels, bufferstep ));
frame.insert( "G", Slice( type, buffer + size, size * 3, bufferstep )); frame.insert( "G", Slice( type, buffer + size, size * channels, bufferstep ));
frame.insert( "R", Slice( type, buffer + size * 2, size * 3, bufferstep )); frame.insert( "R", Slice( type, buffer + size * 2, size * channels, bufferstep ));
} }
else else
frame.insert( "Y", Slice( type, buffer, size, bufferstep )); frame.insert( "Y", Slice( type, buffer, size * channels, bufferstep ));
if( channels % 2 == 0 )
{ // even channel count indicates Alpha channel
frame.insert( "A", Slice( type, buffer + size * (channels - 1), size * channels, bufferstep ));
}
file.setFrameBuffer( frame ); file.setFrameBuffer( frame );

@ -81,7 +81,7 @@ protected:
void UpSample( uchar *data, int xstep, int ystep, int xsample, int ysample ); void UpSample( uchar *data, int xstep, int ystep, int xsample, int ysample );
void UpSampleX( float *data, int xstep, int xsample ); void UpSampleX( float *data, int xstep, int xsample );
void UpSampleY( uchar *data, int xstep, int ystep, int ysample ); void UpSampleY( uchar *data, int xstep, int ystep, int ysample );
void ChromaToBGR( float *data, int numlines, int step ); void ChromaToBGR( float *data, int numlines, int xstep, int ystep );
void RGBToGray( float *in, float *out ); void RGBToGray( float *in, float *out );
InputFile *m_file; InputFile *m_file;
@ -91,11 +91,13 @@ protected:
const Channel *m_red; const Channel *m_red;
const Channel *m_green; const Channel *m_green;
const Channel *m_blue; const Channel *m_blue;
const Channel *m_alpha;
Chromaticities m_chroma; Chromaticities m_chroma;
int m_bit_depth; int m_bit_depth;
bool m_native_depth; bool m_native_depth;
bool m_iscolor; bool m_iscolor;
bool m_isfloat; bool m_isfloat;
bool m_hasalpha;
private: private:
ExrDecoder(const ExrDecoder &); // copy disabled ExrDecoder(const ExrDecoder &); // copy disabled

@ -7,7 +7,7 @@
namespace opencv_test { namespace { namespace opencv_test { namespace {
TEST(Imgcodecs_EXR, readWrite_32FC1) TEST(Imgcodecs_EXR, readWrite_32FC1)
{ { // Y channels
const string root = cvtest::TS::ptr()->get_data_path(); const string root = cvtest::TS::ptr()->get_data_path();
const string filenameInput = root + "readwrite/test32FC1.exr"; const string filenameInput = root + "readwrite/test32FC1.exr";
const string filenameOutput = cv::tempfile(".exr"); const string filenameOutput = cv::tempfile(".exr");
@ -31,7 +31,7 @@ TEST(Imgcodecs_EXR, readWrite_32FC1)
} }
TEST(Imgcodecs_EXR, readWrite_32FC3) TEST(Imgcodecs_EXR, readWrite_32FC3)
{ { // RGB channels
const string root = cvtest::TS::ptr()->get_data_path(); const string root = cvtest::TS::ptr()->get_data_path();
const string filenameInput = root + "readwrite/test32FC3.exr"; const string filenameInput = root + "readwrite/test32FC3.exr";
const string filenameOutput = cv::tempfile(".exr"); const string filenameOutput = cv::tempfile(".exr");
@ -113,5 +113,159 @@ TEST(Imgcodecs_EXR, readWrite_32FC3_half)
EXPECT_EQ(0, remove(filenameOutput.c_str())); EXPECT_EQ(0, remove(filenameOutput.c_str()));
} }
// Note: YC to GRAYSCALE (IMREAD_GRAYSCALE | IMREAD_ANYDEPTH)
// outputs a black image,
// as does Y to RGB (IMREAD_COLOR | IMREAD_ANYDEPTH).
// This behavoir predates adding EXR alpha support issue
// 16115.
TEST(Imgcodecs_EXR, read_YA_ignore_alpha)
{
const string root = cvtest::TS::ptr()->get_data_path();
const string filenameInput = root + "readwrite/test_YA.exr";
const Mat img = cv::imread(filenameInput, IMREAD_GRAYSCALE | IMREAD_ANYDEPTH);
ASSERT_FALSE(img.empty());
ASSERT_EQ(CV_32FC1, img.type());
// Writing Y covered by test 32FC1
}
TEST(Imgcodecs_EXR, read_YA_unchanged)
{
const string root = cvtest::TS::ptr()->get_data_path();
const string filenameInput = root + "readwrite/test_YA.exr";
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
ASSERT_FALSE(img.empty());
ASSERT_EQ(CV_32FC2, img.type());
// Cannot test writing, 2 channel writing not suppported by loadsave
}
TEST(Imgcodecs_EXR, read_YC_changeDepth)
{
const string root = cvtest::TS::ptr()->get_data_path();
const string filenameInput = root + "readwrite/test_YRYBY.exr";
const Mat img = cv::imread(filenameInput, IMREAD_COLOR);
ASSERT_FALSE(img.empty());
ASSERT_EQ(CV_8UC3, img.type());
// Cannot test writing, EXR encoder doesn't support 8U depth
}
TEST(Imgcodecs_EXR, readwrite_YCA_ignore_alpha)
{
const string root = cvtest::TS::ptr()->get_data_path();
const string filenameInput = root + "readwrite/test_YRYBYA.exr";
const string filenameOutput = cv::tempfile(".exr");
const Mat img = cv::imread(filenameInput, IMREAD_COLOR | IMREAD_ANYDEPTH);
ASSERT_FALSE(img.empty());
ASSERT_EQ(CV_32FC3, img.type());
ASSERT_TRUE(cv::imwrite(filenameOutput, img));
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()));
}
TEST(Imgcodecs_EXR, read_YC_unchanged)
{
const string root = cvtest::TS::ptr()->get_data_path();
const string filenameInput = root + "readwrite/test_YRYBY.exr";
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
ASSERT_FALSE(img.empty());
ASSERT_EQ(CV_32FC3, img.type());
// Writing YC covered by test readwrite_YCA_ignore_alpha
}
TEST(Imgcodecs_EXR, readwrite_YCA_unchanged)
{
const string root = cvtest::TS::ptr()->get_data_path();
const string filenameInput = root + "readwrite/test_YRYBYA.exr";
const string filenameOutput = cv::tempfile(".exr");
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
ASSERT_FALSE(img.empty());
ASSERT_EQ(CV_32FC4, img.type());
ASSERT_TRUE(cv::imwrite(filenameOutput, img));
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()));
}
TEST(Imgcodecs_EXR, readwrite_RGBA_togreyscale)
{
const string root = cvtest::TS::ptr()->get_data_path();
const string filenameInput = root + "readwrite/test_GeneratedRGBA.exr";
const string filenameOutput = cv::tempfile(".exr");
const Mat img = cv::imread(filenameInput, IMREAD_GRAYSCALE | IMREAD_ANYDEPTH);
ASSERT_FALSE(img.empty());
ASSERT_EQ(CV_32FC1, img.type());
ASSERT_TRUE(cv::imwrite(filenameOutput, img));
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()));
}
TEST(Imgcodecs_EXR, read_RGBA_ignore_alpha)
{
const string root = cvtest::TS::ptr()->get_data_path();
const string filenameInput = root + "readwrite/test_GeneratedRGBA.exr";
const Mat img = cv::imread(filenameInput, IMREAD_COLOR | IMREAD_ANYDEPTH);
ASSERT_FALSE(img.empty());
ASSERT_EQ(CV_32FC3, img.type());
// Writing RGB covered by test 32FC3
}
TEST(Imgcodecs_EXR, read_RGBA_unchanged)
{
const string root = cvtest::TS::ptr()->get_data_path();
const string filenameInput = root + "readwrite/test_GeneratedRGBA.exr";
const string filenameOutput = cv::tempfile(".exr");
#ifndef GENERATE_DATA
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
#else
const Size sz(64, 32);
Mat img(sz, CV_32FC4, Scalar(0.5, 0.1, 1, 1));
img(Rect(10, 5, sz.width - 30, sz.height - 20)).setTo(Scalar(1, 0, 0, 1));
img(Rect(10, 20, sz.width - 30, sz.height - 20)).setTo(Scalar(1, 1, 0, 0));
ASSERT_TRUE(cv::imwrite(filenameInput, img));
#endif
ASSERT_FALSE(img.empty());
ASSERT_EQ(CV_32FC4, img.type());
ASSERT_TRUE(cv::imwrite(filenameOutput, img));
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 }} // namespace

Loading…
Cancel
Save