mirror of
https://github.com/opencv/opencv.git
synced 2024-11-28 13:10:12 +08:00
Merge pull request #10283 from zhijackchen:exr_export
* Fix issue #10114 Convert table change From: CV_8U -> HALF CV_8S -> HALF CV_16U -> UINT CV_16S -> UINT CV_32S -> UINT CV_32F -> FLOAT To: CV_8U -> HALF CV_8S -> HALF CV_16U -> UINT CV_16S -> FLOAT CV_32S -> FLOAT loss precision CV_32F -> FLOAT Signed integer can't be presented well with UINT. Even adjust bias, CV16S and CV32S will be confused when load from exr file. Also fix CV_8S negative value incorrect bug * EXR import and export imread() from EXR returns CV_32F only imwrite() accepts CV_32 cv::Mat only and stores FLOAT images by default. Add imwrite() flag to store in HALF format. * fix compiling error * clean up * fix EXR import issues
This commit is contained in:
parent
18ff806d5b
commit
6df8ac0342
@ -89,10 +89,17 @@ enum ImwriteFlags {
|
||||
IMWRITE_PNG_STRATEGY = 17, //!< One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_RLE.
|
||||
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_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
|
||||
};
|
||||
|
||||
enum ImwriteEXRTypeFlags {
|
||||
/*IMWRITE_EXR_TYPE_UNIT = 0, //!< not supported */
|
||||
IMWRITE_EXR_TYPE_HALF = 1, //!< store as HALF (FP16)
|
||||
IMWRITE_EXR_TYPE_FLOAT = 2 //!< store as FP32 (default)
|
||||
};
|
||||
|
||||
//! 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.
|
||||
|
||||
|
@ -94,6 +94,7 @@ enum
|
||||
CV_IMWRITE_PNG_STRATEGY_RLE =3,
|
||||
CV_IMWRITE_PNG_STRATEGY_FIXED =4,
|
||||
CV_IMWRITE_PXM_BINARY =32,
|
||||
CV_IMWRITE_EXR_TYPE = 48,
|
||||
CV_IMWRITE_WEBP_QUALITY =64,
|
||||
CV_IMWRITE_PAM_TUPLETYPE = 128,
|
||||
CV_IMWRITE_PAM_FORMAT_NULL = 0,
|
||||
|
@ -52,6 +52,10 @@
|
||||
# pragma GCC diagnostic ignored "-Wshadow"
|
||||
#endif
|
||||
|
||||
/// C++ Standard Libraries
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <ImfHeader.h>
|
||||
#include <ImfInputFile.h>
|
||||
#include <ImfOutputFile.h>
|
||||
@ -160,26 +164,8 @@ bool ExrDecoder::readHeader()
|
||||
|
||||
if( result )
|
||||
{
|
||||
int uintcnt = 0;
|
||||
int chcnt = 0;
|
||||
if( m_red )
|
||||
{
|
||||
chcnt++;
|
||||
uintcnt += ( m_red->type == UINT );
|
||||
}
|
||||
if( m_green )
|
||||
{
|
||||
chcnt++;
|
||||
uintcnt += ( m_green->type == UINT );
|
||||
}
|
||||
if( m_blue )
|
||||
{
|
||||
chcnt++;
|
||||
uintcnt += ( m_blue->type == UINT );
|
||||
}
|
||||
m_type = (chcnt == uintcnt) ? UINT : FLOAT;
|
||||
|
||||
m_isfloat = (m_type == FLOAT);
|
||||
m_type = FLOAT;
|
||||
m_isfloat = ( m_type == FLOAT );
|
||||
}
|
||||
|
||||
if( !result )
|
||||
@ -193,12 +179,12 @@ bool ExrDecoder::readData( Mat& img )
|
||||
{
|
||||
m_native_depth = CV_MAT_DEPTH(type()) == img.depth();
|
||||
bool color = img.channels() > 1;
|
||||
|
||||
int channels = 0;
|
||||
uchar* data = img.ptr();
|
||||
size_t step = img.step;
|
||||
bool justcopy = m_native_depth;
|
||||
bool chromatorgb = false;
|
||||
bool rgbtogray = false;
|
||||
bool justcopy = ( m_native_depth && (color == m_iscolor) );
|
||||
bool chromatorgb = ( m_ischroma && color );
|
||||
bool rgbtogray = ( !m_ischroma && m_iscolor && !color );
|
||||
bool result = true;
|
||||
FrameBuffer frame;
|
||||
int xsample[3] = {1, 1, 1};
|
||||
@ -210,7 +196,7 @@ bool ExrDecoder::readData( Mat& img )
|
||||
|
||||
AutoBuffer<char> copy_buffer;
|
||||
|
||||
if( !m_native_depth || (!color && m_iscolor ))
|
||||
if( !justcopy )
|
||||
{
|
||||
copy_buffer.allocate(sizeof(float) * m_width * 3);
|
||||
buffer = copy_buffer;
|
||||
@ -226,45 +212,44 @@ bool ExrDecoder::readData( Mat& img )
|
||||
{
|
||||
if( color )
|
||||
{
|
||||
if( m_iscolor )
|
||||
if( m_blue )
|
||||
{
|
||||
if( m_blue )
|
||||
{
|
||||
frame.insert( "BY", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,
|
||||
12, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 ));
|
||||
xsample[0] = m_blue->ySampling;
|
||||
}
|
||||
if( m_green )
|
||||
{
|
||||
frame.insert( "Y", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,
|
||||
12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
|
||||
xsample[1] = m_green->ySampling;
|
||||
}
|
||||
if( m_red )
|
||||
{
|
||||
frame.insert( "RY", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,
|
||||
12, ystep, m_red->xSampling, m_red->ySampling, 0.0 ));
|
||||
xsample[2] = m_red->ySampling;
|
||||
}
|
||||
chromatorgb = true;
|
||||
frame.insert( "BY", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,
|
||||
12, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 ));
|
||||
xsample[0] = m_blue->ySampling;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.insert( "BY", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,
|
||||
12, ystep, 1, 1, 0.0 ));
|
||||
}
|
||||
if( m_green )
|
||||
{
|
||||
frame.insert( "Y", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,
|
||||
12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
|
||||
xsample[1] = m_green->ySampling;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.insert( "Y", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,
|
||||
12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
|
||||
frame.insert( "Y", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,
|
||||
12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
|
||||
frame.insert( "Y", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,
|
||||
12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
|
||||
xsample[0] = m_green->ySampling;
|
||||
xsample[1] = m_green->ySampling;
|
||||
xsample[2] = m_green->ySampling;
|
||||
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,
|
||||
12, ystep, 1, 1, 0.0 ));
|
||||
}
|
||||
if( m_red )
|
||||
{
|
||||
frame.insert( "RY", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,
|
||||
12, ystep, m_red->xSampling, m_red->ySampling, 0.0 ));
|
||||
xsample[2] = m_red->ySampling;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.insert( "RY", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,
|
||||
12, ystep, 1, 1, 0.0 ));
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -284,6 +269,12 @@ bool ExrDecoder::readData( Mat& img )
|
||||
12, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 ));
|
||||
xsample[0] = m_blue->ySampling;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.insert( "B", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,
|
||||
12, ystep, 1, 1, 0.0 ));
|
||||
}
|
||||
if( m_green )
|
||||
{
|
||||
frame.insert( "G", Slice( m_type,
|
||||
@ -291,6 +282,12 @@ bool ExrDecoder::readData( Mat& img )
|
||||
12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
|
||||
xsample[1] = m_green->ySampling;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.insert( "G", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,
|
||||
12, ystep, 1, 1, 0.0 ));
|
||||
}
|
||||
if( m_red )
|
||||
{
|
||||
frame.insert( "R", Slice( m_type,
|
||||
@ -298,13 +295,18 @@ bool ExrDecoder::readData( Mat& img )
|
||||
12, ystep, m_red->xSampling, m_red->ySampling, 0.0 ));
|
||||
xsample[2] = m_red->ySampling;
|
||||
}
|
||||
if(color == 0)
|
||||
else
|
||||
{
|
||||
rgbtogray = true;
|
||||
justcopy = false;
|
||||
frame.insert( "R", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,
|
||||
12, ystep, 1, 1, 0.0 ));
|
||||
}
|
||||
}
|
||||
|
||||
for (FrameBuffer::Iterator it = frame.begin(); it != frame.end(); it++) {
|
||||
channels++;
|
||||
}
|
||||
|
||||
m_file->setFrameBuffer( frame );
|
||||
if( justcopy )
|
||||
{
|
||||
@ -321,6 +323,9 @@ bool ExrDecoder::readData( Mat& img )
|
||||
}
|
||||
else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
|
||||
UpSample( data, 1, step / xstep, xsample[0], m_green->ySampling );
|
||||
|
||||
if( chromatorgb )
|
||||
ChromaToBGR( (float *)data, m_height, step / xstep );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -330,41 +335,32 @@ bool ExrDecoder::readData( Mat& img )
|
||||
{
|
||||
m_file->readPixels( y, y );
|
||||
|
||||
for( int i = 0; i < channels; i++ )
|
||||
{
|
||||
if( xsample[i] != 1 )
|
||||
UpSampleX( (float *)buffer + i, channels, xsample[i] );
|
||||
}
|
||||
if( rgbtogray )
|
||||
{
|
||||
if( xsample[0] != 1 )
|
||||
UpSampleX( (float *)buffer, 3, xsample[0] );
|
||||
if( xsample[1] != 1 )
|
||||
UpSampleX( (float *)buffer + 4, 3, xsample[1] );
|
||||
if( xsample[2] != 1 )
|
||||
UpSampleX( (float *)buffer + 8, 3, xsample[2] );
|
||||
|
||||
RGBToGray( (float *)buffer, (float *)out );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( xsample[0] != 1 )
|
||||
UpSampleX( (float *)buffer, 3, xsample[0] );
|
||||
if( xsample[1] != 1 )
|
||||
UpSampleX( (float *)(buffer + 4), 3, xsample[1] );
|
||||
if( xsample[2] != 1 )
|
||||
UpSampleX( (float *)(buffer + 8), 3, xsample[2] );
|
||||
|
||||
if( chromatorgb )
|
||||
ChromaToBGR( (float *)buffer, 1, step );
|
||||
|
||||
if( m_type == FLOAT )
|
||||
{
|
||||
float *fi = (float *)buffer;
|
||||
for( x = 0; x < m_width * 3; x++)
|
||||
for( x = 0; x < m_width * img.channels(); x++)
|
||||
{
|
||||
out[x] = cv::saturate_cast<uchar>(fi[x]*5);
|
||||
out[x] = cv::saturate_cast<uchar>(fi[x]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned *ui = (unsigned *)buffer;
|
||||
for( x = 0; x < m_width * 3; x++)
|
||||
for( x = 0; x < m_width * img.channels(); x++)
|
||||
{
|
||||
out[x] = cv::saturate_cast<uchar>(ui[x]);
|
||||
}
|
||||
@ -386,9 +382,6 @@ bool ExrDecoder::readData( Mat& img )
|
||||
UpSampleY( data, 1, step / xstep, m_green->ySampling );
|
||||
}
|
||||
|
||||
if( chromatorgb )
|
||||
ChromaToBGR( (float *)data, m_height, step / xstep );
|
||||
|
||||
close();
|
||||
|
||||
return result;
|
||||
@ -471,13 +464,7 @@ void ExrDecoder::ChromaToBGR( float *data, int numlines, int step )
|
||||
for( int x = 0; x < m_width; x++ )
|
||||
{
|
||||
double b, Y, r;
|
||||
if( !m_native_depth )
|
||||
{
|
||||
b = ((uchar *)data)[y * step + x * 3];
|
||||
Y = ((uchar *)data)[y * step + x * 3 + 1];
|
||||
r = ((uchar *)data)[y * step + x * 3 + 2];
|
||||
}
|
||||
else if( m_type == FLOAT )
|
||||
if( m_type == FLOAT )
|
||||
{
|
||||
b = data[y * step + x * 3];
|
||||
Y = data[y * step + x * 3 + 1];
|
||||
@ -493,13 +480,7 @@ void ExrDecoder::ChromaToBGR( float *data, int numlines, int step )
|
||||
b = (b + 1) * Y;
|
||||
Y = (Y - b * m_chroma.blue[1] - r * m_chroma.red[1]) / m_chroma.green[1];
|
||||
|
||||
if( !m_native_depth )
|
||||
{
|
||||
((uchar *)data)[y * step + x * 3 + 0] = cv::saturate_cast<uchar>(b);
|
||||
((uchar *)data)[y * step + x * 3 + 1] = cv::saturate_cast<uchar>(Y);
|
||||
((uchar *)data)[y * step + x * 3 + 2] = cv::saturate_cast<uchar>(r);
|
||||
}
|
||||
else if( m_type == FLOAT )
|
||||
if( m_type == FLOAT )
|
||||
{
|
||||
data[y * step + x * 3] = (float)b;
|
||||
data[y * step + x * 3 + 1] = (float)Y;
|
||||
@ -580,41 +561,49 @@ ExrEncoder::~ExrEncoder()
|
||||
|
||||
bool ExrEncoder::isFormatSupported( int depth ) const
|
||||
{
|
||||
return CV_MAT_DEPTH(depth) >= CV_8U && CV_MAT_DEPTH(depth) < CV_64F;
|
||||
return ( CV_MAT_DEPTH(depth) == CV_32F );
|
||||
}
|
||||
|
||||
|
||||
// TODO scale appropriately
|
||||
bool ExrEncoder::write( const Mat& img, const std::vector<int>& )
|
||||
bool ExrEncoder::write( const Mat& img, const std::vector<int>& params )
|
||||
{
|
||||
int width = img.cols, height = img.rows;
|
||||
int depth = img.depth(), channels = img.channels();
|
||||
int depth = img.depth();
|
||||
CV_Assert( depth == CV_32F );
|
||||
int channels = img.channels();
|
||||
CV_Assert( channels == 3 || channels == 1 );
|
||||
bool result = false;
|
||||
bool issigned = depth == CV_8S || depth == CV_16S || depth == CV_32S;
|
||||
bool isfloat = depth == CV_32F || depth == CV_64F;
|
||||
depth = CV_ELEM_SIZE1(depth)*8;
|
||||
const size_t step = img.step;
|
||||
|
||||
Header header( width, height );
|
||||
Imf::PixelType type;
|
||||
Imf::PixelType type = FLOAT;
|
||||
|
||||
if(depth == 8)
|
||||
type = HALF;
|
||||
else if(isfloat)
|
||||
type = FLOAT;
|
||||
else
|
||||
type = UINT;
|
||||
for( size_t i = 0; i < params.size(); i += 2 )
|
||||
{
|
||||
if( params[i] == CV_IMWRITE_EXR_TYPE )
|
||||
{
|
||||
switch( params[i+1] )
|
||||
{
|
||||
case IMWRITE_EXR_TYPE_HALF:
|
||||
type = HALF;
|
||||
break;
|
||||
case IMWRITE_EXR_TYPE_FLOAT:
|
||||
type = FLOAT;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error( "IMWRITE_EXR_TYPE is invalid or not supported" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( channels == 3 )
|
||||
{
|
||||
header.channels().insert( "R", Channel( type ));
|
||||
header.channels().insert( "G", Channel( type ));
|
||||
header.channels().insert( "B", Channel( type ));
|
||||
header.channels().insert( "R", Channel( type ) );
|
||||
header.channels().insert( "G", Channel( type ) );
|
||||
header.channels().insert( "B", Channel( type ) );
|
||||
//printf("bunt\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
header.channels().insert( "Y", Channel( type ));
|
||||
header.channels().insert( "Y", Channel( type ) );
|
||||
//printf("gray\n");
|
||||
}
|
||||
|
||||
@ -625,27 +614,21 @@ bool ExrEncoder::write( const Mat& img, const std::vector<int>& )
|
||||
char *buffer;
|
||||
size_t bufferstep;
|
||||
int size;
|
||||
if( type == FLOAT && depth == 32 )
|
||||
Mat exrMat;
|
||||
if( type == HALF )
|
||||
{
|
||||
buffer = (char *)const_cast<uchar *>(img.ptr());
|
||||
bufferstep = step;
|
||||
size = 4;
|
||||
}
|
||||
else if( depth > 16 || type == UINT )
|
||||
{
|
||||
buffer = (char *)new unsigned[width * channels];
|
||||
bufferstep = 0;
|
||||
size = 4;
|
||||
convertFp16(img, exrMat);
|
||||
buffer = (char *)const_cast<uchar *>( exrMat.ptr() );
|
||||
bufferstep = exrMat.step;
|
||||
size = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = (char *)new half[width * channels];
|
||||
bufferstep = 0;
|
||||
size = 2;
|
||||
buffer = (char *)const_cast<uchar *>( img.ptr() );
|
||||
bufferstep = img.step;
|
||||
size = 4;
|
||||
}
|
||||
|
||||
//printf("depth %d %s\n", depth, types[type]);
|
||||
|
||||
if( channels == 3 )
|
||||
{
|
||||
frame.insert( "B", Slice( type, buffer, size * 3, bufferstep ));
|
||||
@ -657,77 +640,14 @@ bool ExrEncoder::write( const Mat& img, const std::vector<int>& )
|
||||
|
||||
file.setFrameBuffer( frame );
|
||||
|
||||
int offset = issigned ? 1 << (depth - 1) : 0;
|
||||
|
||||
result = true;
|
||||
if( type == FLOAT && depth == 32 )
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
file.writePixels( height );
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
file.writePixels( height );
|
||||
}
|
||||
else
|
||||
catch(...)
|
||||
{
|
||||
// int scale = 1 << (32 - depth);
|
||||
// printf("scale %d\n", scale);
|
||||
for(int line = 0; line < height; line++)
|
||||
{
|
||||
if(type == UINT)
|
||||
{
|
||||
unsigned *buf = (unsigned*)buffer; // FIXME 64-bit problems
|
||||
|
||||
if( depth <= 8 )
|
||||
{
|
||||
const uchar* sd = img.ptr(line);
|
||||
for(int i = 0; i < width * channels; i++)
|
||||
buf[i] = sd[i] + offset;
|
||||
}
|
||||
else if( depth <= 16 )
|
||||
{
|
||||
const unsigned short *sd = img.ptr<unsigned short>(line);
|
||||
for(int i = 0; i < width * channels; i++)
|
||||
buf[i] = sd[i] + offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
const int *sd = img.ptr<int>(line); // FIXME 64-bit problems
|
||||
for(int i = 0; i < width * channels; i++)
|
||||
buf[i] = (unsigned) sd[i] + offset;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
half *buf = (half *)buffer;
|
||||
|
||||
if( depth <= 8 )
|
||||
{
|
||||
const uchar* sd = img.ptr(line);
|
||||
for(int i = 0; i < width * channels; i++)
|
||||
buf[i] = sd[i];
|
||||
}
|
||||
else if( depth <= 16 )
|
||||
{
|
||||
const unsigned short *sd = img.ptr<unsigned short>(line);
|
||||
for(int i = 0; i < width * channels; i++)
|
||||
buf[i] = sd[i];
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
file.writePixels( 1 );
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete[] buffer;
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
Loading…
Reference in New Issue
Block a user