Path: blob/master/modules/imgcodecs/src/grfmt_gdal.cpp
16337 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// Intel License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000, Intel Corporation, all rights reserved.13// Third party copyrights are property of their respective owners.14//15// Redistribution and use in source and binary forms, with or without modification,16// are permitted provided that the following conditions are met:17//18// * Redistribution's of source code must retain the above copyright notice,19// this list of conditions and the following disclaimer.20//21// * Redistribution's in binary form must reproduce the above copyright notice,22// this list of conditions and the following disclaimer in the documentation23// and/or other materials provided with the distribution.24//25// * The name of Intel Corporation may not be used to endorse or promote products26// derived from this software without specific prior written permission.27//28// This software is provided by the copyright holders and contributors "as is" and29// any express or implied warranties, including, but not limited to, the implied30// warranties of merchantability and fitness for a particular purpose are disclaimed.31// In no event shall the Intel Corporation or contributors be liable for any direct,32// indirect, incidental, special, exemplary, or consequential damages33// (including, but not limited to, procurement of substitute goods or services;34// loss of use, data, or profits; or business interruption) however caused35// and on any theory of liability, whether in contract, strict liability,36// or tort (including negligence or otherwise) arising in any way out of37// the use of this software, even if advised of the possibility of such damage.38//39//M*/40#include "precomp.hpp"4142// GDAL Macros43#include "cvconfig.h"4445#ifdef HAVE_GDAL4647// Our Header48#include "grfmt_gdal.hpp"495051/// C++ Standard Libraries52#include <iostream>53#include <stdexcept>54#include <string>555657namespace cv{585960/**61* Convert GDAL Palette Interpretation to OpenCV Pixel Type62*/63int gdalPaletteInterpretation2OpenCV( GDALPaletteInterp const& paletteInterp, GDALDataType const& gdalType ){6465switch( paletteInterp ){6667/// GRAYSCALE68case GPI_Gray:69if( gdalType == GDT_Byte ){ return CV_8UC1; }70if( gdalType == GDT_UInt16 ){ return CV_16UC1; }71if( gdalType == GDT_Int16 ){ return CV_16SC1; }72if( gdalType == GDT_UInt32 ){ return CV_32SC1; }73if( gdalType == GDT_Int32 ){ return CV_32SC1; }74if( gdalType == GDT_Float32 ){ return CV_32FC1; }75if( gdalType == GDT_Float64 ){ return CV_64FC1; }76return -1;7778/// RGB79case GPI_RGB:80if( gdalType == GDT_Byte ){ return CV_8UC3; }81if( gdalType == GDT_UInt16 ){ return CV_16UC3; }82if( gdalType == GDT_Int16 ){ return CV_16SC3; }83if( gdalType == GDT_UInt32 ){ return CV_32SC3; }84if( gdalType == GDT_Int32 ){ return CV_32SC3; }85if( gdalType == GDT_Float32 ){ return CV_32FC3; }86if( gdalType == GDT_Float64 ){ return CV_64FC3; }87return -1;888990/// otherwise91default:92return -1;9394}95}9697/**98* Convert gdal type to opencv type99*/100int gdal2opencv( const GDALDataType& gdalType, const int& channels ){101102switch( gdalType ){103104/// UInt8105case GDT_Byte:106return CV_8UC(channels);107108/// UInt16109case GDT_UInt16:110return CV_16UC(channels);111112/// Int16113case GDT_Int16:114return CV_16SC(channels);115116/// UInt32117case GDT_UInt32:118case GDT_Int32:119return CV_32SC(channels);120121case GDT_Float32:122return CV_32FC(channels);123124case GDT_Float64:125return CV_64FC(channels);126127default:128std::cout << "Unknown GDAL Data Type" << std::endl;129std::cout << "Type: " << GDALGetDataTypeName(gdalType) << std::endl;130return -1;131}132}133134/**135* GDAL Decoder Constructor136*/137GdalDecoder::GdalDecoder(){138139// set a dummy signature140m_signature="0";141for( size_t i=0; i<160; i++ ){142m_signature += "0";143}144145/// Register the driver146GDALAllRegister();147148m_driver = NULL;149m_dataset = NULL;150}151152/**153* GDAL Decoder Destructor154*/155GdalDecoder::~GdalDecoder(){156157if( m_dataset != NULL ){158close();159}160}161162/**163* Convert data range164*/165double range_cast( const GDALDataType& gdalType,166const int& cvDepth,167const double& value )168{169170// uint8 -> uint8171if( gdalType == GDT_Byte && cvDepth == CV_8U ){172return value;173}174// uint8 -> uint16175if( gdalType == GDT_Byte && (cvDepth == CV_16U || cvDepth == CV_16S)){176return (value*256);177}178179// uint8 -> uint32180if( gdalType == GDT_Byte && (cvDepth == CV_32F || cvDepth == CV_32S)){181return (value*16777216);182}183184// int16 -> uint8185if( (gdalType == GDT_UInt16 || gdalType == GDT_Int16) && cvDepth == CV_8U ){186return std::floor(value/256.0);187}188189// int16 -> int16190if( (gdalType == GDT_UInt16 || gdalType == GDT_Int16) &&191( cvDepth == CV_16U || cvDepth == CV_16S )){192return value;193}194195// float32 -> float32196// float64 -> float64197if( (gdalType == GDT_Float32 || gdalType == GDT_Float64) &&198( cvDepth == CV_32F || cvDepth == CV_64F )){199return value;200}201202std::cout << GDALGetDataTypeName( gdalType ) << std::endl;203std::cout << "warning: unknown range cast requested." << std::endl;204return (value);205}206207208/**209* There are some better mpl techniques for doing this.210*/211void write_pixel( const double& pixelValue,212const GDALDataType& gdalType,213const int& gdalChannels,214Mat& image,215const int& row,216const int& col,217const int& channel ){218219// convert the pixel220double newValue = range_cast(gdalType, image.depth(), pixelValue );221222// input: 1 channel, output: 1 channel223if( gdalChannels == 1 && image.channels() == 1 ){224if( image.depth() == CV_8U ){ image.ptr<uchar>(row)[col] = newValue; }225else if( image.depth() == CV_16U ){ image.ptr<unsigned short>(row)[col] = newValue; }226else if( image.depth() == CV_16S ){ image.ptr<short>(row)[col] = newValue; }227else if( image.depth() == CV_32S ){ image.ptr<int>(row)[col] = newValue; }228else if( image.depth() == CV_32F ){ image.ptr<float>(row)[col] = newValue; }229else if( image.depth() == CV_64F ){ image.ptr<double>(row)[col] = newValue; }230else{ throw std::runtime_error("Unknown image depth, gdal: 1, img: 1"); }231}232233// input: 1 channel, output: 3 channel234else if( gdalChannels == 1 && image.channels() == 3 ){235if( image.depth() == CV_8U ){ image.ptr<Vec3b>(row)[col] = Vec3b(newValue,newValue,newValue); }236else if( image.depth() == CV_16U ){ image.ptr<Vec3s>(row)[col] = Vec3s(newValue,newValue,newValue); }237else if( image.depth() == CV_16S ){ image.ptr<Vec3s>(row)[col] = Vec3s(newValue,newValue,newValue); }238else if( image.depth() == CV_32S ){ image.ptr<Vec3i>(row)[col] = Vec3i(newValue,newValue,newValue); }239else if( image.depth() == CV_32F ){ image.ptr<Vec3f>(row)[col] = Vec3f(newValue,newValue,newValue); }240else if( image.depth() == CV_64F ){ image.ptr<Vec3d>(row)[col] = Vec3d(newValue,newValue,newValue); }241else{ throw std::runtime_error("Unknown image depth, gdal:1, img: 3"); }242}243244// input: 3 channel, output: 1 channel245else if( gdalChannels == 3 && image.channels() == 1 ){246if( image.depth() == CV_8U ){ image.ptr<uchar>(row)[col] += (newValue/3.0); }247else{ throw std::runtime_error("Unknown image depth, gdal:3, img: 1"); }248}249250// input: 4 channel, output: 1 channel251else if( gdalChannels == 4 && image.channels() == 1 ){252if( image.depth() == CV_8U ){ image.ptr<uchar>(row)[col] = newValue; }253else{ throw std::runtime_error("Unknown image depth, gdal: 4, image: 1"); }254}255256// input: 3 channel, output: 3 channel257else if( gdalChannels == 3 && image.channels() == 3 ){258if( image.depth() == CV_8U ){ (*image.ptr<Vec3b>(row,col))[channel] = newValue; }259else if( image.depth() == CV_16U ){ (*image.ptr<Vec3s>(row,col))[channel] = newValue; }260else if( image.depth() == CV_16S ){ (*image.ptr<Vec3s>(row,col))[channel] = newValue; }261else if( image.depth() == CV_32S ){ (*image.ptr<Vec3i>(row,col))[channel] = newValue; }262else if( image.depth() == CV_32F ){ (*image.ptr<Vec3f>(row,col))[channel] = newValue; }263else if( image.depth() == CV_64F ){ (*image.ptr<Vec3d>(row,col))[channel] = newValue; }264else{ throw std::runtime_error("Unknown image depth, gdal: 3, image: 3"); }265}266267// input: 4 channel, output: 3 channel268else if( gdalChannels == 4 && image.channels() == 3 ){269if( channel >= 4 ){ return; }270else if( image.depth() == CV_8U && channel < 4 ){ (*image.ptr<Vec3b>(row,col))[channel] = newValue; }271else if( image.depth() == CV_16U && channel < 4 ){ (*image.ptr<Vec3s>(row,col))[channel] = newValue; }272else if( image.depth() == CV_16S && channel < 4 ){ (*image.ptr<Vec3s>(row,col))[channel] = newValue; }273else if( image.depth() == CV_32S && channel < 4 ){ (*image.ptr<Vec3i>(row,col))[channel] = newValue; }274else if( image.depth() == CV_32F && channel < 4 ){ (*image.ptr<Vec3f>(row,col))[channel] = newValue; }275else if( image.depth() == CV_64F && channel < 4 ){ (*image.ptr<Vec3d>(row,col))[channel] = newValue; }276else{ throw std::runtime_error("Unknown image depth, gdal: 4, image: 3"); }277}278279// input: 4 channel, output: 4 channel280else if( gdalChannels == 4 && image.channels() == 4 ){281if( image.depth() == CV_8U ){ (*image.ptr<Vec4b>(row,col))[channel] = newValue; }282else if( image.depth() == CV_16U ){ (*image.ptr<Vec4s>(row,col))[channel] = newValue; }283else if( image.depth() == CV_16S ){ (*image.ptr<Vec4s>(row,col))[channel] = newValue; }284else if( image.depth() == CV_32S ){ (*image.ptr<Vec4i>(row,col))[channel] = newValue; }285else if( image.depth() == CV_32F ){ (*image.ptr<Vec4f>(row,col))[channel] = newValue; }286else if( image.depth() == CV_64F ){ (*image.ptr<Vec4d>(row,col))[channel] = newValue; }287else{ throw std::runtime_error("Unknown image depth, gdal: 4, image: 4"); }288}289290// input: > 4 channels, output: > 4 channels291else if( gdalChannels > 4 && image.channels() > 4 ){292if( image.depth() == CV_8U ){ image.ptr<uchar>(row,col)[channel] = newValue; }293else if( image.depth() == CV_16U ){ image.ptr<unsigned short>(row,col)[channel] = newValue; }294else if( image.depth() == CV_16S ){ image.ptr<short>(row,col)[channel] = newValue; }295else if( image.depth() == CV_32S ){ image.ptr<int>(row,col)[channel] = newValue; }296else if( image.depth() == CV_32F ){ image.ptr<float>(row,col)[channel] = newValue; }297else if( image.depth() == CV_64F ){ image.ptr<double>(row,col)[channel] = newValue; }298else{ throw std::runtime_error("Unknown image depth, gdal: N, img: N"); }299}300// otherwise, throw an error301else{302throw std::runtime_error("error: can't convert types.");303}304305}306307308void write_ctable_pixel( const double& pixelValue,309const GDALDataType& gdalType,310GDALColorTable const* gdalColorTable,311Mat& image,312const int& y,313const int& x,314const int& c ){315316if( gdalColorTable == NULL ){317write_pixel( pixelValue, gdalType, 1, image, y, x, c );318}319320// if we are Grayscale, then do a straight conversion321if( gdalColorTable->GetPaletteInterpretation() == GPI_Gray ){322write_pixel( pixelValue, gdalType, 1, image, y, x, c );323}324325// if we are rgb, then convert here326else if( gdalColorTable->GetPaletteInterpretation() == GPI_RGB ){327328// get the pixel329short r = gdalColorTable->GetColorEntry( (int)pixelValue )->c1;330short g = gdalColorTable->GetColorEntry( (int)pixelValue )->c2;331short b = gdalColorTable->GetColorEntry( (int)pixelValue )->c3;332short a = gdalColorTable->GetColorEntry( (int)pixelValue )->c4;333334write_pixel( r, gdalType, 4, image, y, x, 2 );335write_pixel( g, gdalType, 4, image, y, x, 1 );336write_pixel( b, gdalType, 4, image, y, x, 0 );337if( image.channels() > 3 ){338write_pixel( a, gdalType, 4, image, y, x, 1 );339}340}341342// otherwise, set zeros343else{344write_pixel( pixelValue, gdalType, 1, image, y, x, c );345}346}347348349350/**351* read data352*/353bool GdalDecoder::readData( Mat& img ){354355356// make sure the image is the proper size357if( img.size() != Size(m_width, m_height) ){358return false;359}360361// make sure the raster is alive362if( m_dataset == NULL || m_driver == NULL ){363return false;364}365366// set the image to zero367img = 0;368369// iterate over each raster band370// note that OpenCV does bgr rather than rgb371int nChannels = m_dataset->GetRasterCount();372373GDALColorTable* gdalColorTable = NULL;374if( m_dataset->GetRasterBand(1)->GetColorTable() != NULL ){375gdalColorTable = m_dataset->GetRasterBand(1)->GetColorTable();376}377378const GDALDataType gdalType = m_dataset->GetRasterBand(1)->GetRasterDataType();379int nRows, nCols;380381if( nChannels > img.channels() ){382nChannels = img.channels();383}384385for( int c = 0; c<nChannels; c++ ){386387// get the GDAL Band388GDALRasterBand* band = m_dataset->GetRasterBand(c+1);389390/* Map palette band and gray band to color index 0 and red, green,391blue, alpha bands to BGRA indexes. Note: ignoring HSL, CMY,392CMYK, and YCbCr color spaces, rather than converting them393to BGR. */394int color = 0;395switch (band->GetColorInterpretation()) {396case GCI_PaletteIndex:397case GCI_GrayIndex:398case GCI_BlueBand:399color = 0;400break;401case GCI_GreenBand:402color = 1;403break;404case GCI_RedBand:405color = 2;406break;407case GCI_AlphaBand:408color = 3;409break;410default:411CV_Error(cv::Error::StsError, "Invalid/unsupported mode");412}413414// make sure the image band has the same dimensions as the image415if( band->GetXSize() != m_width || band->GetYSize() != m_height ){ return false; }416417// grab the raster size418nRows = band->GetYSize();419nCols = band->GetXSize();420421// create a temporary scanline pointer to store data422double* scanline = new double[nCols];423424// iterate over each row and column425for( int y=0; y<nRows; y++ ){426427// get the entire row428CPLErr err = band->RasterIO( GF_Read, 0, y, nCols, 1, scanline, nCols, 1, GDT_Float64, 0, 0);429CV_Assert(err == CE_None);430431// set inside the image432for( int x=0; x<nCols; x++ ){433434// set depending on image types435// given boost, I would use enable_if to speed up. Avoid for now.436if( hasColorTable == false ){437write_pixel( scanline[x], gdalType, nChannels, img, y, x, color );438}439else{440write_ctable_pixel( scanline[x], gdalType, gdalColorTable, img, y, x, color );441}442}443}444445// delete our temp pointer446delete [] scanline;447}448449return true;450}451452453/**454* Read image header455*/456bool GdalDecoder::readHeader(){457458// load the dataset459m_dataset = (GDALDataset*) GDALOpen( m_filename.c_str(), GA_ReadOnly);460461// if dataset is null, then there was a problem462if( m_dataset == NULL ){463return false;464}465466// make sure we have pixel data inside the raster467if( m_dataset->GetRasterCount() <= 0 ){468return false;469}470471//extract the driver information472m_driver = m_dataset->GetDriver();473474// if the driver failed, then exit475if( m_driver == NULL ){476return false;477}478479480// get the image dimensions481m_width = m_dataset->GetRasterXSize();482m_height= m_dataset->GetRasterYSize();483484// make sure we have at least one band/channel485if( m_dataset->GetRasterCount() <= 0 ){486return false;487}488489// check if we have a color palette490int tempType;491if( m_dataset->GetRasterBand(1)->GetColorInterpretation() == GCI_PaletteIndex ){492493// remember that we have a color palette494hasColorTable = true;495496// if the color tables does not exist, then we failed497if( m_dataset->GetRasterBand(1)->GetColorTable() == NULL ){498return false;499}500501// otherwise, get the pixeltype502else{503// convert the palette interpretation to opencv type504tempType = gdalPaletteInterpretation2OpenCV( m_dataset->GetRasterBand(1)->GetColorTable()->GetPaletteInterpretation(),505m_dataset->GetRasterBand(1)->GetRasterDataType() );506507if( tempType == -1 ){508return false;509}510m_type = tempType;511}512513}514515// otherwise, we have standard channels516else{517518// remember that we don't have a color table519hasColorTable = false;520521// convert the datatype to opencv522tempType = gdal2opencv( m_dataset->GetRasterBand(1)->GetRasterDataType(), m_dataset->GetRasterCount() );523if( tempType == -1 ){524return false;525}526m_type = tempType;527}528529return true;530}531532/**533* Close the module534*/535void GdalDecoder::close(){536537538GDALClose((GDALDatasetH)m_dataset);539m_dataset = NULL;540m_driver = NULL;541}542543/**544* Create a new decoder545*/546ImageDecoder GdalDecoder::newDecoder()const{547return makePtr<GdalDecoder>();548}549550/**551* Test the file signature552*/553bool GdalDecoder::checkSignature( const String& signature )const{554555// look for NITF556std::string str(signature);557if( str.substr(0,4).find("NITF") != std::string::npos ){558return true;559}560561// look for DTED562if( str.size() > 144 && str.substr(140,4) == "DTED" ){563return true;564}565566return false;567}568569} /// End of cv Namespace570571#endif /**< End of HAVE_GDAL Definition */572573574