[zonal statistics] add variance statistic

This commit is contained in:
nirvn 2017-06-29 09:47:08 +07:00 committed by Mathieu Pellerin
parent 8379f9bb98
commit 58f6f93cb6
4 changed files with 29 additions and 5 deletions

View File

@ -36,6 +36,7 @@ class QgsZonalStatistics
Minority, Minority,
Majority, Majority,
Variety, Variety,
Variance,
All All
}; };
typedef QFlags<QgsZonalStatistics::Statistic> Statistics; typedef QFlags<QgsZonalStatistics::Statistic> Statistics;

View File

@ -158,6 +158,13 @@ int QgsZonalStatistics::calculateStatistics( QgsFeedback *feedback )
QgsField varietyField( varietyFieldName, QVariant::Int, QStringLiteral( "int" ) ); QgsField varietyField( varietyFieldName, QVariant::Int, QStringLiteral( "int" ) );
newFieldList.push_back( varietyField ); newFieldList.push_back( varietyField );
} }
QString varianceFieldName;
if ( mStatistics & QgsZonalStatistics::Variance )
{
varianceFieldName = getUniqueFieldName( mAttributePrefix + "variance", newFieldList );
QgsField varianceField( varianceFieldName, QVariant::Double, QStringLiteral( "double precision" ) );
newFieldList.push_back( varianceField );
}
vectorProvider->addAttributes( newFieldList ); vectorProvider->addAttributes( newFieldList );
//index of the new fields //index of the new fields
@ -172,6 +179,7 @@ int QgsZonalStatistics::calculateStatistics( QgsFeedback *feedback )
int minorityIndex = mStatistics & QgsZonalStatistics::Minority ? vectorProvider->fieldNameIndex( minorityFieldName ) : -1; int minorityIndex = mStatistics & QgsZonalStatistics::Minority ? vectorProvider->fieldNameIndex( minorityFieldName ) : -1;
int majorityIndex = mStatistics & QgsZonalStatistics::Majority ? vectorProvider->fieldNameIndex( majorityFieldName ) : -1; int majorityIndex = mStatistics & QgsZonalStatistics::Majority ? vectorProvider->fieldNameIndex( majorityFieldName ) : -1;
int varietyIndex = mStatistics & QgsZonalStatistics::Variety ? vectorProvider->fieldNameIndex( varietyFieldName ) : -1; int varietyIndex = mStatistics & QgsZonalStatistics::Variety ? vectorProvider->fieldNameIndex( varietyFieldName ) : -1;
int varianceIndex = mStatistics & QgsZonalStatistics::Variance ? vectorProvider->fieldNameIndex( varianceFieldName ) : -1;
if ( ( mStatistics & QgsZonalStatistics::Count && countIndex == -1 ) if ( ( mStatistics & QgsZonalStatistics::Count && countIndex == -1 )
|| ( mStatistics & QgsZonalStatistics::Sum && sumIndex == -1 ) || ( mStatistics & QgsZonalStatistics::Sum && sumIndex == -1 )
@ -184,6 +192,7 @@ int QgsZonalStatistics::calculateStatistics( QgsFeedback *feedback )
|| ( mStatistics & QgsZonalStatistics::Minority && minorityIndex == -1 ) || ( mStatistics & QgsZonalStatistics::Minority && minorityIndex == -1 )
|| ( mStatistics & QgsZonalStatistics::Majority && majorityIndex == -1 ) || ( mStatistics & QgsZonalStatistics::Majority && majorityIndex == -1 )
|| ( mStatistics & QgsZonalStatistics::Variety && varietyIndex == -1 ) || ( mStatistics & QgsZonalStatistics::Variety && varietyIndex == -1 )
|| ( mStatistics & QgsZonalStatistics::Variance && varianceIndex == -1 )
) )
{ {
//failed to create a required field //failed to create a required field
@ -200,7 +209,8 @@ int QgsZonalStatistics::calculateStatistics( QgsFeedback *feedback )
QgsFeature f; QgsFeature f;
bool statsStoreValues = ( mStatistics & QgsZonalStatistics::Median ) || bool statsStoreValues = ( mStatistics & QgsZonalStatistics::Median ) ||
( mStatistics & QgsZonalStatistics::StDev ); ( mStatistics & QgsZonalStatistics::StDev ) ||
( mStatistics & QgsZonalStatistics::Variance );
bool statsStoreValueCount = ( mStatistics & QgsZonalStatistics::Minority ) || bool statsStoreValueCount = ( mStatistics & QgsZonalStatistics::Minority ) ||
( mStatistics & QgsZonalStatistics::Majority ); ( mStatistics & QgsZonalStatistics::Majority );
@ -288,7 +298,7 @@ int QgsZonalStatistics::calculateStatistics( QgsFeedback *feedback )
} }
changeAttributeMap.insert( medianIndex, QVariant( medianValue ) ); changeAttributeMap.insert( medianIndex, QVariant( medianValue ) );
} }
if ( mStatistics & QgsZonalStatistics::StDev ) if ( mStatistics & QgsZonalStatistics::StDev || mStatistics & QgsZonalStatistics::Variance )
{ {
double sumSquared = 0; double sumSquared = 0;
for ( int i = 0; i < featureStats.values.count(); ++i ) for ( int i = 0; i < featureStats.values.count(); ++i )
@ -296,8 +306,14 @@ int QgsZonalStatistics::calculateStatistics( QgsFeedback *feedback )
double diff = featureStats.values.at( i ) - mean; double diff = featureStats.values.at( i ) - mean;
sumSquared += diff * diff; sumSquared += diff * diff;
} }
double stdev = qPow( sumSquared / featureStats.values.count(), 0.5 ); double variance = sumSquared / featureStats.values.count();
changeAttributeMap.insert( stdevIndex, QVariant( stdev ) ); if ( mStatistics & QgsZonalStatistics::StDev )
{
double stdev = qPow( variance, 0.5 );
changeAttributeMap.insert( stdevIndex, QVariant( stdev ) );
}
if ( mStatistics & QgsZonalStatistics::Variance )
changeAttributeMap.insert( varianceIndex, QVariant( variance ) );
} }
if ( mStatistics & QgsZonalStatistics::Min ) if ( mStatistics & QgsZonalStatistics::Min )
changeAttributeMap.insert( minIndex, QVariant( featureStats.min ) ); changeAttributeMap.insert( minIndex, QVariant( featureStats.min ) );

View File

@ -55,7 +55,8 @@ class ANALYSIS_EXPORT QgsZonalStatistics
Minority = 256, //!< Minority of pixel values Minority = 256, //!< Minority of pixel values
Majority = 512, //!< Majority of pixel values Majority = 512, //!< Majority of pixel values
Variety = 1024, //!< Variety (count of distinct) pixel values Variety = 1024, //!< Variety (count of distinct) pixel values
All = Count | Sum | Mean | Median | StDev | Max | Min | Range | Minority | Majority | Variety Variance = 2048, //!< Variance of pixel values
All = Count | Sum | Mean | Median | StDev | Max | Min | Range | Minority | Majority | Variety | Variance
}; };
Q_DECLARE_FLAGS( Statistics, Statistic ) Q_DECLARE_FLAGS( Statistics, Statistic )

View File

@ -94,6 +94,7 @@ void TestQgsZonalStatistics::testStatistics()
QCOMPARE( f.attribute( "minority" ).toDouble(), 0.0 ); QCOMPARE( f.attribute( "minority" ).toDouble(), 0.0 );
QCOMPARE( f.attribute( "majority" ).toDouble(), 1.0 ); QCOMPARE( f.attribute( "majority" ).toDouble(), 1.0 );
QCOMPARE( f.attribute( "variety" ).toDouble(), 2.0 ); QCOMPARE( f.attribute( "variety" ).toDouble(), 2.0 );
QCOMPARE( f.attribute( "variance" ).toDouble(), 0.222222222222222 );
request.setFilterFid( 1 ); request.setFilterFid( 1 );
fetched = mVectorLayer->getFeatures( request ).nextFeature( f ); fetched = mVectorLayer->getFeatures( request ).nextFeature( f );
@ -109,6 +110,7 @@ void TestQgsZonalStatistics::testStatistics()
QCOMPARE( f.attribute( "minority" ).toDouble(), 0.0 ); QCOMPARE( f.attribute( "minority" ).toDouble(), 0.0 );
QCOMPARE( f.attribute( "majority" ).toDouble(), 1.0 ); QCOMPARE( f.attribute( "majority" ).toDouble(), 1.0 );
QCOMPARE( f.attribute( "variety" ).toDouble(), 2.0 ); QCOMPARE( f.attribute( "variety" ).toDouble(), 2.0 );
QCOMPARE( f.attribute( "variance" ).toDouble(), 0.24691358024691 );
request.setFilterFid( 2 ); request.setFilterFid( 2 );
fetched = mVectorLayer->getFeatures( request ).nextFeature( f ); fetched = mVectorLayer->getFeatures( request ).nextFeature( f );
@ -124,6 +126,7 @@ void TestQgsZonalStatistics::testStatistics()
QCOMPARE( f.attribute( "minority" ).toDouble(), 0.0 ); QCOMPARE( f.attribute( "minority" ).toDouble(), 0.0 );
QCOMPARE( f.attribute( "majority" ).toDouble(), 1.0 ); QCOMPARE( f.attribute( "majority" ).toDouble(), 1.0 );
QCOMPARE( f.attribute( "variety" ).toDouble(), 2.0 ); QCOMPARE( f.attribute( "variety" ).toDouble(), 2.0 );
QCOMPARE( f.attribute( "variance" ).toDouble(), 0.13888888888889 );
// same with long prefix to ensure that field name truncation handled correctly // same with long prefix to ensure that field name truncation handled correctly
QgsZonalStatistics zsl( mVectorLayer, mRasterLayer, QStringLiteral( "myqgis2_" ), 1, QgsZonalStatistics::All ); QgsZonalStatistics zsl( mVectorLayer, mRasterLayer, QStringLiteral( "myqgis2_" ), 1, QgsZonalStatistics::All );
@ -143,6 +146,7 @@ void TestQgsZonalStatistics::testStatistics()
QCOMPARE( f.attribute( "myqgis2__2" ).toDouble(), 0.0 ); QCOMPARE( f.attribute( "myqgis2__2" ).toDouble(), 0.0 );
QCOMPARE( f.attribute( "myqgis2__3" ).toDouble(), 1.0 ); QCOMPARE( f.attribute( "myqgis2__3" ).toDouble(), 1.0 );
QCOMPARE( f.attribute( "myqgis2_va" ).toDouble(), 2.0 ); QCOMPARE( f.attribute( "myqgis2_va" ).toDouble(), 2.0 );
QCOMPARE( f.attribute( "myqgis2__4" ).toDouble(), 0.222222222222222 );
request.setFilterFid( 1 ); request.setFilterFid( 1 );
fetched = mVectorLayer->getFeatures( request ).nextFeature( f ); fetched = mVectorLayer->getFeatures( request ).nextFeature( f );
@ -158,6 +162,7 @@ void TestQgsZonalStatistics::testStatistics()
QCOMPARE( f.attribute( "myqgis2__2" ).toDouble(), 0.0 ); QCOMPARE( f.attribute( "myqgis2__2" ).toDouble(), 0.0 );
QCOMPARE( f.attribute( "myqgis2__3" ).toDouble(), 1.0 ); QCOMPARE( f.attribute( "myqgis2__3" ).toDouble(), 1.0 );
QCOMPARE( f.attribute( "myqgis2_va" ).toDouble(), 2.0 ); QCOMPARE( f.attribute( "myqgis2_va" ).toDouble(), 2.0 );
QCOMPARE( f.attribute( "myqgis2__4" ).toDouble(), 0.24691358024691 );
request.setFilterFid( 2 ); request.setFilterFid( 2 );
fetched = mVectorLayer->getFeatures( request ).nextFeature( f ); fetched = mVectorLayer->getFeatures( request ).nextFeature( f );
@ -173,6 +178,7 @@ void TestQgsZonalStatistics::testStatistics()
QCOMPARE( f.attribute( "myqgis2__2" ).toDouble(), 0.0 ); QCOMPARE( f.attribute( "myqgis2__2" ).toDouble(), 0.0 );
QCOMPARE( f.attribute( "myqgis2__3" ).toDouble(), 1.0 ); QCOMPARE( f.attribute( "myqgis2__3" ).toDouble(), 1.0 );
QCOMPARE( f.attribute( "myqgis2_va" ).toDouble(), 2.0 ); QCOMPARE( f.attribute( "myqgis2_va" ).toDouble(), 2.0 );
QCOMPARE( f.attribute( "myqgis2__4" ).toDouble(), 0.13888888888889 );
} }
QGSTEST_MAIN( TestQgsZonalStatistics ) QGSTEST_MAIN( TestQgsZonalStatistics )