mirror of
https://github.com/opencv/opencv.git
synced 2024-11-24 19:20:28 +08:00
Merge pull request #10093 from gdkessler/gdal_image_read_fix_10089
Fix GDAL image decoding color problems identified by issue #10089, by: (#10093) * Fix GDAL image decoding color problems identified by issue #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.
This commit is contained in:
parent
c7f1843584
commit
2674c6b5e0
@ -78,7 +78,7 @@ int gdalPaletteInterpretation2OpenCV( GDALPaletteInterp const& paletteInterp, G
|
||||
|
||||
/// RGB
|
||||
case GPI_RGB:
|
||||
if( gdalType == GDT_Byte ){ return CV_8UC1; }
|
||||
if( gdalType == GDT_Byte ){ return CV_8UC3; }
|
||||
if( gdalType == GDT_UInt16 ){ return CV_16UC3; }
|
||||
if( gdalType == GDT_Int16 ){ return CV_16SC3; }
|
||||
if( gdalType == GDT_UInt32 ){ return CV_32SC3; }
|
||||
@ -256,35 +256,35 @@ void write_pixel( const double& pixelValue,
|
||||
|
||||
// input: 3 channel, output: 3 channel
|
||||
else if( gdalChannels == 3 && image.channels() == 3 ){
|
||||
if( image.depth() == CV_8U ){ image.at<Vec3b>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_16U ){ image.ptr<Vec3s>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_16S ){ image.ptr<Vec3s>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_32S ){ image.ptr<Vec3i>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_32F ){ image.ptr<Vec3f>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_64F ){ image.ptr<Vec3d>(row,col)[channel] = newValue; }
|
||||
if( image.depth() == CV_8U ){ (*image.ptr<Vec3b>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_16U ){ (*image.ptr<Vec3s>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_16S ){ (*image.ptr<Vec3s>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_32S ){ (*image.ptr<Vec3i>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_32F ){ (*image.ptr<Vec3f>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_64F ){ (*image.ptr<Vec3d>(row,col))[channel] = newValue; }
|
||||
else{ throw std::runtime_error("Unknown image depth, gdal: 3, image: 3"); }
|
||||
}
|
||||
|
||||
// input: 4 channel, output: 3 channel
|
||||
else if( gdalChannels == 4 && image.channels() == 3 ){
|
||||
if( channel >= 4 ){ return; }
|
||||
else if( image.depth() == CV_8U && channel < 4 ){ image.ptr<Vec3b>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_16U && channel < 4 ){ image.ptr<Vec3s>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_16S && channel < 4 ){ image.ptr<Vec3s>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_32S && channel < 4 ){ image.ptr<Vec3i>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_32F && channel < 4 ){ image.ptr<Vec3f>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_64F && channel < 4 ){ image.ptr<Vec3d>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_8U && channel < 4 ){ (*image.ptr<Vec3b>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_16U && channel < 4 ){ (*image.ptr<Vec3s>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_16S && channel < 4 ){ (*image.ptr<Vec3s>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_32S && channel < 4 ){ (*image.ptr<Vec3i>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_32F && channel < 4 ){ (*image.ptr<Vec3f>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_64F && channel < 4 ){ (*image.ptr<Vec3d>(row,col))[channel] = newValue; }
|
||||
else{ throw std::runtime_error("Unknown image depth, gdal: 4, image: 3"); }
|
||||
}
|
||||
|
||||
// input: 4 channel, output: 4 channel
|
||||
else if( gdalChannels == 4 && image.channels() == 4 ){
|
||||
if( image.depth() == CV_8U ){ image.at<Vec4b>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_16U ){ image.at<Vec4s>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_16S ){ image.at<Vec4s>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_32S ){ image.at<Vec4i>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_32F ){ image.at<Vec4f>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_64F ){ image.at<Vec4d>(row,col)[channel] = newValue; }
|
||||
if( image.depth() == CV_8U ){ (*image.ptr<Vec4b>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_16U ){ (*image.ptr<Vec4s>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_16S ){ (*image.ptr<Vec4s>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_32S ){ (*image.ptr<Vec4i>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_32F ){ (*image.ptr<Vec4f>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_64F ){ (*image.ptr<Vec4d>(row,col))[channel] = newValue; }
|
||||
else{ throw std::runtime_error("Unknown image depth, gdal: 4, image: 4"); }
|
||||
}
|
||||
|
||||
@ -388,6 +388,30 @@ bool GdalDecoder::readData( Mat& img ){
|
||||
// get the GDAL Band
|
||||
GDALRasterBand* band = m_dataset->GetRasterBand(c+1);
|
||||
|
||||
/* Map palette band and gray band to color index 0 and red, green,
|
||||
blue, alpha bands to BGRA indexes. Note: ignoring HSL, CMY,
|
||||
CMYK, and YCbCr color spaces, rather than converting them
|
||||
to BGR. */
|
||||
int color = 0;
|
||||
switch (band->GetColorInterpretation()) {
|
||||
case GCI_PaletteIndex:
|
||||
case GCI_GrayIndex:
|
||||
case GCI_BlueBand:
|
||||
color = 0;
|
||||
break;
|
||||
case GCI_GreenBand:
|
||||
color = 1;
|
||||
break;
|
||||
case GCI_RedBand:
|
||||
color = 2;
|
||||
break;
|
||||
case GCI_AlphaBand:
|
||||
color = 3;
|
||||
break;
|
||||
default:
|
||||
CV_ErrorNoReturn(cv::Error::StsError, "Invalid/unsupported mode");
|
||||
}
|
||||
|
||||
// make sure the image band has the same dimensions as the image
|
||||
if( band->GetXSize() != m_width || band->GetYSize() != m_height ){ return false; }
|
||||
|
||||
@ -410,10 +434,10 @@ bool GdalDecoder::readData( Mat& img ){
|
||||
// set depending on image types
|
||||
// given boost, I would use enable_if to speed up. Avoid for now.
|
||||
if( hasColorTable == false ){
|
||||
write_pixel( scanline[x], gdalType, nChannels, img, y, x, c );
|
||||
write_pixel( scanline[x], gdalType, nChannels, img, y, x, color );
|
||||
}
|
||||
else{
|
||||
write_ctable_pixel( scanline[x], gdalType, gdalColorTable, img, y, x, c );
|
||||
write_ctable_pixel( scanline[x], gdalType, gdalColorTable, img, y, x, color );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user