@@ -84,12 +84,13 @@ ExrDecoder::ExrDecoder()
84
84
{
85
85
m_signature = " \x76\x2f\x31\x01 " ;
86
86
m_file = 0 ;
87
- m_red = m_green = m_blue = 0 ;
87
+ m_red = m_green = m_blue = m_alpha = 0 ;
88
88
m_type = ((Imf::PixelType)0 );
89
89
m_iscolor = false ;
90
90
m_bit_depth = 0 ;
91
91
m_isfloat = false ;
92
92
m_ischroma = false ;
93
+ m_hasalpha = false ;
93
94
m_native_depth = false ;
94
95
95
96
}
@@ -113,7 +114,7 @@ void ExrDecoder::close()
113
114
114
115
int ExrDecoder::type () const
115
116
{
116
- return CV_MAKETYPE ((m_isfloat ? CV_32F : CV_32S), m_iscolor ? 3 : 1 );
117
+ return CV_MAKETYPE ((m_isfloat ? CV_32F : CV_32S), (( m_iscolor && m_hasalpha) ? 4 : m_iscolor ? 3 : m_hasalpha ? 2 : 1 ) );
117
118
}
118
119
119
120
@@ -141,6 +142,11 @@ bool ExrDecoder::readHeader()
141
142
m_red = channels.findChannel ( " R" );
142
143
m_green = channels.findChannel ( " G" );
143
144
m_blue = channels.findChannel ( " B" );
145
+ m_alpha = channels.findChannel ( " A" );
146
+
147
+ if ( m_alpha ) // alpha channel supported in RGB, Y, and YC scenarios
148
+ m_hasalpha = true ;
149
+
144
150
if ( m_red || m_green || m_blue )
145
151
{
146
152
m_iscolor = true ;
@@ -178,7 +184,8 @@ bool ExrDecoder::readHeader()
178
184
bool ExrDecoder::readData ( Mat& img )
179
185
{
180
186
m_native_depth = CV_MAT_DEPTH (type ()) == img.depth ();
181
- bool color = img.channels () > 1 ;
187
+ bool color = img.channels () > 2 ; // output mat has 3+ channels; Y or YA are the 1 and 2 channel scenario
188
+ bool alphasupported = ( img.channels () % 2 == 0 ); // even number of channels indicates alpha
182
189
int channels = 0 ;
183
190
uchar* data = img.ptr ();
184
191
size_t step = img.step ;
@@ -187,18 +194,22 @@ bool ExrDecoder::readData( Mat& img )
187
194
bool rgbtogray = ( !m_ischroma && m_iscolor && !color );
188
195
bool result = true ;
189
196
FrameBuffer frame;
190
- int xsample[3 ] = {1 , 1 , 1 };
197
+ const int defaultchannels = 3 ;
198
+ int xsample[defaultchannels] = {1 , 1 , 1 };
191
199
char *buffer;
192
- size_t xstep = 0 ;
200
+ CV_Assert (m_type == FLOAT);
201
+ const size_t floatsize = sizeof (float );
202
+ size_t xstep = m_native_depth ? floatsize : 1 ; // 4 bytes if native depth (FLOAT), otherwise converting to 1 byte U8 depth
193
203
size_t ystep = 0 ;
194
-
195
- xstep = m_native_depth ? 4 : 1 ;
204
+ const int channelstoread = ( (m_iscolor && alphasupported) ? 4 :
205
+ ( (m_iscolor && !m_ischroma) || color) ? 3 : alphasupported ? 2 : 1 ); // number of channels to read may exceed channels in output img
206
+ size_t xStride = floatsize * channelstoread;
196
207
197
208
AutoBuffer<char > copy_buffer;
198
209
199
210
if ( !justcopy )
200
211
{
201
- copy_buffer.allocate (sizeof ( float ) * m_width * 3 );
212
+ copy_buffer.allocate (floatsize * m_width * defaultchannels );
202
213
buffer = copy_buffer.data ();
203
214
ystep = 0 ;
204
215
}
@@ -215,117 +226,135 @@ bool ExrDecoder::readData( Mat& img )
215
226
if ( m_blue )
216
227
{
217
228
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 ;
229
+ buffer - m_datawindow.min .x * xStride - m_datawindow.min .y * ystep,
230
+ xStride , ystep, m_blue->xSampling , m_blue->ySampling , 0.0 ));
231
+ xsample[0 ] = m_blue->xSampling ;
221
232
}
222
233
else
223
234
{
224
235
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 ));
236
+ buffer - m_datawindow.min .x * xStride - m_datawindow.min .y * ystep,
237
+ xStride , ystep, 1 , 1 , 0.0 ));
227
238
}
228
239
if ( m_green )
229
240
{
230
241
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 ;
242
+ buffer - m_datawindow.min .x * xStride - m_datawindow.min .y * ystep + floatsize ,
243
+ xStride , ystep, m_green->xSampling , m_green->ySampling , 0.0 ));
244
+ xsample[1 ] = m_green->xSampling ;
234
245
}
235
246
else
236
247
{
237
248
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 ));
249
+ buffer - m_datawindow.min .x * xStride - m_datawindow.min .y * ystep + floatsize ,
250
+ xStride , ystep, 1 , 1 , 0.0 ));
240
251
}
241
252
if ( m_red )
242
253
{
243
254
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 ;
255
+ buffer - m_datawindow.min .x * xStride - m_datawindow.min .y * ystep + (floatsize * 2 ) ,
256
+ xStride , ystep, m_red->xSampling , m_red->ySampling , 0.0 ));
257
+ xsample[2 ] = m_red->xSampling ;
247
258
}
248
259
else
249
260
{
250
261
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 ));
262
+ buffer - m_datawindow.min .x * xStride - m_datawindow.min .y * ystep + (floatsize * 2 ) ,
263
+ xStride , ystep, 1 , 1 , 0.0 ));
253
264
}
254
265
}
255
266
else
256
267
{
257
268
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 ;
269
+ buffer - m_datawindow.min .x * xStride - m_datawindow.min .y * ystep,
270
+ xStride , ystep, m_green->xSampling , m_green->ySampling , 0.0 ));
271
+ xsample[0 ] = m_green->xSampling ;
261
272
}
262
273
}
263
274
else
264
275
{
265
276
if ( m_blue )
266
277
{
267
278
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 ;
279
+ buffer - m_datawindow.min .x * xStride - m_datawindow.min .y * ystep,
280
+ xStride , ystep, m_blue->xSampling , m_blue->ySampling , 0.0 ));
281
+ xsample[0 ] = m_blue->xSampling ;
271
282
}
272
283
else
273
284
{
274
285
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 ));
286
+ buffer - m_datawindow.min .x * xStride - m_datawindow.min .y * ystep,
287
+ xStride , ystep, 1 , 1 , 0.0 ));
277
288
}
278
289
if ( m_green )
279
290
{
280
291
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 ;
292
+ buffer - m_datawindow.min .x * xStride - m_datawindow.min .y * ystep + floatsize ,
293
+ xStride , ystep, m_green->xSampling , m_green->ySampling , 0.0 ));
294
+ xsample[1 ] = m_green->xSampling ;
284
295
}
285
296
else
286
297
{
287
298
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 ));
299
+ buffer - m_datawindow.min .x * xStride - m_datawindow.min .y * ystep + floatsize ,
300
+ xStride , ystep, 1 , 1 , 0.0 ));
290
301
}
291
302
if ( m_red )
292
303
{
293
304
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 ;
305
+ buffer - m_datawindow.min .x * xStride - m_datawindow.min .y * ystep + (floatsize * 2 ) ,
306
+ xStride , ystep, m_red->xSampling , m_red->ySampling , 0.0 ));
307
+ xsample[2 ] = m_red->xSampling ;
297
308
}
298
309
else
299
310
{
300
311
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 ));
312
+ buffer - m_datawindow.min .x * xStride - m_datawindow.min .y * ystep + (floatsize * 2 ) ,
313
+ xStride , ystep, 1 , 1 , 0.0 ));
303
314
}
304
315
}
305
316
317
+ if ( justcopy && m_hasalpha && alphasupported )
318
+ { // alpha preserved only in justcopy scenario where alpha is desired (alphasupported)
319
+ // and present in original file (m_hasalpha)
320
+ CV_Assert (channelstoread == img.channels ());
321
+ int offset = (channelstoread - 1 ) * floatsize;
322
+ frame.insert ( " A" , Slice ( m_type,
323
+ buffer - m_datawindow.min .x * xStride - m_datawindow.min .y * ystep + offset,
324
+ xStride, ystep, m_alpha->xSampling , m_alpha->ySampling , 0.0 ));
325
+ }
326
+
306
327
for (FrameBuffer::Iterator it = frame.begin (); it != frame.end (); it++) {
307
328
channels++;
308
329
}
309
330
331
+ CV_Assert (channels == channelstoread);
332
+
333
+ if ( (channels != channelstoread) || (!justcopy && channels > defaultchannels) )
334
+ { // safety checking what ought to be true here
335
+ close ();
336
+ return false ;
337
+ }
338
+
310
339
m_file->setFrameBuffer ( frame );
311
340
if ( justcopy )
312
341
{
313
342
m_file->readPixels ( m_datawindow.min .y , m_datawindow.max .y );
314
343
315
- if ( color )
344
+ if ( m_iscolor )
316
345
{
317
346
if ( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1 ) )
318
- UpSample ( data, 3 , step / xstep, xsample[ 0 ] , m_blue->ySampling );
347
+ UpSample ( data, channelstoread , step / xstep, m_blue-> xSampling , m_blue->ySampling );
319
348
if ( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1 ) )
320
- UpSample ( data + xstep, 3 , step / xstep, xsample[ 1 ] , m_green->ySampling );
349
+ UpSample ( data + xstep, channelstoread , step / xstep, m_green-> xSampling , m_green->ySampling );
321
350
if ( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1 ) )
322
- UpSample ( data + 2 * xstep, 3 , step / xstep, xsample[ 2 ] , m_red->ySampling );
351
+ UpSample ( data + 2 * xstep, channelstoread , step / xstep, m_red-> xSampling , m_red->ySampling );
323
352
}
324
353
else if ( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1 ) )
325
- UpSample ( data, 1 , step / xstep, xsample[ 0 ] , m_green->ySampling );
354
+ UpSample ( data, channelstoread , step / xstep, m_green-> xSampling , m_green->ySampling );
326
355
327
356
if ( chromatorgb )
328
- ChromaToBGR ( (float *)data, m_height, step / xstep );
357
+ ChromaToBGR ( (float *)data, m_height, channelstoread, step / xstep );
329
358
}
330
359
else
331
360
{
@@ -347,7 +376,7 @@ bool ExrDecoder::readData( Mat& img )
347
376
else
348
377
{
349
378
if ( chromatorgb )
350
- ChromaToBGR ( (float *)buffer, 1 , step );
379
+ ChromaToBGR ( (float *)buffer, 1 , defaultchannels, step );
351
380
352
381
if ( m_type == FLOAT )
353
382
{
@@ -372,11 +401,11 @@ bool ExrDecoder::readData( Mat& img )
372
401
if ( color )
373
402
{
374
403
if ( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1 ) )
375
- UpSampleY ( data, 3 , step / xstep, m_blue->ySampling );
404
+ UpSampleY ( data, defaultchannels , step / xstep, m_blue->ySampling );
376
405
if ( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1 ) )
377
- UpSampleY ( data + xstep, 3 , step / xstep, m_green->ySampling );
406
+ UpSampleY ( data + xstep, defaultchannels , step / xstep, m_green->ySampling );
378
407
if ( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1 ) )
379
- UpSampleY ( data + 2 * xstep, 3 , step / xstep, m_red->ySampling );
408
+ UpSampleY ( data + 2 * xstep, defaultchannels , step / xstep, m_red->ySampling );
380
409
}
381
410
else if ( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1 ) )
382
411
UpSampleY ( data, 1 , step / xstep, m_green->ySampling );
@@ -457,7 +486,7 @@ void ExrDecoder::UpSampleY( uchar *data, int xstep, int ystep, int ysample )
457
486
/* *
458
487
// algorithm from ImfRgbaYca.cpp
459
488
*/
460
- void ExrDecoder::ChromaToBGR ( float *data, int numlines, int step )
489
+ void ExrDecoder::ChromaToBGR ( float *data, int numlines, int xstep, int ystep )
461
490
{
462
491
for ( int y = 0 ; y < numlines; y++ )
463
492
{
@@ -466,34 +495,34 @@ void ExrDecoder::ChromaToBGR( float *data, int numlines, int step )
466
495
double b, Y, r;
467
496
if ( m_type == FLOAT )
468
497
{
469
- b = data[y * step + x * 3 ];
470
- Y = data[y * step + x * 3 + 1 ];
471
- r = data[y * step + x * 3 + 2 ];
498
+ b = data[y * ystep + x * xstep ];
499
+ Y = data[y * ystep + x * xstep + 1 ];
500
+ r = data[y * ystep + x * xstep + 2 ];
472
501
}
473
502
else
474
503
{
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 ];
504
+ b = ((unsigned *)data)[y * ystep + x * xstep ];
505
+ Y = ((unsigned *)data)[y * ystep + x * xstep + 1 ];
506
+ r = ((unsigned *)data)[y * ystep + x * xstep + 2 ];
478
507
}
479
508
r = (r + 1 ) * Y;
480
509
b = (b + 1 ) * Y;
481
510
Y = (Y - b * m_chroma.blue [1 ] - r * m_chroma.red [1 ]) / m_chroma.green [1 ];
482
511
483
512
if ( m_type == FLOAT )
484
513
{
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;
514
+ data[y * ystep + x * xstep ] = (float )b;
515
+ data[y * ystep + x * xstep + 1 ] = (float )Y;
516
+ data[y * ystep + x * xstep + 2 ] = (float )r;
488
517
}
489
518
else
490
519
{
491
520
int t = cvRound (b);
492
- ((unsigned *)data)[y * step + x * 3 + 0 ] = (unsigned )MAX (t, 0 );
521
+ ((unsigned *)data)[y * ystep + x * xstep + 0 ] = (unsigned )MAX (t, 0 );
493
522
t = cvRound (Y);
494
- ((unsigned *)data)[y * step + x * 3 + 1 ] = (unsigned )MAX (t, 0 );
523
+ ((unsigned *)data)[y * ystep + x * xstep + 1 ] = (unsigned )MAX (t, 0 );
495
524
t = cvRound (r);
496
- ((unsigned *)data)[y * step + x * 3 + 2 ] = (unsigned )MAX (t, 0 );
525
+ ((unsigned *)data)[y * ystep + x * xstep + 2 ] = (unsigned )MAX (t, 0 );
497
526
}
498
527
}
499
528
}
@@ -571,7 +600,6 @@ bool ExrEncoder::write( const Mat& img, const std::vector<int>& params )
571
600
int depth = img.depth ();
572
601
CV_Assert ( depth == CV_32F );
573
602
int channels = img.channels ();
574
- CV_Assert ( channels == 3 || channels == 1 );
575
603
bool result = false ;
576
604
Header header ( width, height );
577
605
Imf::PixelType type = FLOAT;
@@ -594,7 +622,7 @@ bool ExrEncoder::write( const Mat& img, const std::vector<int>& params )
594
622
}
595
623
}
596
624
597
- if ( channels == 3 )
625
+ if ( channels == 3 || channels == 4 )
598
626
{
599
627
header.channels ().insert ( " R" , Channel ( type ) );
600
628
header.channels ().insert ( " G" , Channel ( type ) );
@@ -607,6 +635,11 @@ bool ExrEncoder::write( const Mat& img, const std::vector<int>& params )
607
635
// printf("gray\n");
608
636
}
609
637
638
+ if ( channels % 2 == 0 )
639
+ { // even number of channels indicates Alpha
640
+ header.channels ().insert ( " A" , Channel ( type ) );
641
+ }
642
+
610
643
OutputFile file ( m_filename.c_str (), header );
611
644
612
645
FrameBuffer frame;
@@ -629,14 +662,19 @@ bool ExrEncoder::write( const Mat& img, const std::vector<int>& params )
629
662
size = 4 ;
630
663
}
631
664
632
- if ( channels == 3 )
665
+ if ( channels == 3 || channels == 4 )
633
666
{
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 ));
667
+ frame.insert ( " B" , Slice ( type, buffer, size * channels , bufferstep ));
668
+ frame.insert ( " G" , Slice ( type, buffer + size, size * channels , bufferstep ));
669
+ frame.insert ( " R" , Slice ( type, buffer + size * 2 , size * channels , bufferstep ));
637
670
}
638
671
else
639
- frame.insert ( " Y" , Slice ( type, buffer, size, bufferstep ));
672
+ frame.insert ( " Y" , Slice ( type, buffer, size * channels, bufferstep ));
673
+
674
+ if ( channels % 2 == 0 )
675
+ { // even channel count indicates Alpha channel
676
+ frame.insert ( " A" , Slice ( type, buffer + size * (channels - 1 ), size * channels, bufferstep ));
677
+ }
640
678
641
679
file.setFrameBuffer ( frame );
642
680
0 commit comments