From a984a78fd49314451532966180d6fc773ba36754 Mon Sep 17 00:00:00 2001 From: Julien Michel Date: Mon, 4 Jul 2016 14:25:11 +0200 Subject: [PATCH] ENH: Adding a complex derived dataset to allow for on-the-fly computation of amplitude while reading --- gdal/frmts/cderived/GNUmakefile | 11 ++ gdal/frmts/cderived/cderiveddataset.cpp | 195 ++++++++++++++++++++++++ gdal/frmts/gdalallregister.cpp | 1 + gdal/gcore/gdal_frmts.h | 1 + 4 files changed, 208 insertions(+) create mode 100644 gdal/frmts/cderived/GNUmakefile create mode 100644 gdal/frmts/cderived/cderiveddataset.cpp diff --git a/gdal/frmts/cderived/GNUmakefile b/gdal/frmts/cderived/GNUmakefile new file mode 100644 index 000000000000..dd9b946208a7 --- /dev/null +++ b/gdal/frmts/cderived/GNUmakefile @@ -0,0 +1,11 @@ + +include ../../GDALmake.opt + +OBJ = cderiveddataset.o + +default: $(OBJ:.o=.$(OBJ_EXT)) + +clean: + rm -f *.o $(O_OBJ) + +install-obj: $(O_OBJ:.o=.$(OBJ_EXT)) diff --git a/gdal/frmts/cderived/cderiveddataset.cpp b/gdal/frmts/cderived/cderiveddataset.cpp new file mode 100644 index 000000000000..1fbb8c420acc --- /dev/null +++ b/gdal/frmts/cderived/cderiveddataset.cpp @@ -0,0 +1,195 @@ +#include "../vrt/vrtdataset.h" +#include "gdal_pam.h" +#include "gdal_proxy.h" + +#include + +CPLErr ModulePixelFunc(void **papoSources, int nSources, void *pData, + int nXSize, int nYSize, + GDALDataType eSrcType, GDALDataType eBufType, + int nPixelSpace, int nLineSpace) +{ + int ii, iLine, iCol; + double dfPixVal; + + /* ---- Init ---- */ + if (nSources != 1) return CE_Failure; + + if (GDALDataTypeIsComplex( eSrcType )) + { + double dfReal, dfImag; + void *pReal = papoSources[0]; + void *pImag = ((GByte *)papoSources[0]) + + GDALGetDataTypeSize( eSrcType ) / 8 / 2; + + /* ---- Set pixels ---- */ + for( iLine = 0, ii = 0; iLine < nYSize; ++iLine ) { + for( iCol = 0; iCol < nXSize; ++iCol, ++ii ) { + + /* Source raster pixels may be obtained with SRCVAL macro */ + dfReal = SRCVAL(pReal, eSrcType, ii); + dfImag = SRCVAL(pImag, eSrcType, ii); + + dfPixVal = sqrt( dfReal * dfReal + dfImag * dfImag ); + + GDALCopyWords(&dfPixVal, GDT_Float64, 0, + ((GByte *)pData) + nLineSpace * iLine + + iCol * nPixelSpace, eBufType, nPixelSpace, 1); + } + } + } else { + /* ---- Set pixels ---- */ + for( iLine = 0, ii = 0; iLine < nYSize; ++iLine ) { + for( iCol = 0; iCol < nXSize; ++iCol, ++ii ) { + + /* Source raster pixels may be obtained with SRCVAL macro */ + dfPixVal = fabs(SRCVAL(papoSources[0], eSrcType, ii)); + + GDALCopyWords(&dfPixVal, GDT_Float64, 0, + ((GByte *)pData) + nLineSpace * iLine + + iCol * nPixelSpace, eBufType, nPixelSpace, 1); + } + } + } + + /* ---- Return success ---- */ + return CE_None; +} /* ModulePixelFunc */ + + +class ComplexDerivedDatasetContainer: public GDALPamDataset +{ + public: + ComplexDerivedDatasetContainer() {} +}; + + +class ComplexDerivedDataset : public VRTDataset +{ + public: + ComplexDerivedDataset(int nXSize, int nYSize); + ~ComplexDerivedDataset(); + + static GDALDataset *Open( GDALOpenInfo * ); + static int Identify( GDALOpenInfo * ); +}; + + +ComplexDerivedDataset::ComplexDerivedDataset(int nXSize, int nYSize) : VRTDataset(nXSize,nYSize) +{ + poDriver = NULL; + SetWritable(FALSE); +} + +ComplexDerivedDataset::~ComplexDerivedDataset() +{ +} + +int ComplexDerivedDataset::Identify(GDALOpenInfo * poOpenInfo) +{ + if(STARTS_WITH_CI(poOpenInfo->pszFilename, "DERIVED_SUBDATASET:COMPLEX_AMPLITUDE:")) + return TRUE; + + return FALSE; +} + +GDALDataset * ComplexDerivedDataset::Open(GDALOpenInfo * poOpenInfo) +{ + if( !Identify(poOpenInfo) ) + { + return NULL; + } + + /* Try to open original dataset */ + CPLString filename(poOpenInfo->pszFilename); + + // TODO: check starts with + + /* DERIVED_SUBDATASET should be first domain */ + size_t dsds_pos = filename.find("DERIVED_SUBDATASET:"); + + if (dsds_pos == std::string::npos) + { + /* Unable to Open in this case */ + return NULL; + } + + /* DERIVED_SUBDATASET should be first domain */ + size_t alg_pos = filename.find(":",dsds_pos+20); + if (alg_pos == std::string::npos) + { + /* Unable to Open in this case */ + return NULL; + } + + VRTDerivedRasterBand::AddPixelFunction("mod",ModulePixelFunc); + + CPLString odFilename = filename.substr(alg_pos+1,filename.size() - alg_pos); + + GDALDataset * poTmpDS = (GDALDataset*)GDALOpen(odFilename, GA_ReadOnly); + + if( poTmpDS == NULL ) + return NULL; + + int nbBands = poTmpDS->GetRasterCount(); + + int nRows = poTmpDS->GetRasterYSize(); + int nCols = poTmpDS->GetRasterXSize(); + + ComplexDerivedDataset * poDS = new ComplexDerivedDataset(nCols,nRows); + + // Transfer metadata + poDS->SetMetadata(poTmpDS->GetMetadata()); + + for(int nBand = 1; nBand <= nbBands; ++nBand) + { + + + VRTDerivedRasterBand * poBand; + + GDALDataType type = GDT_Float64; + + poBand = new VRTDerivedRasterBand(poDS,nBand,type,nCols,nRows); + poBand->SetPixelFunctionName("mod"); + poBand->SetSourceTransferType(poTmpDS->GetRasterBand(nBand)->GetRasterDataType()); + poDS->SetBand(nBand,poBand); + + GDALProxyPoolDataset* proxyDS; + proxyDS = new GDALProxyPoolDataset( odFilename, + poDS->nRasterXSize, + poDS->nRasterYSize, + GA_ReadOnly, + TRUE); + proxyDS->AddSrcBandDescription(poTmpDS->GetRasterBand(nBand)->GetRasterDataType(), 128, 128); + + poBand->AddComplexSource(proxyDS->GetRasterBand(nBand),0,0,nCols,nRows,0,0,nCols,nRows); + proxyDS->Dereference(); + } + + // TODO: do this earlier ? + delete poTmpDS; + + return poDS; +} + +void GDALRegister_ComplexDerived() +{ + if( GDALGetDriverByName( "COMPLEXDERIVED" ) != NULL ) + return; + + GDALDriver *poDriver = new GDALDriver(); + + poDriver->SetDescription( "COMPLEXDERIVED" ); +#ifdef GDAL_DCAP_RASTER + poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" ); +#endif + poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" ); + poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "Complex derived bands" ); + poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_sentinel2.html" ); + poDriver->SetMetadataItem( GDAL_DMD_SUBDATASETS, "YES" ); + + poDriver->pfnOpen = ComplexDerivedDataset::Open; + poDriver->pfnIdentify = ComplexDerivedDataset::Identify; + + GetGDALDriverManager()->RegisterDriver( poDriver ); +} diff --git a/gdal/frmts/gdalallregister.cpp b/gdal/frmts/gdalallregister.cpp index 569ad92c5e31..9c215a35805c 100644 --- a/gdal/frmts/gdalallregister.cpp +++ b/gdal/frmts/gdalallregister.cpp @@ -68,6 +68,7 @@ void CPL_STDCALL GDALAllRegister() #ifdef FRMT_vrt GDALRegister_VRT(); + GDALRegister_ComplexDerived(); #endif #ifdef FRMT_gtiff diff --git a/gdal/gcore/gdal_frmts.h b/gdal/gcore/gdal_frmts.h index 284a7bb45f7c..354177597bdc 100644 --- a/gdal/gcore/gdal_frmts.h +++ b/gdal/gcore/gdal_frmts.h @@ -187,6 +187,7 @@ void CPL_DLL GDALRegister_SAFE(void); void CPL_DLL GDALRegister_SENTINEL2(void); void CPL_DLL GDALRegister_mrf(void); void CPL_DLL GDALRegister_RRASTER(void); +void CPL_DLL GDALRegister_ComplexDerived(void); CPL_C_END #endif /* ndef GDAL_FRMTS_H_INCLUDED */