Path: blob/master/modules/imgcodecs/src/grfmt_exr.cpp
16337 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.13// Copyright (C) 2009, Willow Garage Inc., all rights reserved.14// Third party copyrights are property of their respective owners.15//16// Redistribution and use in source and binary forms, with or without modification,17// are permitted provided that the following conditions are met:18//19// * Redistribution's of source code must retain the above copyright notice,20// this list of conditions and the following disclaimer.21//22// * Redistribution's in binary form must reproduce the above copyright notice,23// this list of conditions and the following disclaimer in the documentation24// and/or other materials provided with the distribution.25//26// * The name of the copyright holders may not be used to endorse or promote products27// derived from this software without specific prior written permission.28//29// This software is provided by the copyright holders and contributors "as is" and30// any express or implied warranties, including, but not limited to, the implied31// warranties of merchantability and fitness for a particular purpose are disclaimed.32// In no event shall the Intel Corporation or contributors be liable for any direct,33// indirect, incidental, special, exemplary, or consequential damages34// (including, but not limited to, procurement of substitute goods or services;35// loss of use, data, or profits; or business interruption) however caused36// and on any theory of liability, whether in contract, strict liability,37// or tort (including negligence or otherwise) arising in any way out of38// the use of this software, even if advised of the possibility of such damage.39//40//M*/4142#include "precomp.hpp"4344#ifdef HAVE_OPENEXR4546#if defined _MSC_VER && _MSC_VER >= 120047# pragma warning( disable: 4100 4244 4267 )48#endif4950#if defined __GNUC__ && defined __APPLE__51# pragma GCC diagnostic ignored "-Wshadow"52#endif5354/// C++ Standard Libraries55#include <iostream>56#include <stdexcept>5758#include <ImfHeader.h>59#include <ImfInputFile.h>60#include <ImfOutputFile.h>61#include <ImfChannelList.h>62#include <ImfStandardAttributes.h>63#include <half.h>64#include "grfmt_exr.hpp"6566#if defined _WIN326768#undef UINT69#define UINT ((Imf::PixelType)0)70#undef HALF71#define HALF ((Imf::PixelType)1)72#undef FLOAT73#define FLOAT ((Imf::PixelType)2)7475#endif7677namespace cv78{7980/////////////////////// ExrDecoder ///////////////////8182ExrDecoder::ExrDecoder()83{84m_signature = "\x76\x2f\x31\x01";85m_file = 0;86m_red = m_green = m_blue = 0;87m_type = ((Imf::PixelType)0);88m_iscolor = false;89m_bit_depth = 0;90m_isfloat = false;91m_ischroma = false;92m_native_depth = false;9394}959697ExrDecoder::~ExrDecoder()98{99close();100}101102103void ExrDecoder::close()104{105if( m_file )106{107delete m_file;108m_file = 0;109}110}111112113int ExrDecoder::type() const114{115return CV_MAKETYPE((m_isfloat ? CV_32F : CV_32S), m_iscolor ? 3 : 1);116}117118119bool ExrDecoder::readHeader()120{121bool result = false;122123m_file = new InputFile( m_filename.c_str() );124125if( !m_file ) // probably paranoid126return false;127128m_datawindow = m_file->header().dataWindow();129m_width = m_datawindow.max.x - m_datawindow.min.x + 1;130m_height = m_datawindow.max.y - m_datawindow.min.y + 1;131132// the type HALF is converted to 32 bit float133// and the other types supported by OpenEXR are 32 bit anyway134m_bit_depth = 32;135136if( hasChromaticities( m_file->header() ))137m_chroma = chromaticities( m_file->header() );138139const ChannelList &channels = m_file->header().channels();140m_red = channels.findChannel( "R" );141m_green = channels.findChannel( "G" );142m_blue = channels.findChannel( "B" );143if( m_red || m_green || m_blue )144{145m_iscolor = true;146m_ischroma = false;147result = true;148}149else150{151m_green = channels.findChannel( "Y" );152if( m_green )153{154m_ischroma = true;155m_red = channels.findChannel( "RY" );156m_blue = channels.findChannel( "BY" );157m_iscolor = (m_blue || m_red);158result = true;159}160else161result = false;162}163164if( result )165{166m_type = FLOAT;167m_isfloat = ( m_type == FLOAT );168}169170if( !result )171close();172173return result;174}175176177bool ExrDecoder::readData( Mat& img )178{179m_native_depth = CV_MAT_DEPTH(type()) == img.depth();180bool color = img.channels() > 1;181int channels = 0;182uchar* data = img.ptr();183size_t step = img.step;184bool justcopy = ( m_native_depth && (color == m_iscolor) );185bool chromatorgb = ( m_ischroma && color );186bool rgbtogray = ( !m_ischroma && m_iscolor && !color );187bool result = true;188FrameBuffer frame;189int xsample[3] = {1, 1, 1};190char *buffer;191size_t xstep = 0;192size_t ystep = 0;193194xstep = m_native_depth ? 4 : 1;195196AutoBuffer<char> copy_buffer;197198if( !justcopy )199{200copy_buffer.allocate(sizeof(float) * m_width * 3);201buffer = copy_buffer.data();202ystep = 0;203}204else205{206buffer = (char *)data;207ystep = step;208}209210if( m_ischroma )211{212if( color )213{214if( m_blue )215{216frame.insert( "BY", Slice( m_type,217buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,21812, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 ));219xsample[0] = m_blue->ySampling;220}221else222{223frame.insert( "BY", Slice( m_type,224buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,22512, ystep, 1, 1, 0.0 ));226}227if( m_green )228{229frame.insert( "Y", Slice( m_type,230buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,23112, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));232xsample[1] = m_green->ySampling;233}234else235{236frame.insert( "Y", Slice( m_type,237buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,23812, ystep, 1, 1, 0.0 ));239}240if( m_red )241{242frame.insert( "RY", Slice( m_type,243buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,24412, ystep, m_red->xSampling, m_red->ySampling, 0.0 ));245xsample[2] = m_red->ySampling;246}247else248{249frame.insert( "RY", Slice( m_type,250buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,25112, ystep, 1, 1, 0.0 ));252}253}254else255{256frame.insert( "Y", Slice( m_type,257buffer - m_datawindow.min.x * 4 - m_datawindow.min.y * ystep,2584, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));259xsample[0] = m_green->ySampling;260}261}262else263{264if( m_blue )265{266frame.insert( "B", Slice( m_type,267buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,26812, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 ));269xsample[0] = m_blue->ySampling;270}271else272{273frame.insert( "B", Slice( m_type,274buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,27512, ystep, 1, 1, 0.0 ));276}277if( m_green )278{279frame.insert( "G", Slice( m_type,280buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,28112, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));282xsample[1] = m_green->ySampling;283}284else285{286frame.insert( "G", Slice( m_type,287buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,28812, ystep, 1, 1, 0.0 ));289}290if( m_red )291{292frame.insert( "R", Slice( m_type,293buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,29412, ystep, m_red->xSampling, m_red->ySampling, 0.0 ));295xsample[2] = m_red->ySampling;296}297else298{299frame.insert( "R", Slice( m_type,300buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,30112, ystep, 1, 1, 0.0 ));302}303}304305for (FrameBuffer::Iterator it = frame.begin(); it != frame.end(); it++) {306channels++;307}308309m_file->setFrameBuffer( frame );310if( justcopy )311{312m_file->readPixels( m_datawindow.min.y, m_datawindow.max.y );313314if( color )315{316if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )317UpSample( data, 3, step / xstep, xsample[0], m_blue->ySampling );318if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )319UpSample( data + xstep, 3, step / xstep, xsample[1], m_green->ySampling );320if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )321UpSample( data + 2 * xstep, 3, step / xstep, xsample[2], m_red->ySampling );322}323else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )324UpSample( data, 1, step / xstep, xsample[0], m_green->ySampling );325326if( chromatorgb )327ChromaToBGR( (float *)data, m_height, step / xstep );328}329else330{331uchar *out = data;332int x, y;333for( y = m_datawindow.min.y; y <= m_datawindow.max.y; y++ )334{335m_file->readPixels( y, y );336337for( int i = 0; i < channels; i++ )338{339if( xsample[i] != 1 )340UpSampleX( (float *)buffer + i, channels, xsample[i] );341}342if( rgbtogray )343{344RGBToGray( (float *)buffer, (float *)out );345}346else347{348if( chromatorgb )349ChromaToBGR( (float *)buffer, 1, step );350351if( m_type == FLOAT )352{353float *fi = (float *)buffer;354for( x = 0; x < m_width * img.channels(); x++)355{356out[x] = cv::saturate_cast<uchar>(fi[x]);357}358}359else360{361unsigned *ui = (unsigned *)buffer;362for( x = 0; x < m_width * img.channels(); x++)363{364out[x] = cv::saturate_cast<uchar>(ui[x]);365}366}367}368369out += step;370}371if( color )372{373if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )374UpSampleY( data, 3, step / xstep, m_blue->ySampling );375if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )376UpSampleY( data + xstep, 3, step / xstep, m_green->ySampling );377if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )378UpSampleY( data + 2 * xstep, 3, step / xstep, m_red->ySampling );379}380else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )381UpSampleY( data, 1, step / xstep, m_green->ySampling );382}383384close();385386return result;387}388389/**390// on entry pixel values are stored packed in the upper left corner of the image391// this functions expands them by duplication to cover the whole image392*/393void ExrDecoder::UpSample( uchar *data, int xstep, int ystep, int xsample, int ysample )394{395for( int y = (m_height - 1) / ysample, yre = m_height - ysample; y >= 0; y--, yre -= ysample )396{397for( int x = (m_width - 1) / xsample, xre = m_width - xsample; x >= 0; x--, xre -= xsample )398{399for( int i = 0; i < ysample; i++ )400{401for( int n = 0; n < xsample; n++ )402{403if( !m_native_depth )404data[(yre + i) * ystep + (xre + n) * xstep] = data[y * ystep + x * xstep];405else if( m_type == FLOAT )406((float *)data)[(yre + i) * ystep + (xre + n) * xstep] = ((float *)data)[y * ystep + x * xstep];407else408((unsigned *)data)[(yre + i) * ystep + (xre + n) * xstep] = ((unsigned *)data)[y * ystep + x * xstep];409}410}411}412}413}414415/**416// on entry pixel values are stored packed in the upper left corner of the image417// this functions expands them by duplication to cover the whole image418*/419void ExrDecoder::UpSampleX( float *data, int xstep, int xsample )420{421for( int x = (m_width - 1) / xsample, xre = m_width - xsample; x >= 0; x--, xre -= xsample )422{423for( int n = 0; n < xsample; n++ )424{425if( m_type == FLOAT )426((float *)data)[(xre + n) * xstep] = ((float *)data)[x * xstep];427else428((unsigned *)data)[(xre + n) * xstep] = ((unsigned *)data)[x * xstep];429}430}431}432433/**434// on entry pixel values are stored packed in the upper left corner of the image435// this functions expands them by duplication to cover the whole image436*/437void ExrDecoder::UpSampleY( uchar *data, int xstep, int ystep, int ysample )438{439for( int y = m_height - ysample, yre = m_height - ysample; y >= 0; y -= ysample, yre -= ysample )440{441for( int x = 0; x < m_width; x++ )442{443for( int i = 1; i < ysample; i++ )444{445if( !m_native_depth )446data[(yre + i) * ystep + x * xstep] = data[y * ystep + x * xstep];447else if( m_type == FLOAT )448((float *)data)[(yre + i) * ystep + x * xstep] = ((float *)data)[y * ystep + x * xstep];449else450((unsigned *)data)[(yre + i) * ystep + x * xstep] = ((unsigned *)data)[y * ystep + x * xstep];451}452}453}454}455456/**457// algorithm from ImfRgbaYca.cpp458*/459void ExrDecoder::ChromaToBGR( float *data, int numlines, int step )460{461for( int y = 0; y < numlines; y++ )462{463for( int x = 0; x < m_width; x++ )464{465double b, Y, r;466if( m_type == FLOAT )467{468b = data[y * step + x * 3];469Y = data[y * step + x * 3 + 1];470r = data[y * step + x * 3 + 2];471}472else473{474b = ((unsigned *)data)[y * step + x * 3];475Y = ((unsigned *)data)[y * step + x * 3 + 1];476r = ((unsigned *)data)[y * step + x * 3 + 2];477}478r = (r + 1) * Y;479b = (b + 1) * Y;480Y = (Y - b * m_chroma.blue[1] - r * m_chroma.red[1]) / m_chroma.green[1];481482if( m_type == FLOAT )483{484data[y * step + x * 3] = (float)b;485data[y * step + x * 3 + 1] = (float)Y;486data[y * step + x * 3 + 2] = (float)r;487}488else489{490int t = cvRound(b);491((unsigned *)data)[y * step + x * 3 + 0] = (unsigned)MAX(t, 0);492t = cvRound(Y);493((unsigned *)data)[y * step + x * 3 + 1] = (unsigned)MAX(t, 0);494t = cvRound(r);495((unsigned *)data)[y * step + x * 3 + 2] = (unsigned)MAX(t, 0);496}497}498}499}500501502/**503// convert one row to gray504*/505void ExrDecoder::RGBToGray( float *in, float *out )506{507if( m_type == FLOAT )508{509if( m_native_depth )510{511for( int i = 0, n = 0; i < m_width; i++, n += 3 )512out[i] = in[n] * m_chroma.blue[0] + in[n + 1] * m_chroma.green[0] + in[n + 2] * m_chroma.red[0];513}514else515{516uchar *o = (uchar *)out;517for( int i = 0, n = 0; i < m_width; i++, n += 3 )518o[i] = (uchar) (in[n] * m_chroma.blue[0] + in[n + 1] * m_chroma.green[0] + in[n + 2] * m_chroma.red[0]);519}520}521else // UINT522{523if( m_native_depth )524{525unsigned *ui = (unsigned *)in;526for( int i = 0; i < m_width * 3; i++ )527ui[i] -= 0x80000000;528int *si = (int *)in;529for( int i = 0, n = 0; i < m_width; i++, n += 3 )530((int *)out)[i] = int(si[n] * m_chroma.blue[0] + si[n + 1] * m_chroma.green[0] + si[n + 2] * m_chroma.red[0]);531}532else // how to best convert float to uchar?533{534unsigned *ui = (unsigned *)in;535for( int i = 0, n = 0; i < m_width; i++, n += 3 )536((uchar *)out)[i] = uchar((ui[n] * m_chroma.blue[0] + ui[n + 1] * m_chroma.green[0] + ui[n + 2] * m_chroma.red[0]) * (256.0 / 4294967296.0));537}538}539}540541542ImageDecoder ExrDecoder::newDecoder() const543{544return makePtr<ExrDecoder>();545}546547/////////////////////// ExrEncoder ///////////////////548549550ExrEncoder::ExrEncoder()551{552m_description = "OpenEXR Image files (*.exr)";553}554555556ExrEncoder::~ExrEncoder()557{558}559560561bool ExrEncoder::isFormatSupported( int depth ) const562{563return ( CV_MAT_DEPTH(depth) == CV_32F );564}565566567bool ExrEncoder::write( const Mat& img, const std::vector<int>& params )568{569int width = img.cols, height = img.rows;570int depth = img.depth();571CV_Assert( depth == CV_32F );572int channels = img.channels();573CV_Assert( channels == 3 || channels == 1 );574bool result = false;575Header header( width, height );576Imf::PixelType type = FLOAT;577578for( size_t i = 0; i < params.size(); i += 2 )579{580if( params[i] == CV_IMWRITE_EXR_TYPE )581{582switch( params[i+1] )583{584case IMWRITE_EXR_TYPE_HALF:585type = HALF;586break;587case IMWRITE_EXR_TYPE_FLOAT:588type = FLOAT;589break;590default:591throw std::runtime_error( "IMWRITE_EXR_TYPE is invalid or not supported" );592}593}594}595596if( channels == 3 )597{598header.channels().insert( "R", Channel( type ) );599header.channels().insert( "G", Channel( type ) );600header.channels().insert( "B", Channel( type ) );601//printf("bunt\n");602}603else604{605header.channels().insert( "Y", Channel( type ) );606//printf("gray\n");607}608609OutputFile file( m_filename.c_str(), header );610611FrameBuffer frame;612613char *buffer;614size_t bufferstep;615int size;616Mat exrMat;617if( type == HALF )618{619convertFp16(img, exrMat);620buffer = (char *)const_cast<uchar *>( exrMat.ptr() );621bufferstep = exrMat.step;622size = 2;623}624else625{626buffer = (char *)const_cast<uchar *>( img.ptr() );627bufferstep = img.step;628size = 4;629}630631if( channels == 3 )632{633frame.insert( "B", Slice( type, buffer, size * 3, bufferstep ));634frame.insert( "G", Slice( type, buffer + size, size * 3, bufferstep ));635frame.insert( "R", Slice( type, buffer + size * 2, size * 3, bufferstep ));636}637else638frame.insert( "Y", Slice( type, buffer, size, bufferstep ));639640file.setFrameBuffer( frame );641642result = true;643try644{645file.writePixels( height );646}647catch(...)648{649result = false;650}651652return result;653}654655656ImageEncoder ExrEncoder::newEncoder() const657{658return makePtr<ExrEncoder>();659}660661}662663#endif664665/* End of file. */666667668