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