Skip to content

Commit 2674c6b

Browse files
gdkessleralalek
authored andcommitted
Merge pull request opencv#10093 from gdkessler/gdal_image_read_fix_10089
Fix GDAL image decoding color problems identified by issue opencv#10089, by: (opencv#10093) * Fix GDAL image decoding color problems identified by issue opencv#10089, by: Fixing CV_8UC1 symbol, which should be CV_8UC3 for RGB GDAL color table images. Fixing image.ptr<VecX>(row,col)[] to be (*image.ptr<VecX>(row,col))[] to correctly access VecX array elements, as ptr<VecX>() returns a pointer to the VecX, not the first element of VecX. This fixes the color problem with color table gif images, and avoids out-of-bounds memory access. Respecting the color identification of raster bands provided by the GDAL image driver, and produce BGR or BGRA images. Note that color bands of images using the HSL, CMY, CMYK, or YCbCr color space are ignored, rather than converting them to BGR. * When reading image files using the GDAL decoder, exit with an error if a color band is encountered that isn't used (eg. from CMYK or YCbCbr), rather than silently ignoring the band's data.
1 parent c7f1843 commit 2674c6b

File tree

1 file changed

+45
-21
lines changed

1 file changed

+45
-21
lines changed

modules/imgcodecs/src/grfmt_gdal.cpp

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ int gdalPaletteInterpretation2OpenCV( GDALPaletteInterp const& paletteInterp, G
7878

7979
/// RGB
8080
case GPI_RGB:
81-
if( gdalType == GDT_Byte ){ return CV_8UC1; }
81+
if( gdalType == GDT_Byte ){ return CV_8UC3; }
8282
if( gdalType == GDT_UInt16 ){ return CV_16UC3; }
8383
if( gdalType == GDT_Int16 ){ return CV_16SC3; }
8484
if( gdalType == GDT_UInt32 ){ return CV_32SC3; }
@@ -256,35 +256,35 @@ void write_pixel( const double& pixelValue,
256256

257257
// input: 3 channel, output: 3 channel
258258
else if( gdalChannels == 3 && image.channels() == 3 ){
259-
if( image.depth() == CV_8U ){ image.at<Vec3b>(row,col)[channel] = newValue; }
260-
else if( image.depth() == CV_16U ){ image.ptr<Vec3s>(row,col)[channel] = newValue; }
261-
else if( image.depth() == CV_16S ){ image.ptr<Vec3s>(row,col)[channel] = newValue; }
262-
else if( image.depth() == CV_32S ){ image.ptr<Vec3i>(row,col)[channel] = newValue; }
263-
else if( image.depth() == CV_32F ){ image.ptr<Vec3f>(row,col)[channel] = newValue; }
264-
else if( image.depth() == CV_64F ){ image.ptr<Vec3d>(row,col)[channel] = newValue; }
259+
if( image.depth() == CV_8U ){ (*image.ptr<Vec3b>(row,col))[channel] = newValue; }
260+
else if( image.depth() == CV_16U ){ (*image.ptr<Vec3s>(row,col))[channel] = newValue; }
261+
else if( image.depth() == CV_16S ){ (*image.ptr<Vec3s>(row,col))[channel] = newValue; }
262+
else if( image.depth() == CV_32S ){ (*image.ptr<Vec3i>(row,col))[channel] = newValue; }
263+
else if( image.depth() == CV_32F ){ (*image.ptr<Vec3f>(row,col))[channel] = newValue; }
264+
else if( image.depth() == CV_64F ){ (*image.ptr<Vec3d>(row,col))[channel] = newValue; }
265265
else{ throw std::runtime_error("Unknown image depth, gdal: 3, image: 3"); }
266266
}
267267

268268
// input: 4 channel, output: 3 channel
269269
else if( gdalChannels == 4 && image.channels() == 3 ){
270270
if( channel >= 4 ){ return; }
271-
else if( image.depth() == CV_8U && channel < 4 ){ image.ptr<Vec3b>(row,col)[channel] = newValue; }
272-
else if( image.depth() == CV_16U && channel < 4 ){ image.ptr<Vec3s>(row,col)[channel] = newValue; }
273-
else if( image.depth() == CV_16S && channel < 4 ){ image.ptr<Vec3s>(row,col)[channel] = newValue; }
274-
else if( image.depth() == CV_32S && channel < 4 ){ image.ptr<Vec3i>(row,col)[channel] = newValue; }
275-
else if( image.depth() == CV_32F && channel < 4 ){ image.ptr<Vec3f>(row,col)[channel] = newValue; }
276-
else if( image.depth() == CV_64F && channel < 4 ){ image.ptr<Vec3d>(row,col)[channel] = newValue; }
271+
else if( image.depth() == CV_8U && channel < 4 ){ (*image.ptr<Vec3b>(row,col))[channel] = newValue; }
272+
else if( image.depth() == CV_16U && channel < 4 ){ (*image.ptr<Vec3s>(row,col))[channel] = newValue; }
273+
else if( image.depth() == CV_16S && channel < 4 ){ (*image.ptr<Vec3s>(row,col))[channel] = newValue; }
274+
else if( image.depth() == CV_32S && channel < 4 ){ (*image.ptr<Vec3i>(row,col))[channel] = newValue; }
275+
else if( image.depth() == CV_32F && channel < 4 ){ (*image.ptr<Vec3f>(row,col))[channel] = newValue; }
276+
else if( image.depth() == CV_64F && channel < 4 ){ (*image.ptr<Vec3d>(row,col))[channel] = newValue; }
277277
else{ throw std::runtime_error("Unknown image depth, gdal: 4, image: 3"); }
278278
}
279279

280280
// input: 4 channel, output: 4 channel
281281
else if( gdalChannels == 4 && image.channels() == 4 ){
282-
if( image.depth() == CV_8U ){ image.at<Vec4b>(row,col)[channel] = newValue; }
283-
else if( image.depth() == CV_16U ){ image.at<Vec4s>(row,col)[channel] = newValue; }
284-
else if( image.depth() == CV_16S ){ image.at<Vec4s>(row,col)[channel] = newValue; }
285-
else if( image.depth() == CV_32S ){ image.at<Vec4i>(row,col)[channel] = newValue; }
286-
else if( image.depth() == CV_32F ){ image.at<Vec4f>(row,col)[channel] = newValue; }
287-
else if( image.depth() == CV_64F ){ image.at<Vec4d>(row,col)[channel] = newValue; }
282+
if( image.depth() == CV_8U ){ (*image.ptr<Vec4b>(row,col))[channel] = newValue; }
283+
else if( image.depth() == CV_16U ){ (*image.ptr<Vec4s>(row,col))[channel] = newValue; }
284+
else if( image.depth() == CV_16S ){ (*image.ptr<Vec4s>(row,col))[channel] = newValue; }
285+
else if( image.depth() == CV_32S ){ (*image.ptr<Vec4i>(row,col))[channel] = newValue; }
286+
else if( image.depth() == CV_32F ){ (*image.ptr<Vec4f>(row,col))[channel] = newValue; }
287+
else if( image.depth() == CV_64F ){ (*image.ptr<Vec4d>(row,col))[channel] = newValue; }
288288
else{ throw std::runtime_error("Unknown image depth, gdal: 4, image: 4"); }
289289
}
290290

@@ -388,6 +388,30 @@ bool GdalDecoder::readData( Mat& img ){
388388
// get the GDAL Band
389389
GDALRasterBand* band = m_dataset->GetRasterBand(c+1);
390390

391+
/* Map palette band and gray band to color index 0 and red, green,
392+
blue, alpha bands to BGRA indexes. Note: ignoring HSL, CMY,
393+
CMYK, and YCbCr color spaces, rather than converting them
394+
to BGR. */
395+
int color = 0;
396+
switch (band->GetColorInterpretation()) {
397+
case GCI_PaletteIndex:
398+
case GCI_GrayIndex:
399+
case GCI_BlueBand:
400+
color = 0;
401+
break;
402+
case GCI_GreenBand:
403+
color = 1;
404+
break;
405+
case GCI_RedBand:
406+
color = 2;
407+
break;
408+
case GCI_AlphaBand:
409+
color = 3;
410+
break;
411+
default:
412+
CV_ErrorNoReturn(cv::Error::StsError, "Invalid/unsupported mode");
413+
}
414+
391415
// make sure the image band has the same dimensions as the image
392416
if( band->GetXSize() != m_width || band->GetYSize() != m_height ){ return false; }
393417

@@ -410,10 +434,10 @@ bool GdalDecoder::readData( Mat& img ){
410434
// set depending on image types
411435
// given boost, I would use enable_if to speed up. Avoid for now.
412436
if( hasColorTable == false ){
413-
write_pixel( scanline[x], gdalType, nChannels, img, y, x, c );
437+
write_pixel( scanline[x], gdalType, nChannels, img, y, x, color );
414438
}
415439
else{
416-
write_ctable_pixel( scanline[x], gdalType, gdalColorTable, img, y, x, c );
440+
write_ctable_pixel( scanline[x], gdalType, gdalColorTable, img, y, x, color );
417441
}
418442
}
419443
}

0 commit comments

Comments
 (0)