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 // Intel License Agreement 11 // For Open Source Computer Vision Library 12 // 13 // Copyright (C) 2000, Intel Corporation, all rights reserved. 14 // Third party copyrights are property of their respective owners. 15 // 16 // Redistribution and use in source and binary forms, with or without modification, 17 // are permitted provided that the following conditions are met: 18 // 19 // * Redistribution's of source code must retain the above copyright notice, 20 // this list of conditions and the following disclaimer. 21 // 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. 25 // 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. 28 // 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. 39 // 40 //M*/ 41 #include "precomp.hpp" 42 43 // GDAL Macros 44 #include "cvconfig.h" 45 46 #ifdef HAVE_GDAL 47 48 // Our Header 49 #include "grfmt_gdal.hpp" 50 51 52 /// C++ Standard Libraries 53 #include <iostream> 54 #include <stdexcept> 55 #include <string> 56 57 58 namespace cv{ 59 60 61 /** 62 * Convert GDAL Palette Interpretation to OpenCV Pixel Type 63 */ 64 int gdalPaletteInterpretation2OpenCV( GDALPaletteInterp const& paletteInterp, GDALDataType const& gdalType ){ 65 66 switch( paletteInterp ){ 67 68 /// GRAYSCALE 69 case GPI_Gray: 70 if( gdalType == GDT_Byte ){ return CV_8UC1; } 71 if( gdalType == GDT_UInt16 ){ return CV_16UC1; } 72 if( gdalType == GDT_Int16 ){ return CV_16SC1; } 73 if( gdalType == GDT_UInt32 ){ return CV_32SC1; } 74 if( gdalType == GDT_Int32 ){ return CV_32SC1; } 75 if( gdalType == GDT_Float32 ){ return CV_32FC1; } 76 if( gdalType == GDT_Float64 ){ return CV_64FC1; } 77 return -1; 78 79 /// RGB 80 case GPI_RGB: 81 if( gdalType == GDT_Byte ){ return CV_8UC1; } 82 if( gdalType == GDT_UInt16 ){ return CV_16UC3; } 83 if( gdalType == GDT_Int16 ){ return CV_16SC3; } 84 if( gdalType == GDT_UInt32 ){ return CV_32SC3; } 85 if( gdalType == GDT_Int32 ){ return CV_32SC3; } 86 if( gdalType == GDT_Float32 ){ return CV_32FC3; } 87 if( gdalType == GDT_Float64 ){ return CV_64FC3; } 88 return -1; 89 90 91 /// otherwise 92 default: 93 return -1; 94 95 } 96 } 97 98 /** 99 * Convert gdal type to opencv type 100 */ 101 int gdal2opencv( const GDALDataType& gdalType, const int& channels ){ 102 103 switch( gdalType ){ 104 105 /// UInt8 106 case GDT_Byte: 107 if( channels == 1 ){ return CV_8UC1; } 108 if( channels == 3 ){ return CV_8UC3; } 109 if( channels == 4 ){ return CV_8UC4; } 110 return -1; 111 112 /// UInt16 113 case GDT_UInt16: 114 if( channels == 1 ){ return CV_16UC1; } 115 if( channels == 3 ){ return CV_16UC3; } 116 if( channels == 4 ){ return CV_16UC4; } 117 return -1; 118 119 /// Int16 120 case GDT_Int16: 121 if( channels == 1 ){ return CV_16SC1; } 122 if( channels == 3 ){ return CV_16SC3; } 123 if( channels == 4 ){ return CV_16SC4; } 124 return -1; 125 126 /// UInt32 127 case GDT_UInt32: 128 case GDT_Int32: 129 if( channels == 1 ){ return CV_32SC1; } 130 if( channels == 3 ){ return CV_32SC3; } 131 if( channels == 4 ){ return CV_32SC4; } 132 return -1; 133 134 default: 135 std::cout << "Unknown GDAL Data Type" << std::endl; 136 std::cout << "Type: " << GDALGetDataTypeName(gdalType) << std::endl; 137 return -1; 138 } 139 140 return -1; 141 } 142 143 /** 144 * GDAL Decoder Constructor 145 */ 146 GdalDecoder::GdalDecoder(){ 147 148 149 // set a dummy signature 150 m_signature="0"; 151 for( size_t i=0; i<160; i++ ){ 152 m_signature += "0"; 153 } 154 155 /// Register the driver 156 GDALAllRegister(); 157 158 m_driver = NULL; 159 m_dataset = NULL; 160 } 161 162 /** 163 * GDAL Decoder Destructor 164 */ 165 GdalDecoder::~GdalDecoder(){ 166 167 168 if( m_dataset != NULL ){ 169 close(); 170 } 171 } 172 173 /** 174 * Convert data range 175 */ 176 double range_cast( const GDALDataType& gdalType, 177 const int& cvDepth, 178 const double& value ) 179 { 180 181 // uint8 -> uint8 182 if( gdalType == GDT_Byte && cvDepth == CV_8U ){ 183 return value; 184 } 185 // uint8 -> uint16 186 if( gdalType == GDT_Byte && (cvDepth == CV_16U || cvDepth == CV_16S)){ 187 return (value*256); 188 } 189 190 // uint8 -> uint32 191 if( gdalType == GDT_Byte && (cvDepth == CV_32F || cvDepth == CV_32S)){ 192 return (value*16777216); 193 } 194 195 // int16 -> uint8 196 if( (gdalType == GDT_UInt16 || gdalType == GDT_Int16) && cvDepth == CV_8U ){ 197 return std::floor(value/256.0); 198 } 199 200 // int16 -> int16 201 if( (gdalType == GDT_UInt16 || gdalType == GDT_Int16) && 202 ( cvDepth == CV_16U || cvDepth == CV_16S )){ 203 return value; 204 } 205 206 std::cout << GDALGetDataTypeName( gdalType ) << std::endl; 207 std::cout << "warning: unknown range cast requested." << std::endl; 208 return (value); 209 } 210 211 212 /** 213 * There are some better mpl techniques for doing this. 214 */ 215 void write_pixel( const double& pixelValue, 216 const GDALDataType& gdalType, 217 const int& gdalChannels, 218 Mat& image, 219 const int& row, 220 const int& col, 221 const int& channel ){ 222 223 // convert the pixel 224 double newValue = range_cast(gdalType, image.depth(), pixelValue ); 225 226 // input: 1 channel, output: 1 channel 227 if( gdalChannels == 1 && image.channels() == 1 ){ 228 if( image.depth() == CV_8U ){ image.at<uchar>(row,col) = newValue; } 229 else if( image.depth() == CV_16U ){ image.at<unsigned short>(row,col) = newValue; } 230 else if( image.depth() == CV_16S ){ image.at<short>(row,col) = newValue; } 231 else if( image.depth() == CV_32S ){ image.at<int>(row,col) = newValue; } 232 else if( image.depth() == CV_32F ){ image.at<float>(row,col) = newValue; } 233 else if( image.depth() == CV_64F ){ image.at<double>(row,col) = newValue; } 234 else{ throw std::runtime_error("Unknown image depth, gdal: 1, img: 1"); } 235 } 236 237 // input: 1 channel, output: 3 channel 238 else if( gdalChannels == 1 && image.channels() == 3 ){ 239 if( image.depth() == CV_8U ){ image.at<Vec3b>(row,col) = Vec3b(newValue,newValue,newValue); } 240 else if( image.depth() == CV_16U ){ image.at<Vec3s>(row,col) = Vec3s(newValue,newValue,newValue); } 241 else if( image.depth() == CV_16S ){ image.at<Vec3s>(row,col) = Vec3s(newValue,newValue,newValue); } 242 else if( image.depth() == CV_32S ){ image.at<Vec3i>(row,col) = Vec3i(newValue,newValue,newValue); } 243 else if( image.depth() == CV_32F ){ image.at<Vec3f>(row,col) = Vec3f(newValue,newValue,newValue); } 244 else if( image.depth() == CV_64F ){ image.at<Vec3d>(row,col) = Vec3d(newValue,newValue,newValue); } 245 else{ throw std::runtime_error("Unknown image depth, gdal:1, img: 3"); } 246 } 247 248 // input: 3 channel, output: 1 channel 249 else if( gdalChannels == 3 && image.channels() == 1 ){ 250 if( image.depth() == CV_8U ){ image.at<uchar>(row,col) += (newValue/3.0); } 251 else{ throw std::runtime_error("Unknown image depth, gdal:3, img: 1"); } 252 } 253 254 // input: 4 channel, output: 1 channel 255 else if( gdalChannels == 4 && image.channels() == 1 ){ 256 if( image.depth() == CV_8U ){ image.at<uchar>(row,col) = newValue; } 257 else{ throw std::runtime_error("Unknown image depth, gdal: 4, image: 1"); } 258 } 259 260 // input: 3 channel, output: 3 channel 261 else if( gdalChannels == 3 && image.channels() == 3 ){ 262 if( image.depth() == CV_8U ){ image.at<Vec3b>(row,col)[channel] = newValue; } 263 else if( image.depth() == CV_16U ){ image.at<Vec3s>(row,col)[channel] = newValue; } 264 else if( image.depth() == CV_16S ){ image.at<Vec3s>(row,col)[channel] = newValue; } 265 else if( image.depth() == CV_32S ){ image.at<Vec3i>(row,col)[channel] = newValue; } 266 else if( image.depth() == CV_32F ){ image.at<Vec3f>(row,col)[channel] = newValue; } 267 else if( image.depth() == CV_64F ){ image.at<Vec3d>(row,col)[channel] = newValue; } 268 else{ throw std::runtime_error("Unknown image depth, gdal: 3, image: 3"); } 269 } 270 271 // input: 4 channel, output: 3 channel 272 else if( gdalChannels == 4 && image.channels() == 3 ){ 273 if( channel >= 4 ){ return; } 274 else if( image.depth() == CV_8U && channel < 4 ){ image.at<Vec3b>(row,col)[channel] = newValue; } 275 else if( image.depth() == CV_16U && channel < 4 ){ image.at<Vec3s>(row,col)[channel] = newValue; } 276 else if( image.depth() == CV_16S && channel < 4 ){ image.at<Vec3s>(row,col)[channel] = newValue; } 277 else if( image.depth() == CV_32S && channel < 4 ){ image.at<Vec3i>(row,col)[channel] = newValue; } 278 else if( image.depth() == CV_32F && channel < 4 ){ image.at<Vec3f>(row,col)[channel] = newValue; } 279 else if( image.depth() == CV_64F && channel < 4 ){ image.at<Vec3d>(row,col)[channel] = newValue; } 280 else{ throw std::runtime_error("Unknown image depth, gdal: 4, image: 3"); } 281 } 282 283 // input: 4 channel, output: 4 channel 284 else if( gdalChannels == 4 && image.channels() == 4 ){ 285 if( image.depth() == CV_8U ){ image.at<Vec4b>(row,col)[channel] = newValue; } 286 else{ throw std::runtime_error("Unknown image depth, gdal: 4, image: 4"); } 287 } 288 289 // otherwise, throw an error 290 else{ 291 throw std::runtime_error("error: can't convert types."); 292 } 293 294 } 295 296 297 void write_ctable_pixel( const double& pixelValue, 298 const GDALDataType& gdalType, 299 GDALColorTable const* gdalColorTable, 300 Mat& image, 301 const int& y, 302 const int& x, 303 const int& c ){ 304 305 if( gdalColorTable == NULL ){ 306 write_pixel( pixelValue, gdalType, 1, image, y, x, c ); 307 } 308 309 // if we are Grayscale, then do a straight conversion 310 if( gdalColorTable->GetPaletteInterpretation() == GPI_Gray ){ 311 write_pixel( pixelValue, gdalType, 1, image, y, x, c ); 312 } 313 314 // if we are rgb, then convert here 315 else if( gdalColorTable->GetPaletteInterpretation() == GPI_RGB ){ 316 317 // get the pixel 318 short r = gdalColorTable->GetColorEntry( (int)pixelValue )->c1; 319 short g = gdalColorTable->GetColorEntry( (int)pixelValue )->c2; 320 short b = gdalColorTable->GetColorEntry( (int)pixelValue )->c3; 321 short a = gdalColorTable->GetColorEntry( (int)pixelValue )->c4; 322 323 write_pixel( r, gdalType, 4, image, y, x, 2 ); 324 write_pixel( g, gdalType, 4, image, y, x, 1 ); 325 write_pixel( b, gdalType, 4, image, y, x, 0 ); 326 if( image.channels() > 3 ){ 327 write_pixel( a, gdalType, 4, image, y, x, 1 ); 328 } 329 } 330 331 // otherwise, set zeros 332 else{ 333 write_pixel( pixelValue, gdalType, 1, image, y, x, c ); 334 } 335 } 336 337 338 339 /** 340 * read data 341 */ 342 bool GdalDecoder::readData( Mat& img ){ 343 344 345 // make sure the image is the proper size 346 if( img.size().height != m_height ){ 347 return false; 348 } 349 if( img.size().width != m_width ){ 350 return false; 351 } 352 353 // make sure the raster is alive 354 if( m_dataset == NULL || m_driver == NULL ){ 355 return false; 356 } 357 358 // set the image to zero 359 img = 0; 360 361 362 // iterate over each raster band 363 // note that OpenCV does bgr rather than rgb 364 int nChannels = m_dataset->GetRasterCount(); 365 GDALColorTable* gdalColorTable = NULL; 366 if( m_dataset->GetRasterBand(1)->GetColorTable() != NULL ){ 367 gdalColorTable = m_dataset->GetRasterBand(1)->GetColorTable(); 368 } 369 370 const GDALDataType gdalType = m_dataset->GetRasterBand(1)->GetRasterDataType(); 371 int nRows, nCols; 372 373 if( nChannels > img.channels() ){ 374 nChannels = img.channels(); 375 } 376 377 for( int c = 0; c<nChannels; c++ ){ 378 379 // get the GDAL Band 380 GDALRasterBand* band = m_dataset->GetRasterBand(c+1); 381 382 // make sure the image band has the same dimensions as the image 383 if( band->GetXSize() != m_width || band->GetYSize() != m_height ){ return false; } 384 385 // grab the raster size 386 nRows = band->GetYSize(); 387 nCols = band->GetXSize(); 388 389 // create a temporary scanline pointer to store data 390 double* scanline = new double[nCols]; 391 392 // iterate over each row and column 393 for( int y=0; y<nRows; y++ ){ 394 395 // get the entire row 396 band->RasterIO( GF_Read, 0, y, nCols, 1, scanline, nCols, 1, GDT_Float64, 0, 0); 397 398 // set inside the image 399 for( int x=0; x<nCols; x++ ){ 400 401 // set depending on image types 402 // given boost, I would use enable_if to speed up. Avoid for now. 403 if( hasColorTable == false ){ 404 write_pixel( scanline[x], gdalType, nChannels, img, y, x, c ); 405 } 406 else{ 407 write_ctable_pixel( scanline[x], gdalType, gdalColorTable, img, y, x, c ); 408 } 409 } 410 } 411 412 // delete our temp pointer 413 delete [] scanline; 414 415 416 } 417 418 return true; 419 } 420 421 422 /** 423 * Read image header 424 */ 425 bool GdalDecoder::readHeader(){ 426 427 // load the dataset 428 m_dataset = (GDALDataset*) GDALOpen( m_filename.c_str(), GA_ReadOnly); 429 430 // if dataset is null, then there was a problem 431 if( m_dataset == NULL ){ 432 return false; 433 } 434 435 // make sure we have pixel data inside the raster 436 if( m_dataset->GetRasterCount() <= 0 ){ 437 return false; 438 } 439 440 //extract the driver infomation 441 m_driver = m_dataset->GetDriver(); 442 443 // if the driver failed, then exit 444 if( m_driver == NULL ){ 445 return false; 446 } 447 448 449 // get the image dimensions 450 m_width = m_dataset->GetRasterXSize(); 451 m_height= m_dataset->GetRasterYSize(); 452 453 // make sure we have at least one band/channel 454 if( m_dataset->GetRasterCount() <= 0 ){ 455 return false; 456 } 457 458 // check if we have a color palette 459 int tempType; 460 if( m_dataset->GetRasterBand(1)->GetColorInterpretation() == GCI_PaletteIndex ){ 461 462 // remember that we have a color palette 463 hasColorTable = true; 464 465 // if the color tables does not exist, then we failed 466 if( m_dataset->GetRasterBand(1)->GetColorTable() == NULL ){ 467 return false; 468 } 469 470 // otherwise, get the pixeltype 471 else{ 472 // convert the palette interpretation to opencv type 473 tempType = gdalPaletteInterpretation2OpenCV( m_dataset->GetRasterBand(1)->GetColorTable()->GetPaletteInterpretation(), 474 m_dataset->GetRasterBand(1)->GetRasterDataType() ); 475 476 if( tempType == -1 ){ 477 return false; 478 } 479 m_type = tempType; 480 } 481 482 } 483 484 // otherwise, we have standard channels 485 else{ 486 487 // remember that we don't have a color table 488 hasColorTable = false; 489 490 // convert the datatype to opencv 491 tempType = gdal2opencv( m_dataset->GetRasterBand(1)->GetRasterDataType(), m_dataset->GetRasterCount() ); 492 if( tempType == -1 ){ 493 return false; 494 } 495 m_type = tempType; 496 } 497 498 return true; 499 } 500 501 /** 502 * Close the module 503 */ 504 void GdalDecoder::close(){ 505 506 507 GDALClose((GDALDatasetH)m_dataset); 508 m_dataset = NULL; 509 m_driver = NULL; 510 } 511 512 /** 513 * Create a new decoder 514 */ 515 ImageDecoder GdalDecoder::newDecoder()const{ 516 return makePtr<GdalDecoder>(); 517 } 518 519 /** 520 * Test the file signature 521 */ 522 bool GdalDecoder::checkSignature( const String& signature )const{ 523 524 525 // look for NITF 526 std::string str = signature.c_str(); 527 if( str.substr(0,4).find("NITF") != std::string::npos ){ 528 return true; 529 } 530 531 // look for DTED 532 if( str.substr(140,4) == "DTED" ){ 533 return true; 534 } 535 536 return false; 537 } 538 539 } /// End of cv Namespace 540 541 #endif /**< End of HAVE_GDAL Definition */ 542