Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/imgcodecs/src/grfmt_gdal.cpp
16337 views
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_8UC3; }
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
return CV_8UC(channels);
108
109
/// UInt16
110
case GDT_UInt16:
111
return CV_16UC(channels);
112
113
/// Int16
114
case GDT_Int16:
115
return CV_16SC(channels);
116
117
/// UInt32
118
case GDT_UInt32:
119
case GDT_Int32:
120
return CV_32SC(channels);
121
122
case GDT_Float32:
123
return CV_32FC(channels);
124
125
case GDT_Float64:
126
return CV_64FC(channels);
127
128
default:
129
std::cout << "Unknown GDAL Data Type" << std::endl;
130
std::cout << "Type: " << GDALGetDataTypeName(gdalType) << std::endl;
131
return -1;
132
}
133
}
134
135
/**
136
* GDAL Decoder Constructor
137
*/
138
GdalDecoder::GdalDecoder(){
139
140
// set a dummy signature
141
m_signature="0";
142
for( size_t i=0; i<160; i++ ){
143
m_signature += "0";
144
}
145
146
/// Register the driver
147
GDALAllRegister();
148
149
m_driver = NULL;
150
m_dataset = NULL;
151
}
152
153
/**
154
* GDAL Decoder Destructor
155
*/
156
GdalDecoder::~GdalDecoder(){
157
158
if( m_dataset != NULL ){
159
close();
160
}
161
}
162
163
/**
164
* Convert data range
165
*/
166
double range_cast( const GDALDataType& gdalType,
167
const int& cvDepth,
168
const double& value )
169
{
170
171
// uint8 -> uint8
172
if( gdalType == GDT_Byte && cvDepth == CV_8U ){
173
return value;
174
}
175
// uint8 -> uint16
176
if( gdalType == GDT_Byte && (cvDepth == CV_16U || cvDepth == CV_16S)){
177
return (value*256);
178
}
179
180
// uint8 -> uint32
181
if( gdalType == GDT_Byte && (cvDepth == CV_32F || cvDepth == CV_32S)){
182
return (value*16777216);
183
}
184
185
// int16 -> uint8
186
if( (gdalType == GDT_UInt16 || gdalType == GDT_Int16) && cvDepth == CV_8U ){
187
return std::floor(value/256.0);
188
}
189
190
// int16 -> int16
191
if( (gdalType == GDT_UInt16 || gdalType == GDT_Int16) &&
192
( cvDepth == CV_16U || cvDepth == CV_16S )){
193
return value;
194
}
195
196
// float32 -> float32
197
// float64 -> float64
198
if( (gdalType == GDT_Float32 || gdalType == GDT_Float64) &&
199
( cvDepth == CV_32F || cvDepth == CV_64F )){
200
return value;
201
}
202
203
std::cout << GDALGetDataTypeName( gdalType ) << std::endl;
204
std::cout << "warning: unknown range cast requested." << std::endl;
205
return (value);
206
}
207
208
209
/**
210
* There are some better mpl techniques for doing this.
211
*/
212
void write_pixel( const double& pixelValue,
213
const GDALDataType& gdalType,
214
const int& gdalChannels,
215
Mat& image,
216
const int& row,
217
const int& col,
218
const int& channel ){
219
220
// convert the pixel
221
double newValue = range_cast(gdalType, image.depth(), pixelValue );
222
223
// input: 1 channel, output: 1 channel
224
if( gdalChannels == 1 && image.channels() == 1 ){
225
if( image.depth() == CV_8U ){ image.ptr<uchar>(row)[col] = newValue; }
226
else if( image.depth() == CV_16U ){ image.ptr<unsigned short>(row)[col] = newValue; }
227
else if( image.depth() == CV_16S ){ image.ptr<short>(row)[col] = newValue; }
228
else if( image.depth() == CV_32S ){ image.ptr<int>(row)[col] = newValue; }
229
else if( image.depth() == CV_32F ){ image.ptr<float>(row)[col] = newValue; }
230
else if( image.depth() == CV_64F ){ image.ptr<double>(row)[col] = newValue; }
231
else{ throw std::runtime_error("Unknown image depth, gdal: 1, img: 1"); }
232
}
233
234
// input: 1 channel, output: 3 channel
235
else if( gdalChannels == 1 && image.channels() == 3 ){
236
if( image.depth() == CV_8U ){ image.ptr<Vec3b>(row)[col] = Vec3b(newValue,newValue,newValue); }
237
else if( image.depth() == CV_16U ){ image.ptr<Vec3s>(row)[col] = Vec3s(newValue,newValue,newValue); }
238
else if( image.depth() == CV_16S ){ image.ptr<Vec3s>(row)[col] = Vec3s(newValue,newValue,newValue); }
239
else if( image.depth() == CV_32S ){ image.ptr<Vec3i>(row)[col] = Vec3i(newValue,newValue,newValue); }
240
else if( image.depth() == CV_32F ){ image.ptr<Vec3f>(row)[col] = Vec3f(newValue,newValue,newValue); }
241
else if( image.depth() == CV_64F ){ image.ptr<Vec3d>(row)[col] = Vec3d(newValue,newValue,newValue); }
242
else{ throw std::runtime_error("Unknown image depth, gdal:1, img: 3"); }
243
}
244
245
// input: 3 channel, output: 1 channel
246
else if( gdalChannels == 3 && image.channels() == 1 ){
247
if( image.depth() == CV_8U ){ image.ptr<uchar>(row)[col] += (newValue/3.0); }
248
else{ throw std::runtime_error("Unknown image depth, gdal:3, img: 1"); }
249
}
250
251
// input: 4 channel, output: 1 channel
252
else if( gdalChannels == 4 && image.channels() == 1 ){
253
if( image.depth() == CV_8U ){ image.ptr<uchar>(row)[col] = newValue; }
254
else{ throw std::runtime_error("Unknown image depth, gdal: 4, image: 1"); }
255
}
256
257
// input: 3 channel, output: 3 channel
258
else if( gdalChannels == 3 && image.channels() == 3 ){
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; }
265
else{ throw std::runtime_error("Unknown image depth, gdal: 3, image: 3"); }
266
}
267
268
// input: 4 channel, output: 3 channel
269
else if( gdalChannels == 4 && image.channels() == 3 ){
270
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; }
277
else{ throw std::runtime_error("Unknown image depth, gdal: 4, image: 3"); }
278
}
279
280
// input: 4 channel, output: 4 channel
281
else if( gdalChannels == 4 && image.channels() == 4 ){
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; }
288
else{ throw std::runtime_error("Unknown image depth, gdal: 4, image: 4"); }
289
}
290
291
// input: > 4 channels, output: > 4 channels
292
else if( gdalChannels > 4 && image.channels() > 4 ){
293
if( image.depth() == CV_8U ){ image.ptr<uchar>(row,col)[channel] = newValue; }
294
else if( image.depth() == CV_16U ){ image.ptr<unsigned short>(row,col)[channel] = newValue; }
295
else if( image.depth() == CV_16S ){ image.ptr<short>(row,col)[channel] = newValue; }
296
else if( image.depth() == CV_32S ){ image.ptr<int>(row,col)[channel] = newValue; }
297
else if( image.depth() == CV_32F ){ image.ptr<float>(row,col)[channel] = newValue; }
298
else if( image.depth() == CV_64F ){ image.ptr<double>(row,col)[channel] = newValue; }
299
else{ throw std::runtime_error("Unknown image depth, gdal: N, img: N"); }
300
}
301
// otherwise, throw an error
302
else{
303
throw std::runtime_error("error: can't convert types.");
304
}
305
306
}
307
308
309
void write_ctable_pixel( const double& pixelValue,
310
const GDALDataType& gdalType,
311
GDALColorTable const* gdalColorTable,
312
Mat& image,
313
const int& y,
314
const int& x,
315
const int& c ){
316
317
if( gdalColorTable == NULL ){
318
write_pixel( pixelValue, gdalType, 1, image, y, x, c );
319
}
320
321
// if we are Grayscale, then do a straight conversion
322
if( gdalColorTable->GetPaletteInterpretation() == GPI_Gray ){
323
write_pixel( pixelValue, gdalType, 1, image, y, x, c );
324
}
325
326
// if we are rgb, then convert here
327
else if( gdalColorTable->GetPaletteInterpretation() == GPI_RGB ){
328
329
// get the pixel
330
short r = gdalColorTable->GetColorEntry( (int)pixelValue )->c1;
331
short g = gdalColorTable->GetColorEntry( (int)pixelValue )->c2;
332
short b = gdalColorTable->GetColorEntry( (int)pixelValue )->c3;
333
short a = gdalColorTable->GetColorEntry( (int)pixelValue )->c4;
334
335
write_pixel( r, gdalType, 4, image, y, x, 2 );
336
write_pixel( g, gdalType, 4, image, y, x, 1 );
337
write_pixel( b, gdalType, 4, image, y, x, 0 );
338
if( image.channels() > 3 ){
339
write_pixel( a, gdalType, 4, image, y, x, 1 );
340
}
341
}
342
343
// otherwise, set zeros
344
else{
345
write_pixel( pixelValue, gdalType, 1, image, y, x, c );
346
}
347
}
348
349
350
351
/**
352
* read data
353
*/
354
bool GdalDecoder::readData( Mat& img ){
355
356
357
// make sure the image is the proper size
358
if( img.size() != Size(m_width, m_height) ){
359
return false;
360
}
361
362
// make sure the raster is alive
363
if( m_dataset == NULL || m_driver == NULL ){
364
return false;
365
}
366
367
// set the image to zero
368
img = 0;
369
370
// iterate over each raster band
371
// note that OpenCV does bgr rather than rgb
372
int nChannels = m_dataset->GetRasterCount();
373
374
GDALColorTable* gdalColorTable = NULL;
375
if( m_dataset->GetRasterBand(1)->GetColorTable() != NULL ){
376
gdalColorTable = m_dataset->GetRasterBand(1)->GetColorTable();
377
}
378
379
const GDALDataType gdalType = m_dataset->GetRasterBand(1)->GetRasterDataType();
380
int nRows, nCols;
381
382
if( nChannels > img.channels() ){
383
nChannels = img.channels();
384
}
385
386
for( int c = 0; c<nChannels; c++ ){
387
388
// get the GDAL Band
389
GDALRasterBand* band = m_dataset->GetRasterBand(c+1);
390
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_Error(cv::Error::StsError, "Invalid/unsupported mode");
413
}
414
415
// make sure the image band has the same dimensions as the image
416
if( band->GetXSize() != m_width || band->GetYSize() != m_height ){ return false; }
417
418
// grab the raster size
419
nRows = band->GetYSize();
420
nCols = band->GetXSize();
421
422
// create a temporary scanline pointer to store data
423
double* scanline = new double[nCols];
424
425
// iterate over each row and column
426
for( int y=0; y<nRows; y++ ){
427
428
// get the entire row
429
CPLErr err = band->RasterIO( GF_Read, 0, y, nCols, 1, scanline, nCols, 1, GDT_Float64, 0, 0);
430
CV_Assert(err == CE_None);
431
432
// set inside the image
433
for( int x=0; x<nCols; x++ ){
434
435
// set depending on image types
436
// given boost, I would use enable_if to speed up. Avoid for now.
437
if( hasColorTable == false ){
438
write_pixel( scanline[x], gdalType, nChannels, img, y, x, color );
439
}
440
else{
441
write_ctable_pixel( scanline[x], gdalType, gdalColorTable, img, y, x, color );
442
}
443
}
444
}
445
446
// delete our temp pointer
447
delete [] scanline;
448
}
449
450
return true;
451
}
452
453
454
/**
455
* Read image header
456
*/
457
bool GdalDecoder::readHeader(){
458
459
// load the dataset
460
m_dataset = (GDALDataset*) GDALOpen( m_filename.c_str(), GA_ReadOnly);
461
462
// if dataset is null, then there was a problem
463
if( m_dataset == NULL ){
464
return false;
465
}
466
467
// make sure we have pixel data inside the raster
468
if( m_dataset->GetRasterCount() <= 0 ){
469
return false;
470
}
471
472
//extract the driver information
473
m_driver = m_dataset->GetDriver();
474
475
// if the driver failed, then exit
476
if( m_driver == NULL ){
477
return false;
478
}
479
480
481
// get the image dimensions
482
m_width = m_dataset->GetRasterXSize();
483
m_height= m_dataset->GetRasterYSize();
484
485
// make sure we have at least one band/channel
486
if( m_dataset->GetRasterCount() <= 0 ){
487
return false;
488
}
489
490
// check if we have a color palette
491
int tempType;
492
if( m_dataset->GetRasterBand(1)->GetColorInterpretation() == GCI_PaletteIndex ){
493
494
// remember that we have a color palette
495
hasColorTable = true;
496
497
// if the color tables does not exist, then we failed
498
if( m_dataset->GetRasterBand(1)->GetColorTable() == NULL ){
499
return false;
500
}
501
502
// otherwise, get the pixeltype
503
else{
504
// convert the palette interpretation to opencv type
505
tempType = gdalPaletteInterpretation2OpenCV( m_dataset->GetRasterBand(1)->GetColorTable()->GetPaletteInterpretation(),
506
m_dataset->GetRasterBand(1)->GetRasterDataType() );
507
508
if( tempType == -1 ){
509
return false;
510
}
511
m_type = tempType;
512
}
513
514
}
515
516
// otherwise, we have standard channels
517
else{
518
519
// remember that we don't have a color table
520
hasColorTable = false;
521
522
// convert the datatype to opencv
523
tempType = gdal2opencv( m_dataset->GetRasterBand(1)->GetRasterDataType(), m_dataset->GetRasterCount() );
524
if( tempType == -1 ){
525
return false;
526
}
527
m_type = tempType;
528
}
529
530
return true;
531
}
532
533
/**
534
* Close the module
535
*/
536
void GdalDecoder::close(){
537
538
539
GDALClose((GDALDatasetH)m_dataset);
540
m_dataset = NULL;
541
m_driver = NULL;
542
}
543
544
/**
545
* Create a new decoder
546
*/
547
ImageDecoder GdalDecoder::newDecoder()const{
548
return makePtr<GdalDecoder>();
549
}
550
551
/**
552
* Test the file signature
553
*/
554
bool GdalDecoder::checkSignature( const String& signature )const{
555
556
// look for NITF
557
std::string str(signature);
558
if( str.substr(0,4).find("NITF") != std::string::npos ){
559
return true;
560
}
561
562
// look for DTED
563
if( str.size() > 144 && str.substr(140,4) == "DTED" ){
564
return true;
565
}
566
567
return false;
568
}
569
570
} /// End of cv Namespace
571
572
#endif /**< End of HAVE_GDAL Definition */
573
574