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 */
gdalPaletteInterpretation2OpenCV(GDALPaletteInterp const & paletteInterp,GDALDataType const & gdalType)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 */
gdal2opencv(const GDALDataType & gdalType,const int & channels)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 */
GdalDecoder()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 */
~GdalDecoder()165 GdalDecoder::~GdalDecoder(){
166 
167 
168     if( m_dataset != NULL ){
169        close();
170     }
171 }
172 
173 /**
174  * Convert data range
175 */
range_cast(const GDALDataType & gdalType,const int & cvDepth,const double & value)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 */
write_pixel(const double & pixelValue,const GDALDataType & gdalType,const int & gdalChannels,Mat & image,const int & row,const int & col,const int & channel)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 
write_ctable_pixel(const double & pixelValue,const GDALDataType & gdalType,GDALColorTable const * gdalColorTable,Mat & image,const int & y,const int & x,const int & c)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 */
readData(Mat & img)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 */
readHeader()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 */
close()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 */
newDecoder() const515 ImageDecoder GdalDecoder::newDecoder()const{
516     return makePtr<GdalDecoder>();
517 }
518 
519 /**
520  * Test the file signature
521 */
checkSignature(const String & signature) const522 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