Skip to content

Commit 1f276a1

Browse files
committed
[processing] port raster layer statistics
1 parent fa0bb2e commit 1f276a1

File tree

5 files changed

+92
-77
lines changed

5 files changed

+92
-77
lines changed

python/plugins/processing/algs/help/qgis.yaml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -467,9 +467,7 @@ qgis:rasterlayerhistogram: >
467467
The raster layer must have a single band.
468468

469469
qgis:rasterlayerstatistics: >
470-
This algorithm computes basic statistics from the values in a raster layer.
471-
472-
The raster layer must have a single band.
470+
This algorithm computes basic statistics from the values in a given band of the raster layer.
473471

474472
qgis:refactorfields: >
475473
This algorithm allows editing the structure of the attributes table of a vector layer. Fields can be modified in their type and name, using a fields mapping.

python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
from .RandomPointsExtent import RandomPointsExtent
100100
from .RandomPointsLayer import RandomPointsLayer
101101
from .RandomPointsPolygons import RandomPointsPolygons
102+
from .RasterLayerStatistics import RasterLayerStatistics
102103
from .RegularPoints import RegularPoints
103104
from .ReverseLineDirection import ReverseLineDirection
104105
from .Ruggedness import Ruggedness
@@ -144,7 +145,6 @@
144145
# from .HubDistanceLines import HubDistanceLines
145146
# from .HubLines import HubLines
146147
# from .GeometryConvert import GeometryConvert
147-
# from .RasterLayerStatistics import RasterLayerStatistics
148148
# from .StatisticsByCategories import StatisticsByCategories
149149
# from .FieldsCalculator import FieldsCalculator
150150
# from .FieldPyculator import FieldsPyculator
@@ -270,6 +270,7 @@ def getAlgs(self):
270270
RandomPointsExtent(),
271271
RandomPointsLayer(),
272272
RandomPointsPolygons(),
273+
RasterLayerStatistics(),
273274
RegularPoints(),
274275
ReverseLineDirection(),
275276
Ruggedness(),

python/plugins/processing/algs/qgis/RasterLayerStatistics.py

Lines changed: 58 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
* *
1717
***************************************************************************
1818
"""
19-
from builtins import str
2019

2120
__author__ = 'Victor Olaya'
2221
__date__ = 'January 2013'
@@ -26,30 +25,31 @@
2625

2726
__revision__ = '$Format:%H$'
2827

29-
import math
3028
import codecs
3129

32-
from qgis.core import (QgsApplication,
33-
QgsProcessingUtils)
30+
from qgis.core import (QgsRectangle,
31+
QgsRasterBandStats,
32+
QgsProcessingParameterRasterLayer,
33+
QgsProcessingParameterNumber,
34+
QgsProcessingParameterFileDestination,
35+
QgsProcessingOutputHtml,
36+
QgsProcessingOutputNumber)
3437
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
35-
from processing.core.parameters import ParameterRaster
36-
from processing.core.outputs import OutputNumber
37-
from processing.core.outputs import OutputHTML
38-
from processing.tools import raster
3938

4039

4140
class RasterLayerStatistics(QgisAlgorithm):
4241

4342
INPUT = 'INPUT'
43+
BAND = 'BAND'
44+
OUTPUT_HTML_FILE = 'OUTPUT_HTML_FILE'
4445

4546
MIN = 'MIN'
4647
MAX = 'MAX'
48+
RANGE = 'RANGE'
4749
SUM = 'SUM'
4850
MEAN = 'MEAN'
49-
COUNT = 'COUNT'
50-
NO_DATA_COUNT = 'NO_DATA_COUNT'
5151
STD_DEV = 'STD_DEV'
52-
OUTPUT_HTML_FILE = 'OUTPUT_HTML_FILE'
52+
SUM_OF_SQUARES = 'SUM_OF_SQUARES'
5353

5454
def group(self):
5555
return self.tr('Raster tools')
@@ -58,16 +58,22 @@ def __init__(self):
5858
super().__init__()
5959

6060
def initAlgorithm(self, config=None):
61-
self.addParameter(ParameterRaster(self.INPUT, self.tr('Input layer')))
62-
63-
self.addOutput(OutputHTML(self.OUTPUT_HTML_FILE, self.tr('Statistics')))
64-
self.addOutput(OutputNumber(self.MIN, self.tr('Minimum value')))
65-
self.addOutput(OutputNumber(self.MAX, self.tr('Maximum value')))
66-
self.addOutput(OutputNumber(self.SUM, self.tr('Sum')))
67-
self.addOutput(OutputNumber(self.MEAN, self.tr('Mean value')))
68-
self.addOutput(OutputNumber(self.COUNT, self.tr('valid cells count')))
69-
self.addOutput(OutputNumber(self.COUNT, self.tr('No-data cells count')))
70-
self.addOutput(OutputNumber(self.STD_DEV, self.tr('Standard deviation')))
61+
self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
62+
self.tr('Input layer')))
63+
self.addParameter(QgsProcessingParameterNumber(self.BAND,
64+
self.tr('Band number'),
65+
QgsProcessingParameterNumber.Integer,
66+
1, False, 1, 999))
67+
self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT_HTML_FILE, self.tr('Statistics'), self.tr('HTML files (*.html)'), None, True))
68+
self.addOutput(QgsProcessingOutputHtml(self.OUTPUT_HTML_FILE, self.tr('Statistics')))
69+
70+
self.addOutput(QgsProcessingOutputNumber(self.MIN, self.tr('Minimum value')))
71+
self.addOutput(QgsProcessingOutputNumber(self.MAX, self.tr('Maximum value')))
72+
self.addOutput(QgsProcessingOutputNumber(self.RANGE, self.tr('Range')))
73+
self.addOutput(QgsProcessingOutputNumber(self.SUM, self.tr('Sum')))
74+
self.addOutput(QgsProcessingOutputNumber(self.MEAN, self.tr('Mean value')))
75+
self.addOutput(QgsProcessingOutputNumber(self.STD_DEV, self.tr('Standard deviation')))
76+
self.addOutput(QgsProcessingOutputNumber(self.SUM_OF_SQUARES, self.tr('Sum of the squares')))
7177

7278
def name(self):
7379
return 'rasterlayerstatistics'
@@ -76,62 +82,41 @@ def displayName(self):
7682
return self.tr('Raster layer statistics')
7783

7884
def processAlgorithm(self, parameters, context, feedback):
79-
outputFile = self.getOutputValue(self.OUTPUT_HTML_FILE)
80-
uri = self.getParameterValue(self.INPUT)
81-
layer = QgsProcessingUtils.mapLayerFromString(uri, context)
82-
values = raster.scanraster(layer, feedback)
83-
84-
n = 0
85-
nodata = 0
86-
mean = 0
87-
M2 = 0
88-
sum = 0
89-
minvalue = None
90-
maxvalue = None
91-
92-
for v in values:
93-
if v is not None:
94-
sum += v
95-
n = n + 1
96-
delta = v - mean
97-
mean = mean + delta / n
98-
M2 = M2 + delta * (v - mean)
99-
if minvalue is None:
100-
minvalue = v
101-
maxvalue = v
102-
else:
103-
minvalue = min(v, minvalue)
104-
maxvalue = max(v, maxvalue)
105-
else:
106-
nodata += 1
107-
108-
variance = M2 / (n - 1)
109-
stddev = math.sqrt(variance)
85+
layer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
86+
band = self.parameterAsInt(parameters, self.BAND, context)
87+
outputFile = self.parameterAsFileOutput(parameters, self.OUTPUT_HTML_FILE, context)
88+
89+
stat = layer.dataProvider().bandStatistics(band, QgsRasterBandStats.All, QgsRectangle(), 0)
11090

11191
data = []
112-
data.append('Valid cells: ' + str(n))
113-
data.append('No-data cells: ' + str(nodata))
114-
data.append('Minimum value: ' + str(minvalue))
115-
data.append('Maximum value: ' + str(maxvalue))
116-
data.append('Sum: ' + str(sum))
117-
data.append('Mean value: ' + str(mean))
118-
data.append('Standard deviation: ' + str(stddev))
119-
120-
self.createHTML(outputFile, data)
121-
122-
self.setOutputValue(self.COUNT, n)
123-
self.setOutputValue(self.NO_DATA_COUNT, nodata)
124-
self.setOutputValue(self.MIN, minvalue)
125-
self.setOutputValue(self.MAX, maxvalue)
126-
self.setOutputValue(self.SUM, sum)
127-
self.setOutputValue(self.MEAN, mean)
128-
self.setOutputValue(self.STD_DEV, stddev)
92+
data.append(self.tr('Analyzed file: {} (band {})').format(layer.source(), band))
93+
data.append(self.tr('Minimum value: {}').format(stat.minimumValue))
94+
data.append(self.tr('Maximum value: {}').format(stat.maximumValue))
95+
data.append(self.tr('Range: {}').format(stat.range))
96+
data.append(self.tr('Sum: {}').format(stat.sum))
97+
data.append(self.tr('Mean value: {}').format(stat.mean))
98+
data.append(self.tr('Standard deviation: {}').format(stat.stdDev))
99+
data.append(self.tr('Sum of the squares: {}').format(stat.sumOfSquares))
100+
101+
results = {self.MIN: stat.minimumValue,
102+
self.MAX: stat.maximumValue,
103+
self.RANGE: stat.range,
104+
self.SUM: stat.sum,
105+
self.MEAN: stat.mean,
106+
self.STD_DEV: stat.stdDev,
107+
self.SUM_OF_SQUARES: stat.sumOfSquares}
108+
109+
if outputFile:
110+
self.createHTML(outputFile, data)
111+
results[self.OUTPUT_HTML_FILE] = outputFile
112+
113+
return results
129114

130115
def createHTML(self, outputFile, algData):
131116
with codecs.open(outputFile, 'w', encoding='utf-8') as f:
132-
f.write('<html><head>')
117+
f.write('<html><head>\n')
133118
f.write('<meta http-equiv="Content-Type" content="text/html; \
134-
charset=utf-8" /></head><body>')
119+
charset=utf-8" /></head><body>\n')
135120
for s in algData:
136-
f.write('<p>' + str(s) + '</p>')
137-
f.write('</body></html>')
121+
f.write('<p>' + str(s) + '</p>\n')
122+
f.write('</body></html>\n')
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<html><head>
2+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body>
3+
<p>Analyzed file: /home/alex/devel/qgis/python/plugins/processing/tests/testdata/dem.tif (band 1)</p>
4+
<p>Minimum value: 85.0</p>
5+
<p>Maximum value: 243.0</p>
6+
<p>Range: 158.0</p>
7+
<p>Sum: 19213301.982429504</p>
8+
<p>Mean value: 147.17197994967066</p>
9+
<p>Standard deviation: 43.9618116337985</p>
10+
<p>Sum of the squares: 252304334.52061242</p>
11+
</body></html>

python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2758,3 +2758,23 @@ tests:
27582758
OUTPUT:
27592759
hash: f09384c64f56286ec4146a7b9a679cea7c6711ec4c7d77eec054e364
27602760
type: rasterhash
2761+
2762+
- algorithm: qgis:rasterlayerstatistics
2763+
name: Raster layer statistics
2764+
params:
2765+
INPUT:
2766+
name: dem.tif
2767+
type: raster
2768+
BAND: 1
2769+
results:
2770+
OUTPUT_HTML_FILE:
2771+
name: raster_statistics.html
2772+
type: regex
2773+
rules:
2774+
- 'Minimum value: 85.0'
2775+
- 'Maximum value: 243.0'
2776+
- 'Range: 158.0'
2777+
- 'Sum: 19213301.982429504'
2778+
- 'Mean value: 147.17197994967066'
2779+
- 'Standard deviation: 43.9618116337985'
2780+
- 'Sum of the squares: 252304334.52061242'

0 commit comments

Comments
 (0)