Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/imgcodecs/src/grfmt_exr.cpp
16337 views
1
/*M///////////////////////////////////////////////////////////////////////////////////////
2
//
3
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4
//
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.
8
//
9
//
10
// License Agreement
11
// For Open Source Computer Vision Library
12
//
13
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15
// Third party copyrights are property of their respective owners.
16
//
17
// Redistribution and use in source and binary forms, with or without modification,
18
// are permitted provided that the following conditions are met:
19
//
20
// * Redistribution's of source code must retain the above copyright notice,
21
// this list of conditions and the following disclaimer.
22
//
23
// * Redistribution's in binary form must reproduce the above copyright notice,
24
// this list of conditions and the following disclaimer in the documentation
25
// and/or other materials provided with the distribution.
26
//
27
// * The name of the copyright holders may not be used to endorse or promote products
28
// derived from this software without specific prior written permission.
29
//
30
// This software is provided by the copyright holders and contributors "as is" and
31
// any express or implied warranties, including, but not limited to, the implied
32
// warranties of merchantability and fitness for a particular purpose are disclaimed.
33
// In no event shall the Intel Corporation or contributors be liable for any direct,
34
// indirect, incidental, special, exemplary, or consequential damages
35
// (including, but not limited to, procurement of substitute goods or services;
36
// loss of use, data, or profits; or business interruption) however caused
37
// and on any theory of liability, whether in contract, strict liability,
38
// or tort (including negligence or otherwise) arising in any way out of
39
// the use of this software, even if advised of the possibility of such damage.
40
//
41
//M*/
42
43
#include "precomp.hpp"
44
45
#ifdef HAVE_OPENEXR
46
47
#if defined _MSC_VER && _MSC_VER >= 1200
48
# pragma warning( disable: 4100 4244 4267 )
49
#endif
50
51
#if defined __GNUC__ && defined __APPLE__
52
# pragma GCC diagnostic ignored "-Wshadow"
53
#endif
54
55
/// C++ Standard Libraries
56
#include <iostream>
57
#include <stdexcept>
58
59
#include <ImfHeader.h>
60
#include <ImfInputFile.h>
61
#include <ImfOutputFile.h>
62
#include <ImfChannelList.h>
63
#include <ImfStandardAttributes.h>
64
#include <half.h>
65
#include "grfmt_exr.hpp"
66
67
#if defined _WIN32
68
69
#undef UINT
70
#define UINT ((Imf::PixelType)0)
71
#undef HALF
72
#define HALF ((Imf::PixelType)1)
73
#undef FLOAT
74
#define FLOAT ((Imf::PixelType)2)
75
76
#endif
77
78
namespace cv
79
{
80
81
/////////////////////// ExrDecoder ///////////////////
82
83
ExrDecoder::ExrDecoder()
84
{
85
m_signature = "\x76\x2f\x31\x01";
86
m_file = 0;
87
m_red = m_green = m_blue = 0;
88
m_type = ((Imf::PixelType)0);
89
m_iscolor = false;
90
m_bit_depth = 0;
91
m_isfloat = false;
92
m_ischroma = false;
93
m_native_depth = false;
94
95
}
96
97
98
ExrDecoder::~ExrDecoder()
99
{
100
close();
101
}
102
103
104
void ExrDecoder::close()
105
{
106
if( m_file )
107
{
108
delete m_file;
109
m_file = 0;
110
}
111
}
112
113
114
int ExrDecoder::type() const
115
{
116
return CV_MAKETYPE((m_isfloat ? CV_32F : CV_32S), m_iscolor ? 3 : 1);
117
}
118
119
120
bool ExrDecoder::readHeader()
121
{
122
bool result = false;
123
124
m_file = new InputFile( m_filename.c_str() );
125
126
if( !m_file ) // probably paranoid
127
return false;
128
129
m_datawindow = m_file->header().dataWindow();
130
m_width = m_datawindow.max.x - m_datawindow.min.x + 1;
131
m_height = m_datawindow.max.y - m_datawindow.min.y + 1;
132
133
// the type HALF is converted to 32 bit float
134
// and the other types supported by OpenEXR are 32 bit anyway
135
m_bit_depth = 32;
136
137
if( hasChromaticities( m_file->header() ))
138
m_chroma = chromaticities( m_file->header() );
139
140
const ChannelList &channels = m_file->header().channels();
141
m_red = channels.findChannel( "R" );
142
m_green = channels.findChannel( "G" );
143
m_blue = channels.findChannel( "B" );
144
if( m_red || m_green || m_blue )
145
{
146
m_iscolor = true;
147
m_ischroma = false;
148
result = true;
149
}
150
else
151
{
152
m_green = channels.findChannel( "Y" );
153
if( m_green )
154
{
155
m_ischroma = true;
156
m_red = channels.findChannel( "RY" );
157
m_blue = channels.findChannel( "BY" );
158
m_iscolor = (m_blue || m_red);
159
result = true;
160
}
161
else
162
result = false;
163
}
164
165
if( result )
166
{
167
m_type = FLOAT;
168
m_isfloat = ( m_type == FLOAT );
169
}
170
171
if( !result )
172
close();
173
174
return result;
175
}
176
177
178
bool ExrDecoder::readData( Mat& img )
179
{
180
m_native_depth = CV_MAT_DEPTH(type()) == img.depth();
181
bool color = img.channels() > 1;
182
int channels = 0;
183
uchar* data = img.ptr();
184
size_t step = img.step;
185
bool justcopy = ( m_native_depth && (color == m_iscolor) );
186
bool chromatorgb = ( m_ischroma && color );
187
bool rgbtogray = ( !m_ischroma && m_iscolor && !color );
188
bool result = true;
189
FrameBuffer frame;
190
int xsample[3] = {1, 1, 1};
191
char *buffer;
192
size_t xstep = 0;
193
size_t ystep = 0;
194
195
xstep = m_native_depth ? 4 : 1;
196
197
AutoBuffer<char> copy_buffer;
198
199
if( !justcopy )
200
{
201
copy_buffer.allocate(sizeof(float) * m_width * 3);
202
buffer = copy_buffer.data();
203
ystep = 0;
204
}
205
else
206
{
207
buffer = (char *)data;
208
ystep = step;
209
}
210
211
if( m_ischroma )
212
{
213
if( color )
214
{
215
if( m_blue )
216
{
217
frame.insert( "BY", Slice( m_type,
218
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,
219
12, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 ));
220
xsample[0] = m_blue->ySampling;
221
}
222
else
223
{
224
frame.insert( "BY", Slice( m_type,
225
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,
226
12, ystep, 1, 1, 0.0 ));
227
}
228
if( m_green )
229
{
230
frame.insert( "Y", Slice( m_type,
231
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,
232
12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
233
xsample[1] = m_green->ySampling;
234
}
235
else
236
{
237
frame.insert( "Y", Slice( m_type,
238
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,
239
12, ystep, 1, 1, 0.0 ));
240
}
241
if( m_red )
242
{
243
frame.insert( "RY", Slice( m_type,
244
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,
245
12, ystep, m_red->xSampling, m_red->ySampling, 0.0 ));
246
xsample[2] = m_red->ySampling;
247
}
248
else
249
{
250
frame.insert( "RY", Slice( m_type,
251
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,
252
12, ystep, 1, 1, 0.0 ));
253
}
254
}
255
else
256
{
257
frame.insert( "Y", Slice( m_type,
258
buffer - m_datawindow.min.x * 4 - m_datawindow.min.y * ystep,
259
4, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
260
xsample[0] = m_green->ySampling;
261
}
262
}
263
else
264
{
265
if( m_blue )
266
{
267
frame.insert( "B", Slice( m_type,
268
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,
269
12, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 ));
270
xsample[0] = m_blue->ySampling;
271
}
272
else
273
{
274
frame.insert( "B", Slice( m_type,
275
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,
276
12, ystep, 1, 1, 0.0 ));
277
}
278
if( m_green )
279
{
280
frame.insert( "G", Slice( m_type,
281
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,
282
12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
283
xsample[1] = m_green->ySampling;
284
}
285
else
286
{
287
frame.insert( "G", Slice( m_type,
288
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,
289
12, ystep, 1, 1, 0.0 ));
290
}
291
if( m_red )
292
{
293
frame.insert( "R", Slice( m_type,
294
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,
295
12, ystep, m_red->xSampling, m_red->ySampling, 0.0 ));
296
xsample[2] = m_red->ySampling;
297
}
298
else
299
{
300
frame.insert( "R", Slice( m_type,
301
buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,
302
12, ystep, 1, 1, 0.0 ));
303
}
304
}
305
306
for (FrameBuffer::Iterator it = frame.begin(); it != frame.end(); it++) {
307
channels++;
308
}
309
310
m_file->setFrameBuffer( frame );
311
if( justcopy )
312
{
313
m_file->readPixels( m_datawindow.min.y, m_datawindow.max.y );
314
315
if( color )
316
{
317
if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )
318
UpSample( data, 3, step / xstep, xsample[0], m_blue->ySampling );
319
if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
320
UpSample( data + xstep, 3, step / xstep, xsample[1], m_green->ySampling );
321
if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
322
UpSample( data + 2 * xstep, 3, step / xstep, xsample[2], m_red->ySampling );
323
}
324
else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
325
UpSample( data, 1, step / xstep, xsample[0], m_green->ySampling );
326
327
if( chromatorgb )
328
ChromaToBGR( (float *)data, m_height, step / xstep );
329
}
330
else
331
{
332
uchar *out = data;
333
int x, y;
334
for( y = m_datawindow.min.y; y <= m_datawindow.max.y; y++ )
335
{
336
m_file->readPixels( y, y );
337
338
for( int i = 0; i < channels; i++ )
339
{
340
if( xsample[i] != 1 )
341
UpSampleX( (float *)buffer + i, channels, xsample[i] );
342
}
343
if( rgbtogray )
344
{
345
RGBToGray( (float *)buffer, (float *)out );
346
}
347
else
348
{
349
if( chromatorgb )
350
ChromaToBGR( (float *)buffer, 1, step );
351
352
if( m_type == FLOAT )
353
{
354
float *fi = (float *)buffer;
355
for( x = 0; x < m_width * img.channels(); x++)
356
{
357
out[x] = cv::saturate_cast<uchar>(fi[x]);
358
}
359
}
360
else
361
{
362
unsigned *ui = (unsigned *)buffer;
363
for( x = 0; x < m_width * img.channels(); x++)
364
{
365
out[x] = cv::saturate_cast<uchar>(ui[x]);
366
}
367
}
368
}
369
370
out += step;
371
}
372
if( color )
373
{
374
if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )
375
UpSampleY( data, 3, step / xstep, m_blue->ySampling );
376
if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
377
UpSampleY( data + xstep, 3, step / xstep, m_green->ySampling );
378
if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
379
UpSampleY( data + 2 * xstep, 3, step / xstep, m_red->ySampling );
380
}
381
else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
382
UpSampleY( data, 1, step / xstep, m_green->ySampling );
383
}
384
385
close();
386
387
return result;
388
}
389
390
/**
391
// on entry pixel values are stored packed in the upper left corner of the image
392
// this functions expands them by duplication to cover the whole image
393
*/
394
void ExrDecoder::UpSample( uchar *data, int xstep, int ystep, int xsample, int ysample )
395
{
396
for( int y = (m_height - 1) / ysample, yre = m_height - ysample; y >= 0; y--, yre -= ysample )
397
{
398
for( int x = (m_width - 1) / xsample, xre = m_width - xsample; x >= 0; x--, xre -= xsample )
399
{
400
for( int i = 0; i < ysample; i++ )
401
{
402
for( int n = 0; n < xsample; n++ )
403
{
404
if( !m_native_depth )
405
data[(yre + i) * ystep + (xre + n) * xstep] = data[y * ystep + x * xstep];
406
else if( m_type == FLOAT )
407
((float *)data)[(yre + i) * ystep + (xre + n) * xstep] = ((float *)data)[y * ystep + x * xstep];
408
else
409
((unsigned *)data)[(yre + i) * ystep + (xre + n) * xstep] = ((unsigned *)data)[y * ystep + x * xstep];
410
}
411
}
412
}
413
}
414
}
415
416
/**
417
// on entry pixel values are stored packed in the upper left corner of the image
418
// this functions expands them by duplication to cover the whole image
419
*/
420
void ExrDecoder::UpSampleX( float *data, int xstep, int xsample )
421
{
422
for( int x = (m_width - 1) / xsample, xre = m_width - xsample; x >= 0; x--, xre -= xsample )
423
{
424
for( int n = 0; n < xsample; n++ )
425
{
426
if( m_type == FLOAT )
427
((float *)data)[(xre + n) * xstep] = ((float *)data)[x * xstep];
428
else
429
((unsigned *)data)[(xre + n) * xstep] = ((unsigned *)data)[x * xstep];
430
}
431
}
432
}
433
434
/**
435
// on entry pixel values are stored packed in the upper left corner of the image
436
// this functions expands them by duplication to cover the whole image
437
*/
438
void ExrDecoder::UpSampleY( uchar *data, int xstep, int ystep, int ysample )
439
{
440
for( int y = m_height - ysample, yre = m_height - ysample; y >= 0; y -= ysample, yre -= ysample )
441
{
442
for( int x = 0; x < m_width; x++ )
443
{
444
for( int i = 1; i < ysample; i++ )
445
{
446
if( !m_native_depth )
447
data[(yre + i) * ystep + x * xstep] = data[y * ystep + x * xstep];
448
else if( m_type == FLOAT )
449
((float *)data)[(yre + i) * ystep + x * xstep] = ((float *)data)[y * ystep + x * xstep];
450
else
451
((unsigned *)data)[(yre + i) * ystep + x * xstep] = ((unsigned *)data)[y * ystep + x * xstep];
452
}
453
}
454
}
455
}
456
457
/**
458
// algorithm from ImfRgbaYca.cpp
459
*/
460
void ExrDecoder::ChromaToBGR( float *data, int numlines, int step )
461
{
462
for( int y = 0; y < numlines; y++ )
463
{
464
for( int x = 0; x < m_width; x++ )
465
{
466
double b, Y, r;
467
if( m_type == FLOAT )
468
{
469
b = data[y * step + x * 3];
470
Y = data[y * step + x * 3 + 1];
471
r = data[y * step + x * 3 + 2];
472
}
473
else
474
{
475
b = ((unsigned *)data)[y * step + x * 3];
476
Y = ((unsigned *)data)[y * step + x * 3 + 1];
477
r = ((unsigned *)data)[y * step + x * 3 + 2];
478
}
479
r = (r + 1) * Y;
480
b = (b + 1) * Y;
481
Y = (Y - b * m_chroma.blue[1] - r * m_chroma.red[1]) / m_chroma.green[1];
482
483
if( m_type == FLOAT )
484
{
485
data[y * step + x * 3] = (float)b;
486
data[y * step + x * 3 + 1] = (float)Y;
487
data[y * step + x * 3 + 2] = (float)r;
488
}
489
else
490
{
491
int t = cvRound(b);
492
((unsigned *)data)[y * step + x * 3 + 0] = (unsigned)MAX(t, 0);
493
t = cvRound(Y);
494
((unsigned *)data)[y * step + x * 3 + 1] = (unsigned)MAX(t, 0);
495
t = cvRound(r);
496
((unsigned *)data)[y * step + x * 3 + 2] = (unsigned)MAX(t, 0);
497
}
498
}
499
}
500
}
501
502
503
/**
504
// convert one row to gray
505
*/
506
void ExrDecoder::RGBToGray( float *in, float *out )
507
{
508
if( m_type == FLOAT )
509
{
510
if( m_native_depth )
511
{
512
for( int i = 0, n = 0; i < m_width; i++, n += 3 )
513
out[i] = in[n] * m_chroma.blue[0] + in[n + 1] * m_chroma.green[0] + in[n + 2] * m_chroma.red[0];
514
}
515
else
516
{
517
uchar *o = (uchar *)out;
518
for( int i = 0, n = 0; i < m_width; i++, n += 3 )
519
o[i] = (uchar) (in[n] * m_chroma.blue[0] + in[n + 1] * m_chroma.green[0] + in[n + 2] * m_chroma.red[0]);
520
}
521
}
522
else // UINT
523
{
524
if( m_native_depth )
525
{
526
unsigned *ui = (unsigned *)in;
527
for( int i = 0; i < m_width * 3; i++ )
528
ui[i] -= 0x80000000;
529
int *si = (int *)in;
530
for( int i = 0, n = 0; i < m_width; i++, n += 3 )
531
((int *)out)[i] = int(si[n] * m_chroma.blue[0] + si[n + 1] * m_chroma.green[0] + si[n + 2] * m_chroma.red[0]);
532
}
533
else // how to best convert float to uchar?
534
{
535
unsigned *ui = (unsigned *)in;
536
for( int i = 0, n = 0; i < m_width; i++, n += 3 )
537
((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));
538
}
539
}
540
}
541
542
543
ImageDecoder ExrDecoder::newDecoder() const
544
{
545
return makePtr<ExrDecoder>();
546
}
547
548
/////////////////////// ExrEncoder ///////////////////
549
550
551
ExrEncoder::ExrEncoder()
552
{
553
m_description = "OpenEXR Image files (*.exr)";
554
}
555
556
557
ExrEncoder::~ExrEncoder()
558
{
559
}
560
561
562
bool ExrEncoder::isFormatSupported( int depth ) const
563
{
564
return ( CV_MAT_DEPTH(depth) == CV_32F );
565
}
566
567
568
bool ExrEncoder::write( const Mat& img, const std::vector<int>& params )
569
{
570
int width = img.cols, height = img.rows;
571
int depth = img.depth();
572
CV_Assert( depth == CV_32F );
573
int channels = img.channels();
574
CV_Assert( channels == 3 || channels == 1 );
575
bool result = false;
576
Header header( width, height );
577
Imf::PixelType type = FLOAT;
578
579
for( size_t i = 0; i < params.size(); i += 2 )
580
{
581
if( params[i] == CV_IMWRITE_EXR_TYPE )
582
{
583
switch( params[i+1] )
584
{
585
case IMWRITE_EXR_TYPE_HALF:
586
type = HALF;
587
break;
588
case IMWRITE_EXR_TYPE_FLOAT:
589
type = FLOAT;
590
break;
591
default:
592
throw std::runtime_error( "IMWRITE_EXR_TYPE is invalid or not supported" );
593
}
594
}
595
}
596
597
if( channels == 3 )
598
{
599
header.channels().insert( "R", Channel( type ) );
600
header.channels().insert( "G", Channel( type ) );
601
header.channels().insert( "B", Channel( type ) );
602
//printf("bunt\n");
603
}
604
else
605
{
606
header.channels().insert( "Y", Channel( type ) );
607
//printf("gray\n");
608
}
609
610
OutputFile file( m_filename.c_str(), header );
611
612
FrameBuffer frame;
613
614
char *buffer;
615
size_t bufferstep;
616
int size;
617
Mat exrMat;
618
if( type == HALF )
619
{
620
convertFp16(img, exrMat);
621
buffer = (char *)const_cast<uchar *>( exrMat.ptr() );
622
bufferstep = exrMat.step;
623
size = 2;
624
}
625
else
626
{
627
buffer = (char *)const_cast<uchar *>( img.ptr() );
628
bufferstep = img.step;
629
size = 4;
630
}
631
632
if( channels == 3 )
633
{
634
frame.insert( "B", Slice( type, buffer, size * 3, bufferstep ));
635
frame.insert( "G", Slice( type, buffer + size, size * 3, bufferstep ));
636
frame.insert( "R", Slice( type, buffer + size * 2, size * 3, bufferstep ));
637
}
638
else
639
frame.insert( "Y", Slice( type, buffer, size, bufferstep ));
640
641
file.setFrameBuffer( frame );
642
643
result = true;
644
try
645
{
646
file.writePixels( height );
647
}
648
catch(...)
649
{
650
result = false;
651
}
652
653
return result;
654
}
655
656
657
ImageEncoder ExrEncoder::newEncoder() const
658
{
659
return makePtr<ExrEncoder>();
660
}
661
662
}
663
664
#endif
665
666
/* End of file. */
667
668