Skip to content

Commit 918cd4b

Browse files
committed
Refactor the way to get the unique pixel values from the raster in a
memory efficient manner, to use it for the auto symbology function
1 parent 7b7e5e5 commit 918cd4b

File tree

1 file changed

+49
-11
lines changed

1 file changed

+49
-11
lines changed

utils/others_utils.py

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"""
33
/***************************************************************************
44
ThRasE
5-
5+
66
A powerful and fast thematic raster editor Qgis plugin
77
-------------------
88
copyright : (C) 2019-2025 by Xavier Corredor Llano, SMByC
@@ -24,8 +24,9 @@
2424
from random import randrange
2525
from osgeo import gdal
2626

27+
from qgis.PyQt.QtCore import Qt
2728
from qgis.PyQt.QtGui import QColor
28-
from qgis.PyQt.QtWidgets import QMessageBox
29+
from qgis.PyQt.QtWidgets import QMessageBox, QProgressDialog, QApplication
2930
from qgis.core import QgsPalettedRasterRenderer
3031

3132
from ThRasE.utils.qgis_utils import get_file_path_of_layer
@@ -51,14 +52,52 @@ def mask(input_list, boolean_mask):
5152
# symbology utils
5253

5354

54-
@wait_process
55+
def get_unique_values(layer, band, chunk_size=1000):
56+
"""Get unique values in a raster band using chunked GDAL reading"""
57+
gdal_file = gdal.Open(get_file_path_of_layer(layer), gdal.GA_ReadOnly)
58+
raster_band = gdal_file.GetRasterBand(band)
59+
60+
# Calculate total chunks for progress
61+
x_chunks = (gdal_file.RasterXSize + chunk_size - 1) // chunk_size
62+
y_chunks = (gdal_file.RasterYSize + chunk_size - 1) // chunk_size
63+
total_chunks = x_chunks * y_chunks
64+
65+
# Create progress dialog
66+
progress = QProgressDialog("Analyzing raster unique values...", "Cancel", 0, total_chunks)
67+
progress.setWindowTitle("Processing")
68+
progress.setWindowModality(Qt.WindowModal)
69+
progress.setMinimumDuration(0)
70+
71+
unique_values = set()
72+
chunk_count = 0
73+
74+
# Read in chunks to avoid loading entire raster into memory
75+
for y in range(0, gdal_file.RasterYSize, chunk_size):
76+
ysize = min(chunk_size, gdal_file.RasterYSize - y)
77+
for x in range(0, gdal_file.RasterXSize, chunk_size):
78+
if progress.wasCanceled():
79+
gdal_file = None
80+
return []
81+
82+
xsize = min(chunk_size, gdal_file.RasterXSize - x)
83+
chunk = raster_band.ReadAsArray(x, y, xsize, ysize)
84+
unique_values.update(np.unique(chunk).tolist())
85+
86+
chunk_count += 1
87+
progress.setValue(chunk_count)
88+
QApplication.processEvents()
89+
90+
progress.close()
91+
gdal_file = None # Close the file
92+
return sorted(unique_values)
93+
94+
5595
def auto_symbology_classification_render(layer, band):
5696
# get the unique values in the band
57-
rows = layer.height()
58-
cols = layer.width()
59-
provider = layer.dataProvider()
60-
bl = provider.block(band, provider.extent(), cols, rows)
61-
unique_values = list(set([bl.value(r, c) for r in range(rows) for c in range(cols)]))
97+
unique_values = get_unique_values(layer, band)
98+
99+
if not unique_values:
100+
return
62101

63102
# fill categories
64103
categories = []
@@ -172,7 +211,7 @@ def safe_call(method, *args):
172211

173212
def copy_band_metadata(src, dst):
174213
"""Copy all metadata from source band to destination band
175-
214+
176215
Args:
177216
src: Source GDAL raster band
178217
dst: Destination GDAL raster band
@@ -225,7 +264,7 @@ def copy_band_metadata(src, dst):
225264

226265
def copy_dataset_metadata(src, dst):
227266
"""Copy all metadata from source dataset to destination dataset
228-
267+
229268
Args:
230269
src: Source GDAL dataset
231270
dst: Destination GDAL dataset
@@ -248,4 +287,3 @@ def copy_dataset_metadata(src, dst):
248287
gcps = src.GetGCPs()
249288
if gcps:
250289
safe_call(dst.SetGCPs, gcps, src.GetGCPProjection())
251-

0 commit comments

Comments
 (0)