1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
22 // * Redistribution's in binary form must reproduce the above copyright notice,
23 // this list of conditions and the following disclaimer in the documentation
24 // and/or other materials provided with the distribution.
26 // * The name of Intel Corporation may not be used to endorse or promote products
27 // derived from this software without specific prior written permission.
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // 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 damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
46 #include <OpenEXR/ImfHeader.h>
47 #include <OpenEXR/ImfInputFile.h>
48 #include <OpenEXR/ImfOutputFile.h>
49 #include <OpenEXR/ImfChannelList.h>
50 #include <OpenEXR/ImfStandardAttributes.h>
51 #include <OpenEXR/half.h>
52 #include "grfmt_exr.h"
54 #if defined _MSC_VER && _MSC_VER >= 1200
55 #pragma comment(lib, "Half.lib")
56 #pragma comment(lib, "Iex.lib")
57 #pragma comment(lib, "IlmImf.lib")
58 #pragma comment(lib, "IlmThread.lib")
59 #pragma comment(lib, "Imath.lib")
62 #define UINT ((Imf::PixelType)0)
64 #define HALF ((Imf::PixelType)1)
66 #define FLOAT ((Imf::PixelType)2)
76 m_signature = "\x76\x2f\x31\x01";
77 m_description = "OpenEXR Image files (*.exr)";
86 GrFmtReader* GrFmtExr::NewReader( const char* filename )
88 return new GrFmtExrReader( filename );
92 GrFmtWriter* GrFmtExr::NewWriter( const char* filename )
94 return new GrFmtExrWriter( filename );
98 /////////////////////// GrFmtExrReader ///////////////////
100 GrFmtExrReader::GrFmtExrReader( const char* filename ) : GrFmtReader( filename )
102 m_file = new InputFile( filename );
103 m_red = m_green = m_blue = 0;
107 GrFmtExrReader::~GrFmtExrReader()
113 void GrFmtExrReader::Close()
121 GrFmtReader::Close();
124 bool GrFmtExrReader::ReadHeader()
128 if( !m_file ) // probably paranoid
131 m_datawindow = m_file->header().dataWindow();
132 m_width = m_datawindow.max.x - m_datawindow.min.x + 1;
133 m_height = m_datawindow.max.y - m_datawindow.min.y + 1;
135 // the type HALF is converted to 32 bit float
136 // and the other types supported by OpenEXR are 32 bit anyway
139 if( hasChromaticities( m_file->header() ))
140 m_chroma = chromaticities( m_file->header() );
142 const ChannelList &channels = m_file->header().channels();
143 m_red = channels.findChannel( "R" );
144 m_green = channels.findChannel( "G" );
145 m_blue = channels.findChannel( "B" );
146 if( m_red || m_green || m_blue )
154 m_green = channels.findChannel( "Y" );
158 m_red = channels.findChannel( "RY" );
159 m_blue = channels.findChannel( "BY" );
160 m_iscolor = (m_blue || m_red);
174 uintcnt += ( m_red->type == UINT );
179 uintcnt += ( m_green->type == UINT );
184 uintcnt += ( m_blue->type == UINT );
186 m_type = (chcnt == uintcnt) ? UINT : FLOAT;
188 m_isfloat = (m_type == FLOAT);
198 bool GrFmtExrReader::ReadData( uchar* data, int step, int color )
200 bool justcopy = m_native_depth;
201 bool chromatorgb = false;
202 bool rgbtogray = false;
205 int xsample[3] = {1, 1, 1};
210 xstep = m_native_depth ? 4 : 1;
212 if( !m_native_depth || (!color && m_iscolor ))
214 buffer = (char *)new float[ m_width * 3 ];
219 buffer = (char *)data;
231 frame.insert( "BY", Slice( m_type,
232 buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,
233 12, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 ));
234 xsample[0] = m_blue->ySampling;
238 frame.insert( "Y", Slice( m_type,
239 buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,
240 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
241 xsample[1] = m_green->ySampling;
245 frame.insert( "RY", Slice( m_type,
246 buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,
247 12, ystep, m_red->xSampling, m_red->ySampling, 0.0 ));
248 xsample[2] = m_red->ySampling;
254 frame.insert( "Y", Slice( m_type,
255 buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,
256 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
257 frame.insert( "Y", Slice( m_type,
258 buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,
259 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
260 frame.insert( "Y", Slice( m_type,
261 buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,
262 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
263 xsample[0] = m_green->ySampling;
264 xsample[1] = m_green->ySampling;
265 xsample[2] = m_green->ySampling;
270 frame.insert( "Y", Slice( m_type,
271 buffer - m_datawindow.min.x * 4 - m_datawindow.min.y * ystep,
272 4, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
273 xsample[0] = m_green->ySampling;
280 frame.insert( "B", Slice( m_type,
281 buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,
282 12, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 ));
283 xsample[0] = m_blue->ySampling;
287 frame.insert( "G", Slice( m_type,
288 buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,
289 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
290 xsample[1] = m_green->ySampling;
294 frame.insert( "R", Slice( m_type,
295 buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,
296 12, ystep, m_red->xSampling, m_red->ySampling, 0.0 ));
297 xsample[2] = m_red->ySampling;
306 m_file->setFrameBuffer( frame );
309 m_file->readPixels( m_datawindow.min.y, m_datawindow.max.y );
313 if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )
314 UpSample( data, 3, step / xstep, xsample[0], m_blue->ySampling );
315 if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
316 UpSample( data + xstep, 3, step / xstep, xsample[1], m_green->ySampling );
317 if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
318 UpSample( data + 2 * xstep, 3, step / xstep, xsample[2], m_red->ySampling );
320 else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
321 UpSample( data, 1, step / xstep, xsample[0], m_green->ySampling );
327 for( y = m_datawindow.min.y; y <= m_datawindow.max.y; y++ )
329 m_file->readPixels( y, y );
333 if( xsample[0] != 1 )
334 UpSampleX( (float *)buffer, 3, xsample[0] );
335 if( xsample[1] != 1 )
336 UpSampleX( (float *)buffer + 4, 3, xsample[1] );
337 if( xsample[2] != 1 )
338 UpSampleX( (float *)buffer + 8, 3, xsample[2] );
340 RGBToGray( (float *)buffer, (float *)out );
344 if( xsample[0] != 1 )
345 UpSampleX( (float *)buffer, 3, xsample[0] );
346 if( xsample[1] != 1 )
347 UpSampleX( (float *)(buffer + 4), 3, xsample[1] );
348 if( xsample[2] != 1 )
349 UpSampleX( (float *)(buffer + 8), 3, xsample[2] );
352 ChromaToBGR( (float *)buffer, 1, step );
354 if( m_type == FLOAT )
356 float *fi = (float *)buffer;
357 for( x = 0; x < m_width * 3; x++)
359 int t = cvRound(fi[x]*5);
360 out[x] = CV_CAST_8U(t);
365 uint *ui = (uint *)buffer;
366 for( x = 0; x < m_width * 3; x++)
369 out[x] = CV_CAST_8U(t);
378 if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )
379 UpSampleY( data, 3, step / xstep, m_blue->ySampling );
380 if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
381 UpSampleY( data + xstep, 3, step / xstep, m_green->ySampling );
382 if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
383 UpSampleY( data + 2 * xstep, 3, step / xstep, m_red->ySampling );
385 else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
386 UpSampleY( data, 1, step / xstep, m_green->ySampling );
390 ChromaToBGR( (float *)data, m_height, step / xstep );
398 // on entry pixel values are stored packed in the upper left corner of the image
399 // this functions expands them by duplication to cover the whole image
401 void GrFmtExrReader::UpSample( uchar *data, int xstep, int ystep, int xsample, int ysample )
403 for( int y = (m_height - 1) / ysample, yre = m_height - ysample; y >= 0; y--, yre -= ysample )
405 for( int x = (m_width - 1) / xsample, xre = m_width - xsample; x >= 0; x--, xre -= xsample )
407 for( int i = 0; i < ysample; i++ )
409 for( int n = 0; n < xsample; n++ )
411 if( !m_native_depth )
412 data[(yre + i) * ystep + (xre + n) * xstep] = data[y * ystep + x * xstep];
413 else if( m_type == FLOAT )
414 ((float *)data)[(yre + i) * ystep + (xre + n) * xstep] = ((float *)data)[y * ystep + x * xstep];
416 ((uint *)data)[(yre + i) * ystep + (xre + n) * xstep] = ((uint *)data)[y * ystep + x * xstep];
424 // on entry pixel values are stored packed in the upper left corner of the image
425 // this functions expands them by duplication to cover the whole image
427 void GrFmtExrReader::UpSampleX( float *data, int xstep, int xsample )
429 for( int x = (m_width - 1) / xsample, xre = m_width - xsample; x >= 0; x--, xre -= xsample )
431 for( int n = 0; n < xsample; n++ )
433 if( m_type == FLOAT )
434 ((float *)data)[(xre + n) * xstep] = ((float *)data)[x * xstep];
436 ((uint *)data)[(xre + n) * xstep] = ((uint *)data)[x * xstep];
442 // on entry pixel values are stored packed in the upper left corner of the image
443 // this functions expands them by duplication to cover the whole image
445 void GrFmtExrReader::UpSampleY( uchar *data, int xstep, int ystep, int ysample )
447 for( int y = m_height - ysample, yre = m_height - ysample; y >= 0; y -= ysample, yre -= ysample )
449 for( int x = 0; x < m_width; x++ )
451 for( int i = 1; i < ysample; i++ )
453 if( !m_native_depth )
454 data[(yre + i) * ystep + x * xstep] = data[y * ystep + x * xstep];
455 else if( m_type == FLOAT )
456 ((float *)data)[(yre + i) * ystep + x * xstep] = ((float *)data)[y * ystep + x * xstep];
458 ((uint *)data)[(yre + i) * ystep + x * xstep] = ((uint *)data)[y * ystep + x * xstep];
465 // algorithm from ImfRgbaYca.cpp
467 void GrFmtExrReader::ChromaToBGR( float *data, int numlines, int step )
471 for( y = 0; y < numlines; y++ )
473 for( x = 0; x < m_width; x++ )
476 if( !m_native_depth )
478 b = ((uchar *)data)[y * step + x * 3];
479 Y = ((uchar *)data)[y * step + x * 3 + 1];
480 r = ((uchar *)data)[y * step + x * 3 + 2];
482 else if( m_type == FLOAT )
484 b = data[y * step + x * 3];
485 Y = data[y * step + x * 3 + 1];
486 r = data[y * step + x * 3 + 2];
490 b = ((uint *)data)[y * step + x * 3];
491 Y = ((uint *)data)[y * step + x * 3 + 1];
492 r = ((uint *)data)[y * step + x * 3 + 2];
496 Y = (Y - b * m_chroma.blue[1] - r * m_chroma.red[1]) / m_chroma.green[1];
498 if( !m_native_depth )
501 ((uchar *)data)[y * step + x * 3] = CV_CAST_8U(t);
503 ((uchar *)data)[y * step + x * 3 + 1] = CV_CAST_8U(t);
505 ((uchar *)data)[y * step + x * 3 + 2] = CV_CAST_8U(t);
507 else if( m_type == FLOAT )
509 data[y * step + x * 3] = (float)b;
510 data[y * step + x * 3 + 1] = (float)Y;
511 data[y * step + x * 3 + 2] = (float)r;
516 ((uint *)data)[y * step + x * 3] = (uint)MAX(t,0);
518 ((uint *)data)[y * step + x * 3 + 1] = (uint)MAX(t,0);
520 ((uint *)data)[y * step + x * 3 + 2] = (uint)MAX(t,0);
528 // convert one row to gray
530 void GrFmtExrReader::RGBToGray( float *in, float *out )
532 if( m_type == FLOAT )
536 for( int i = 0, n = 0; i < m_width; i++, n += 3 )
537 out[i] = in[n] * m_chroma.blue[0] + in[n + 1] * m_chroma.green[0] + in[n + 2] * m_chroma.red[0];
541 uchar *o = (uchar *)out;
542 for( int i = 0, n = 0; i < m_width; i++, n += 3 )
543 o[i] = (uchar) (in[n] * m_chroma.blue[0] + in[n + 1] * m_chroma.green[0] + in[n + 2] * m_chroma.red[0]);
550 uint *ui = (uint *)in;
551 for( int i = 0; i < m_width * 3; i++ )
554 for( int i = 0, n = 0; i < m_width; i++, n += 3 )
555 ((int *)out)[i] = int(si[n] * m_chroma.blue[0] + si[n + 1] * m_chroma.green[0] + si[n + 2] * m_chroma.red[0]);
557 else // how to best convert float to uchar?
559 uint *ui = (uint *)in;
560 for( int i = 0, n = 0; i < m_width; i++, n += 3 )
561 ((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));
566 /////////////////////// GrFmtExrWriter ///////////////////
569 GrFmtExrWriter::GrFmtExrWriter( const char* filename ) : GrFmtWriter( filename )
574 GrFmtExrWriter::~GrFmtExrWriter()
579 bool GrFmtExrWriter::IsFormatSupported( int depth )
581 return depth == IPL_DEPTH_8U || depth == IPL_DEPTH_8S ||
582 depth == IPL_DEPTH_16U || depth == IPL_DEPTH_16S ||
583 depth == IPL_DEPTH_32S || depth == IPL_DEPTH_32F;
584 // TODO: do (or should) we support 64f?
588 // TODO scale appropriately
589 bool GrFmtExrWriter::WriteImage( const uchar* data, int step,
590 int width, int height, int depth, int channels )
594 Header header( width, height );
596 bool issigned = depth < 0;
597 bool isfloat = depth == IPL_DEPTH_32F || depth == IPL_DEPTH_64F;
599 if(depth == IPL_DEPTH_8U || depth == IPL_DEPTH_8S)
610 header.channels().insert( "R", Channel( type ));
611 header.channels().insert( "G", Channel( type ));
612 header.channels().insert( "B", Channel( type ));
617 header.channels().insert( "Y", Channel( type ));
621 OutputFile file( m_filename, header );
628 if( type == FLOAT && depth == 32 )
630 buffer = (char *)const_cast<uchar *>(data);
634 else if( depth > 16 || type == UINT )
636 buffer = (char *)new uint[width * channels];
642 buffer = (char *)new half[width * channels];
647 //printf("depth %d %s\n", depth, types[type]);
651 frame.insert( "B", Slice( type, buffer, size * 3, bufferstep ));
652 frame.insert( "G", Slice( type, buffer + size, size * 3, bufferstep ));
653 frame.insert( "R", Slice( type, buffer + size * 2, size * 3, bufferstep ));
656 frame.insert( "Y", Slice( type, buffer, size, bufferstep ));
658 file.setFrameBuffer( frame );
660 int offset = issigned ? 1 << (depth - 1) : 0;
663 if( type == FLOAT && depth == 32 )
667 file.writePixels( height );
676 // int scale = 1 << (32 - depth);
677 // printf("scale %d\n", scale);
678 for(int line = 0; line < height; line++)
682 uint *buf = (uint *)buffer; // FIXME 64-bit problems
686 for(int i = 0; i < width * channels; i++)
687 buf[i] = data[i] + offset;
689 else if( depth <= 16 )
691 unsigned short *sd = (unsigned short *)data;
692 for(int i = 0; i < width * channels; i++)
693 buf[i] = sd[i] + offset;
697 int *sd = (int *)data; // FIXME 64-bit problems
698 for(int i = 0; i < width * channels; i++)
699 buf[i] = (uint) sd[i] + offset;
704 half *buf = (half *)buffer;
708 for(int i = 0; i < width * channels; i++)
711 else if( depth <= 16 )
713 unsigned short *sd = (unsigned short *)data;
714 for(int i = 0; i < width * channels; i++)
720 file.writePixels( 1 );