From 636ec43072d69392ed1d7afedd9ebdf2ca87f984 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 14 Nov 2019 16:17:17 +0100 Subject: [PATCH 1/2] VRT: fix requesting a downsampling version of the mask band of a source that has masks and overviews --- autotest/gcore/vrtmisc.py | 22 ++++++++++ gdal/frmts/vrt/vrtdataset.cpp | 69 ++++++++++++++++++++++++++++++++ gdal/frmts/vrt/vrtrasterband.cpp | 5 ++- 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/autotest/gcore/vrtmisc.py b/autotest/gcore/vrtmisc.py index 9efd96e207ec..22a06b88a3e4 100755 --- a/autotest/gcore/vrtmisc.py +++ b/autotest/gcore/vrtmisc.py @@ -29,6 +29,7 @@ # DEALINGS IN THE SOFTWARE. ############################################################################### +import gdaltest from osgeo import gdal from osgeo import osr @@ -515,6 +516,27 @@ def test_vrtmisc_write_srs(): gdal.Unlink(tmpfile) +############################################################################### +# complex scenario involving masks and implicit overviews + +def test_vrtmisc_mask_implicit_overviews(): + + with gdaltest.config_option('GDAL_TIFF_INTERNAL_MASK', 'YES'): + ds = gdal.Translate('/vsimem/cog.tif', 'data/stefan_full_rgba.tif', options = '-outsize 2048 0 -b 1 -b 2 -b 3 -mask 4') + ds.BuildOverviews('NEAR', [2, 4]) + ds = None + gdal.Translate('/vsimem/cog.vrt', '/vsimem/cog.tif') + gdal.Translate('/vsimem/out.tif', '/vsimem/cog.vrt', options = '-b mask -outsize 10% 0') + gdal.GetDriverByName('GTiff').Delete('/vsimem/cog.tif') + gdal.Unlink('/vsimem/cog.vrt') + ds = gdal.Open('/vsimem/out.tif') + histo = ds.GetRasterBand(1).GetDefaultHistogram()[3] + # Check that there are only 0 and 255 in the histogram + assert histo[0] + histo[255] == ds.RasterXSize * ds.RasterYSize, histo + assert ds.GetRasterBand(1).Checksum() == 46885 + ds = None + gdal.Unlink('/vsimem/out.tif') + ############################################################################### # Cleanup. diff --git a/gdal/frmts/vrt/vrtdataset.cpp b/gdal/frmts/vrt/vrtdataset.cpp index 757bf25cd50a..32731cf7e5ee 100644 --- a/gdal/frmts/vrt/vrtdataset.cpp +++ b/gdal/frmts/vrt/vrtdataset.cpp @@ -1888,6 +1888,38 @@ void VRTDataset::BuildVirtualOverviews() nOverviews = nOvrCount; } + if( m_poMaskBand ) + { + if( !m_poMaskBand->IsSourcedRasterBand()) + return; + + VRTSourcedRasterBand* poVRTBand + = cpl::down_cast( m_poMaskBand ); + if( poVRTBand->nSources != 1 ) + return; + if( !poVRTBand->papoSources[0]->IsSimpleSource() ) + return; + + VRTSimpleSource* poSource + = cpl::down_cast( poVRTBand->papoSources[0] ); + if( !EQUAL(poSource->GetType(), "SimpleSource") && + !EQUAL(poSource->GetType(), "ComplexSource") ) + return; + GDALRasterBand* poSrcBand = poSource->GetBand(); + if( poSrcBand == nullptr ) + return; + + // To prevent recursion + m_apoOverviewsBak.push_back(nullptr); + const int nOvrCount = poSrcBand->GetOverviewCount(); + m_apoOverviewsBak.resize(0); + + if( nOvrCount == 0 ) + return; + if( nOvrCount < nOverviews ) + nOverviews = nOvrCount; + } + for( int j = 0; j < nOverviews; j++) { auto poOvrBand = poFirstBand->GetOverview(j); @@ -1941,6 +1973,43 @@ void VRTDataset::BuildVirtualOverviews() poOvrVRTBand->AddSource(poNewSource); } } + + if( m_poMaskBand ) + { + VRTSourcedRasterBand* poVRTBand + = cpl::down_cast(m_poMaskBand ); + VRTSourcedRasterBand* poOvrVRTBand = new VRTSourcedRasterBand( + poOvrVDS, + 0, + poVRTBand->GetRasterDataType(), + nOvrXSize, nOvrYSize); + poOvrVDS->SetMaskBand( poOvrVRTBand ); + + VRTSimpleSource* poSrcSource = cpl::down_cast( + poVRTBand->papoSources[0] ); + VRTSimpleSource* poNewSource = nullptr; + if( EQUAL(poSrcSource->GetType(), "SimpleSource") ) + { + poNewSource = + new VRTSimpleSource(poSrcSource, dfXRatio, dfYRatio); + } + else if( EQUAL(poSrcSource->GetType(), "ComplexSource") ) + { + poNewSource = new VRTComplexSource( + cpl::down_cast( poSrcSource ), + dfXRatio, dfYRatio ); + } + else + { + CPLAssert(false); + } + if( poNewSource ) + { + if( poNewSource->GetBand()->GetDataset() ) + poNewSource->GetBand()->GetDataset()->Reference(); + poOvrVRTBand->AddSource(poNewSource); + } + } } } diff --git a/gdal/frmts/vrt/vrtrasterband.cpp b/gdal/frmts/vrt/vrtrasterband.cpp index f75f63b52e3c..0b40a25c1053 100644 --- a/gdal/frmts/vrt/vrtrasterband.cpp +++ b/gdal/frmts/vrt/vrtrasterband.cpp @@ -1200,7 +1200,10 @@ GDALRasterBand *VRTRasterBand::GetOverview( int iOverview ) || iOverview >= static_cast( poVRTDS->m_apoOverviews.size() ) ) return nullptr; - return poVRTDS->m_apoOverviews[iOverview]->GetRasterBand(nBand ? nBand : 1); + auto poOvrBand = poVRTDS->m_apoOverviews[iOverview]->GetRasterBand(nBand ? nBand : 1); + if( m_bIsMaskBand ) + return poOvrBand->GetMaskBand(); + return poOvrBand; } return nullptr; From a01e3142191a1e1ba0ec1c95c491c8b1b0a92e7b Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 14 Nov 2019 16:56:48 +0100 Subject: [PATCH 2/2] VRT: refactor previous commit to avoid code duplication. No functional change --- gdal/frmts/vrt/vrtdataset.cpp | 118 +++++++++++----------------------- 1 file changed, 38 insertions(+), 80 deletions(-) diff --git a/gdal/frmts/vrt/vrtdataset.cpp b/gdal/frmts/vrt/vrtdataset.cpp index 32731cf7e5ee..065993aed4ce 100644 --- a/gdal/frmts/vrt/vrtdataset.cpp +++ b/gdal/frmts/vrt/vrtdataset.cpp @@ -1848,27 +1848,28 @@ void VRTDataset::BuildVirtualOverviews() int nOverviews = 0; GDALRasterBand* poFirstBand = nullptr; - for( int iBand = 0; iBand < nBands; iBand++ ) + + const auto CheckBandForOverview = + [&nOverviews, &poFirstBand, this](GDALRasterBand* poBand) { - if( !reinterpret_cast( - papoBands[iBand] )->IsSourcedRasterBand()) - return; + if( !cpl::down_cast(poBand)->IsSourcedRasterBand()) + return false; VRTSourcedRasterBand* poVRTBand - = reinterpret_cast( papoBands[iBand] ); + = cpl::down_cast(poBand); if( poVRTBand->nSources != 1 ) - return; + return false; if( !poVRTBand->papoSources[0]->IsSimpleSource() ) - return; + return false; VRTSimpleSource* poSource - = reinterpret_cast( poVRTBand->papoSources[0] ); + = cpl::down_cast( poVRTBand->papoSources[0] ); if( !EQUAL(poSource->GetType(), "SimpleSource") && !EQUAL(poSource->GetType(), "ComplexSource") ) - return; + return false; GDALRasterBand* poSrcBand = poSource->GetBand(); if( poSrcBand == nullptr ) - return; + return false; // To prevent recursion m_apoOverviewsBak.push_back(nullptr); @@ -1876,48 +1877,29 @@ void VRTDataset::BuildVirtualOverviews() m_apoOverviewsBak.resize(0); if( nOvrCount == 0 ) - return; - if( iBand == 0 ) + return false; + if( poFirstBand == nullptr ) { if( poSrcBand->GetXSize() == 0 || poSrcBand->GetYSize() == 0 ) - return; + return false; poFirstBand = poSrcBand; nOverviews = nOvrCount; } else if( nOvrCount < nOverviews ) nOverviews = nOvrCount; - } + return true; + }; - if( m_poMaskBand ) + for( int iBand = 0; iBand < nBands; iBand++ ) { - if( !m_poMaskBand->IsSourcedRasterBand()) + if( !CheckBandForOverview(papoBands[iBand]) ) return; + } - VRTSourcedRasterBand* poVRTBand - = cpl::down_cast( m_poMaskBand ); - if( poVRTBand->nSources != 1 ) - return; - if( !poVRTBand->papoSources[0]->IsSimpleSource() ) - return; - - VRTSimpleSource* poSource - = cpl::down_cast( poVRTBand->papoSources[0] ); - if( !EQUAL(poSource->GetType(), "SimpleSource") && - !EQUAL(poSource->GetType(), "ComplexSource") ) - return; - GDALRasterBand* poSrcBand = poSource->GetBand(); - if( poSrcBand == nullptr ) - return; - - // To prevent recursion - m_apoOverviewsBak.push_back(nullptr); - const int nOvrCount = poSrcBand->GetOverviewCount(); - m_apoOverviewsBak.resize(0); - - if( nOvrCount == 0 ) + if( m_poMaskBand ) + { + if( !CheckBandForOverview(m_poMaskBand) ) return; - if( nOvrCount < nOverviews ) - nOverviews = nOvrCount; } for( int j = 0; j < nOverviews; j++) @@ -1936,19 +1918,19 @@ void VRTDataset::BuildVirtualOverviews() VRTDataset* poOvrVDS = new VRTDataset(nOvrXSize, nOvrYSize); m_apoOverviews.push_back(poOvrVDS); - for( int i = 0; i < nBands; i++ ) + const auto CreateOverviewBand = + [&poOvrVDS, nOvrXSize, nOvrYSize, dfXRatio, dfYRatio] + (GDALRasterBand* poBand) { VRTSourcedRasterBand* poVRTBand - = reinterpret_cast( - GetRasterBand(i+1) ); + = cpl::down_cast(poBand); VRTSourcedRasterBand* poOvrVRTBand = new VRTSourcedRasterBand( poOvrVDS, - poOvrVDS->GetRasterCount() + 1, + poBand->GetBand(), poVRTBand->GetRasterDataType(), nOvrXSize, nOvrYSize); - poOvrVDS->SetBand( poOvrVDS->GetRasterCount() + 1, poOvrVRTBand ); - VRTSimpleSource* poSrcSource = reinterpret_cast( + VRTSimpleSource* poSrcSource = cpl::down_cast( poVRTBand->papoSources[0] ); VRTSimpleSource* poNewSource = nullptr; if( EQUAL(poSrcSource->GetType(), "SimpleSource") ) @@ -1959,7 +1941,7 @@ void VRTDataset::BuildVirtualOverviews() else if( EQUAL(poSrcSource->GetType(), "ComplexSource") ) { poNewSource = new VRTComplexSource( - reinterpret_cast( poSrcSource ), + cpl::down_cast( poSrcSource ), dfXRatio, dfYRatio ); } else @@ -1972,43 +1954,19 @@ void VRTDataset::BuildVirtualOverviews() poNewSource->GetBand()->GetDataset()->Reference(); poOvrVRTBand->AddSource(poNewSource); } + + return poOvrVRTBand; + }; + + for( int i = 0; i < nBands; i++ ) + { + poOvrVDS->SetBand( poOvrVDS->GetRasterCount() + 1, + CreateOverviewBand(GetRasterBand(i+1)) ); } if( m_poMaskBand ) { - VRTSourcedRasterBand* poVRTBand - = cpl::down_cast(m_poMaskBand ); - VRTSourcedRasterBand* poOvrVRTBand = new VRTSourcedRasterBand( - poOvrVDS, - 0, - poVRTBand->GetRasterDataType(), - nOvrXSize, nOvrYSize); - poOvrVDS->SetMaskBand( poOvrVRTBand ); - - VRTSimpleSource* poSrcSource = cpl::down_cast( - poVRTBand->papoSources[0] ); - VRTSimpleSource* poNewSource = nullptr; - if( EQUAL(poSrcSource->GetType(), "SimpleSource") ) - { - poNewSource = - new VRTSimpleSource(poSrcSource, dfXRatio, dfYRatio); - } - else if( EQUAL(poSrcSource->GetType(), "ComplexSource") ) - { - poNewSource = new VRTComplexSource( - cpl::down_cast( poSrcSource ), - dfXRatio, dfYRatio ); - } - else - { - CPLAssert(false); - } - if( poNewSource ) - { - if( poNewSource->GetBand()->GetDataset() ) - poNewSource->GetBand()->GetDataset()->Reference(); - poOvrVRTBand->AddSource(poNewSource); - } + poOvrVDS->SetMaskBand( CreateOverviewBand(m_poMaskBand) ); } } }