Skip to content

Commit

Permalink
Expose additional GDAL supported resampling methods as options
Browse files Browse the repository at this point in the history
for "early" raster resampling

Notably, this adds the "Average" resampling as an option for
early resampling methods. (A nice side effect is that we also
get mode, cubic spline, Lanczos, ... for free!)

Fixes #40746
  • Loading branch information
nyalldawson committed Jan 31, 2021
1 parent d140970 commit 13fbcd1
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 25 deletions.
13 changes: 9 additions & 4 deletions python/core/auto_additions/qgsrasterdataprovider.py
@@ -1,7 +1,12 @@
# The following has been generated automatically from src/core/raster/qgsrasterdataprovider.h
# monkey patching scoped based enum
QgsRasterDataProvider.ResamplingMethod.Nearest.__doc__ = "Nearest-neighbour resamplikng"
QgsRasterDataProvider.ResamplingMethod.Bilinear.__doc__ = "Bilinear resamplikng"
QgsRasterDataProvider.ResamplingMethod.Cubic.__doc__ = "Bicubic resamplikng"
QgsRasterDataProvider.ResamplingMethod.__doc__ = 'Resampling method for provider-level resampling.\n\n.. versionadded:: 3.16\n\n' + '* ``Nearest``: ' + QgsRasterDataProvider.ResamplingMethod.Nearest.__doc__ + '\n' + '* ``Bilinear``: ' + QgsRasterDataProvider.ResamplingMethod.Bilinear.__doc__ + '\n' + '* ``Cubic``: ' + QgsRasterDataProvider.ResamplingMethod.Cubic.__doc__
QgsRasterDataProvider.ResamplingMethod.Nearest.__doc__ = "Nearest-neighbour resampling"
QgsRasterDataProvider.ResamplingMethod.Bilinear.__doc__ = "Bilinear (2x2 kernel) resampling"
QgsRasterDataProvider.ResamplingMethod.Cubic.__doc__ = "Cubic Convolution Approximation (4x4 kernel) resampling"
QgsRasterDataProvider.ResamplingMethod.CubicSpline.__doc__ = "Cubic B-Spline Approximation (4x4 kernel)"
QgsRasterDataProvider.ResamplingMethod.Lanczos.__doc__ = "Lanczos windowed sinc interpolation (6x6 kernel)"
QgsRasterDataProvider.ResamplingMethod.Average.__doc__ = "Average resampling"
QgsRasterDataProvider.ResamplingMethod.Mode.__doc__ = "Mode (selects the value which appears most often of all the sampled points)"
QgsRasterDataProvider.ResamplingMethod.Gauss.__doc__ = "Gauss blurring"
QgsRasterDataProvider.ResamplingMethod.__doc__ = 'Resampling method for provider-level resampling.\n\n.. versionadded:: 3.16\n\n' + '* ``Nearest``: ' + QgsRasterDataProvider.ResamplingMethod.Nearest.__doc__ + '\n' + '* ``Bilinear``: ' + QgsRasterDataProvider.ResamplingMethod.Bilinear.__doc__ + '\n' + '* ``Cubic``: ' + QgsRasterDataProvider.ResamplingMethod.Cubic.__doc__ + '\n' + '* ``CubicSpline``: ' + QgsRasterDataProvider.ResamplingMethod.CubicSpline.__doc__ + '\n' + '* ``Lanczos``: ' + QgsRasterDataProvider.ResamplingMethod.Lanczos.__doc__ + '\n' + '* ``Average``: ' + QgsRasterDataProvider.ResamplingMethod.Average.__doc__ + '\n' + '* ``Mode``: ' + QgsRasterDataProvider.ResamplingMethod.Mode.__doc__ + '\n' + '* ``Gauss``: ' + QgsRasterDataProvider.ResamplingMethod.Gauss.__doc__
# --
Expand Up @@ -559,6 +559,11 @@ Returns whether provider-level resampling is enabled.
Nearest,
Bilinear,
Cubic,
CubicSpline,
Lanczos,
Average,
Mode,
Gauss
};

virtual bool setZoomedInResamplingMethod( ResamplingMethod method );
Expand Down
20 changes: 20 additions & 0 deletions src/core/providers/gdal/qgsgdalprovider.cpp
Expand Up @@ -802,6 +802,26 @@ static GDALRIOResampleAlg getGDALResamplingAlg( QgsGdalProvider::ResamplingMetho
case QgsGdalProvider::ResamplingMethod::Cubic:
eResampleAlg = GRIORA_Cubic;
break;

case QgsRasterDataProvider::ResamplingMethod::CubicSpline:
eResampleAlg = GRIORA_CubicSpline;
break;

case QgsRasterDataProvider::ResamplingMethod::Lanczos:
eResampleAlg = GRIORA_Lanczos;
break;

case QgsRasterDataProvider::ResamplingMethod::Average:
eResampleAlg = GRIORA_Average;
break;

case QgsRasterDataProvider::ResamplingMethod::Mode:
eResampleAlg = GRIORA_Mode;
break;

case QgsRasterDataProvider::ResamplingMethod::Gauss:
eResampleAlg = GRIORA_Gauss;
break;
}

return eResampleAlg;
Expand Down
39 changes: 36 additions & 3 deletions src/core/raster/qgsrasterdataprovider.cpp
Expand Up @@ -570,6 +570,26 @@ static QgsRasterDataProvider::ResamplingMethod resamplingMethodFromString( const
{
return QgsRasterDataProvider::ResamplingMethod::Cubic;
}
else if ( str == QLatin1String( "cubicSpline" ) )
{
return QgsRasterDataProvider::ResamplingMethod::CubicSpline;
}
else if ( str == QLatin1String( "lanczos" ) )
{
return QgsRasterDataProvider::ResamplingMethod::Lanczos;
}
else if ( str == QLatin1String( "average" ) )
{
return QgsRasterDataProvider::ResamplingMethod::Average;
}
else if ( str == QLatin1String( "mode" ) )
{
return QgsRasterDataProvider::ResamplingMethod::Mode;
}
else if ( str == QLatin1String( "gauss" ) )
{
return QgsRasterDataProvider::ResamplingMethod::Gauss;
}
return QgsRasterDataProvider::ResamplingMethod::Nearest;
}

Expand All @@ -594,9 +614,22 @@ static QString resamplingMethodToString( QgsRasterDataProvider::ResamplingMethod
{
switch ( method )
{
case QgsRasterDataProvider::ResamplingMethod::Nearest : return QStringLiteral( "nearestNeighbour" );
case QgsRasterDataProvider::ResamplingMethod::Bilinear : return QStringLiteral( "bilinear" );
case QgsRasterDataProvider::ResamplingMethod::Cubic : return QStringLiteral( "cubic" );
case QgsRasterDataProvider::ResamplingMethod::Nearest:
return QStringLiteral( "nearestNeighbour" );
case QgsRasterDataProvider::ResamplingMethod::Bilinear:
return QStringLiteral( "bilinear" );
case QgsRasterDataProvider::ResamplingMethod::Cubic:
return QStringLiteral( "cubic" );
case QgsRasterDataProvider::ResamplingMethod::CubicSpline:
return QStringLiteral( "cubicSpline" );
case QgsRasterDataProvider::ResamplingMethod::Lanczos:
return QStringLiteral( "lanczos" );
case QgsRasterDataProvider::ResamplingMethod::Average:
return QStringLiteral( "average" );
case QgsRasterDataProvider::ResamplingMethod::Mode:
return QStringLiteral( "mode" );
case QgsRasterDataProvider::ResamplingMethod::Gauss:
return QStringLiteral( "gauss" );
}
// should not happen
return QStringLiteral( "nearestNeighbour" );
Expand Down
11 changes: 8 additions & 3 deletions src/core/raster/qgsrasterdataprovider.h
Expand Up @@ -607,9 +607,14 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
*/
enum class ResamplingMethod
{
Nearest, //!< Nearest-neighbour resamplikng
Bilinear, //!< Bilinear resamplikng
Cubic, //!< Bicubic resamplikng
Nearest, //!< Nearest-neighbour resampling
Bilinear, //!< Bilinear (2x2 kernel) resampling
Cubic,//!< Cubic Convolution Approximation (4x4 kernel) resampling
CubicSpline, //!< Cubic B-Spline Approximation (4x4 kernel)
Lanczos, //!< Lanczos windowed sinc interpolation (6x6 kernel)
Average, //!< Average resampling
Mode, //!< Mode (selects the value which appears most often of all the sampled points)
Gauss //!< Gauss blurring
};

/**
Expand Down
104 changes: 90 additions & 14 deletions src/gui/raster/qgsresamplingutils.cpp
Expand Up @@ -44,13 +44,25 @@ void QgsResamplingUtils::initWidgets( QgsRasterLayer *rasterLayer,
mMaximumOversamplingSpinBox = maximumOversamplingSpinBox;
mCbEarlyResampling = cbEarlyResampling;

mZoomedInResamplingComboBox->addItem( QObject::tr( "Nearest neighbour" ), static_cast<int>( QgsRasterDataProvider::ResamplingMethod::Nearest ) );
mZoomedInResamplingComboBox->addItem( QObject::tr( "Bilinear" ), static_cast<int>( QgsRasterDataProvider::ResamplingMethod::Bilinear ) );
mZoomedInResamplingComboBox->addItem( QObject::tr( "Cubic" ), static_cast<int>( QgsRasterDataProvider::ResamplingMethod::Cubic ) );
for ( QComboBox *combo : {mZoomedInResamplingComboBox, mZoomedOutResamplingComboBox } )
{
combo->addItem( QObject::tr( "Nearest Neighbour" ), static_cast<int>( QgsRasterDataProvider::ResamplingMethod::Nearest ) );
combo->addItem( QObject::tr( "Bilinear" ), static_cast<int>( QgsRasterDataProvider::ResamplingMethod::Bilinear ) );
combo->addItem( QObject::tr( "Cubic" ), static_cast<int>( QgsRasterDataProvider::ResamplingMethod::Cubic ) );
}

if ( mCbEarlyResampling->isChecked() )
{
addExtraEarlyResamplingMethodsToCombos();
}

mZoomedOutResamplingComboBox->addItem( QObject::tr( "Nearest neighbour" ), static_cast<int>( QgsRasterDataProvider::ResamplingMethod::Nearest ) );
mZoomedOutResamplingComboBox->addItem( QObject::tr( "Bilinear" ), static_cast<int>( QgsRasterDataProvider::ResamplingMethod::Bilinear ) );
mZoomedOutResamplingComboBox->addItem( QObject::tr( "Cubic" ), static_cast<int>( QgsRasterDataProvider::ResamplingMethod::Cubic ) );
QObject::connect( mCbEarlyResampling, &QCheckBox::toggled, this, [ = ]( bool state )
{
if ( state )
addExtraEarlyResamplingMethodsToCombos();
else
removeExtraEarlyResamplingMethodsFromCombos();
} );
}

void QgsResamplingUtils::refreshWidgetsFromLayer()
Expand All @@ -60,6 +72,16 @@ void QgsResamplingUtils::refreshWidgetsFromLayer()
provider && ( provider->providerCapabilities() & QgsRasterDataProvider::ProviderHintCanPerformProviderResampling ) );
mCbEarlyResampling->setChecked( mRasterLayer->resamplingStage() == QgsRasterPipe::ResamplingStage::Provider );

switch ( mRasterLayer->resamplingStage() )
{
case QgsRasterPipe::ResamplingStage::ResampleFilter:
removeExtraEarlyResamplingMethodsFromCombos();
break;
case QgsRasterPipe::ResamplingStage::Provider:
addExtraEarlyResamplingMethodsToCombos();
break;
}

if ( provider && mRasterLayer->resamplingStage() == QgsRasterPipe::ResamplingStage::Provider )
{
mZoomedInResamplingComboBox->setCurrentIndex( mZoomedInResamplingComboBox->findData( static_cast<int>( provider->zoomedInResamplingMethod() ) ) );
Expand Down Expand Up @@ -134,45 +156,99 @@ void QgsResamplingUtils::refreshLayerFromWidgets()
QgsRasterResampleFilter *resampleFilter = mRasterLayer->resampleFilter();
if ( resampleFilter )
{
QgsRasterResampler *zoomedInResampler = nullptr;
std::unique_ptr< QgsRasterResampler > zoomedInResampler;

switch ( zoomedInMethod )
{
case QgsRasterDataProvider::ResamplingMethod::Nearest:
break;

case QgsRasterDataProvider::ResamplingMethod::Bilinear:
zoomedInResampler = new QgsBilinearRasterResampler();
zoomedInResampler = qgis::make_unique< QgsBilinearRasterResampler >();
break;

case QgsRasterDataProvider::ResamplingMethod::Cubic:
zoomedInResampler = new QgsCubicRasterResampler();
zoomedInResampler = qgis::make_unique< QgsCubicRasterResampler >();
break;

case QgsRasterDataProvider::ResamplingMethod::CubicSpline:
case QgsRasterDataProvider::ResamplingMethod::Lanczos:
case QgsRasterDataProvider::ResamplingMethod::Average:
case QgsRasterDataProvider::ResamplingMethod::Mode:
case QgsRasterDataProvider::ResamplingMethod::Gauss:

// not supported as late resampler methods
break;
}

resampleFilter->setZoomedInResampler( zoomedInResampler );
resampleFilter->setZoomedInResampler( zoomedInResampler.release() );

//raster resampling
QgsRasterResampler *zoomedOutResampler = nullptr;
std::unique_ptr< QgsRasterResampler > zoomedOutResampler;

switch ( zoomedOutMethod )
{
case QgsRasterDataProvider::ResamplingMethod::Nearest:
break;

case QgsRasterDataProvider::ResamplingMethod::Bilinear:
zoomedOutResampler = new QgsBilinearRasterResampler();
zoomedOutResampler = qgis::make_unique< QgsBilinearRasterResampler >();
break;

case QgsRasterDataProvider::ResamplingMethod::Cubic:
zoomedOutResampler = new QgsCubicRasterResampler();
zoomedOutResampler = qgis::make_unique< QgsCubicRasterResampler >();
break;


case QgsRasterDataProvider::ResamplingMethod::CubicSpline:
case QgsRasterDataProvider::ResamplingMethod::Lanczos:
case QgsRasterDataProvider::ResamplingMethod::Average:
case QgsRasterDataProvider::ResamplingMethod::Mode:
case QgsRasterDataProvider::ResamplingMethod::Gauss:
// not supported as late resampler methods
break;
}

resampleFilter->setZoomedOutResampler( zoomedOutResampler );
resampleFilter->setZoomedOutResampler( zoomedOutResampler.release() );

resampleFilter->setMaxOversampling( mMaximumOversamplingSpinBox->value() );
}
}

void QgsResamplingUtils::addExtraEarlyResamplingMethodsToCombos()
{
if ( mZoomedInResamplingComboBox->findData( static_cast<int>( QgsRasterDataProvider::ResamplingMethod::CubicSpline ) ) != -1 )
return; // already present

for ( QComboBox *combo : {mZoomedInResamplingComboBox, mZoomedOutResamplingComboBox } )
{
combo->addItem( QObject::tr( "Cubic Spline" ), static_cast<int>( QgsRasterDataProvider::ResamplingMethod::CubicSpline ) );
combo->addItem( QObject::tr( "Lanczos" ), static_cast<int>( QgsRasterDataProvider::ResamplingMethod::Lanczos ) );
combo->addItem( QObject::tr( "Average" ), static_cast<int>( QgsRasterDataProvider::ResamplingMethod::Average ) );
combo->addItem( QObject::tr( "Mode" ), static_cast<int>( QgsRasterDataProvider::ResamplingMethod::Mode ) );
combo->addItem( QObject::tr( "Gauss" ), static_cast<int>( QgsRasterDataProvider::ResamplingMethod::Gauss ) );
}
}

void QgsResamplingUtils::removeExtraEarlyResamplingMethodsFromCombos()
{
if ( mZoomedInResamplingComboBox->findData( static_cast<int>( QgsRasterDataProvider::ResamplingMethod::CubicSpline ) ) == -1 )
return; // already removed

for ( QComboBox *combo : {mZoomedInResamplingComboBox, mZoomedOutResamplingComboBox } )
{
for ( QgsRasterDataProvider::ResamplingMethod method :
{
QgsRasterDataProvider::ResamplingMethod::CubicSpline,
QgsRasterDataProvider::ResamplingMethod::Lanczos,
QgsRasterDataProvider::ResamplingMethod::Average,
QgsRasterDataProvider::ResamplingMethod::Mode,
QgsRasterDataProvider::ResamplingMethod::Gauss
} )
{
combo->removeItem( combo->findData( static_cast< int >( method ) ) );
}
}
}

/// @endcond PRIVATE
12 changes: 11 additions & 1 deletion src/gui/raster/qgsresamplingutils.h
Expand Up @@ -18,6 +18,8 @@
#ifndef QGSRESAMPLINGUTILS_H
#define QGSRESAMPLINGUTILS_H

#include "qgis_gui.h"
#include <QObject>

class QgsRasterLayer;
class QComboBox;
Expand All @@ -32,8 +34,10 @@ class QCheckBox;
* QgsRenderedRasterPropertiesWidget to deal with widgets related to
* resampling settings.
*/
class QgsResamplingUtils
class GUI_EXPORT QgsResamplingUtils : public QObject
{
Q_OBJECT

QgsRasterLayer *mRasterLayer = nullptr;
QComboBox *mZoomedInResamplingComboBox = nullptr;
QComboBox *mZoomedOutResamplingComboBox = nullptr;
Expand All @@ -59,6 +63,12 @@ class QgsResamplingUtils

//! Synchronize QgsRasterLayer state from widgets
void refreshLayerFromWidgets();

private:

void addExtraEarlyResamplingMethodsToCombos();
void removeExtraEarlyResamplingMethodsFromCombos();

};

///@endcond PRIVATE
Expand Down

0 comments on commit 13fbcd1

Please sign in to comment.