mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #25734 -- Made GDALBand min and max properties use GDALComputeRasterStatistics.
Thanks Sergey Fedoseev and Tim Graham for the review.
This commit is contained in:
		
				
					committed by
					
						 Tim Graham
						Tim Graham
					
				
			
			
				
	
			
			
			
						parent
						
							2cb50f935a
						
					
				
				
					commit
					8f5904560a
				
			| @@ -62,8 +62,17 @@ get_band_ds = voidptr_output(std_call('GDALGetBandDataset'), [c_void_p]) | ||||
| get_band_datatype = int_output(std_call('GDALGetRasterDataType'), [c_void_p]) | ||||
| get_band_nodata_value = double_output(std_call('GDALGetRasterNoDataValue'), [c_void_p, POINTER(c_int)]) | ||||
| set_band_nodata_value = void_output(std_call('GDALSetRasterNoDataValue'), [c_void_p, c_double]) | ||||
| get_band_minimum = double_output(std_call('GDALGetRasterMinimum'), [c_void_p, POINTER(c_int)]) | ||||
| get_band_maximum = double_output(std_call('GDALGetRasterMaximum'), [c_void_p, POINTER(c_int)]) | ||||
| get_band_statistics = void_output(std_call('GDALGetRasterStatistics'), | ||||
|     [ | ||||
|         c_void_p, c_int, c_int, POINTER(c_double), POINTER(c_double), | ||||
|         POINTER(c_double), POINTER(c_double), c_void_p, c_void_p, | ||||
|     ], | ||||
|     errcheck=False | ||||
| ) | ||||
| compute_band_statistics = void_output(std_call('GDALComputeRasterStatistics'), | ||||
|     [c_void_p, c_int, POINTER(c_double), POINTER(c_double), POINTER(c_double), POINTER(c_double), c_void_p, c_void_p], | ||||
|     errcheck=False | ||||
| ) | ||||
|  | ||||
| # Reprojection routine | ||||
| reproject_image = void_output(std_call('GDALReprojectImage'), | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| from ctypes import byref, c_int | ||||
| import math | ||||
| from ctypes import byref, c_double, c_int, c_void_p | ||||
|  | ||||
| from django.contrib.gis.gdal.base import GDALBase | ||||
| from django.contrib.gis.gdal.error import GDALException | ||||
| @@ -19,6 +20,14 @@ class GDALBand(GDALBase): | ||||
|         self.source = source | ||||
|         self._ptr = capi.get_ds_raster_band(source._ptr, index) | ||||
|  | ||||
|     def _flush(self): | ||||
|         """ | ||||
|         Call the flush method on the Band's parent raster and force a refresh | ||||
|         of the statistics attribute when requested the next time. | ||||
|         """ | ||||
|         self.source._flush() | ||||
|         self._stats_refresh = True | ||||
|  | ||||
|     @property | ||||
|     def description(self): | ||||
|         """ | ||||
| @@ -47,19 +56,80 @@ class GDALBand(GDALBase): | ||||
|         """ | ||||
|         return self.width * self.height | ||||
|  | ||||
|     _stats_refresh = False | ||||
|  | ||||
|     def statistics(self, refresh=False, approximate=False): | ||||
|         """ | ||||
|         Compute statistics on the pixel values of this band. | ||||
|  | ||||
|         The return value is a tuple with the following structure: | ||||
|         (minimum, maximum, mean, standard deviation). | ||||
|  | ||||
|         If approximate=True, the statistics may be computed based on overviews | ||||
|         or a subset of image tiles. | ||||
|  | ||||
|         If refresh=True, the statistics will be computed from the data directly, | ||||
|         and the cache will be updated where applicable. | ||||
|  | ||||
|         For empty bands (where all pixel values are nodata), all statistics | ||||
|         values are returned as None. | ||||
|  | ||||
|         For raster formats using Persistent Auxiliary Metadata (PAM) services, | ||||
|         the statistics might be cached in an auxiliary file. | ||||
|         """ | ||||
|         # Prepare array with arguments for capi function | ||||
|         smin, smax, smean, sstd = c_double(), c_double(), c_double(), c_double() | ||||
|         stats_args = [ | ||||
|             self._ptr, c_int(approximate), byref(smin), byref(smax), | ||||
|             byref(smean), byref(sstd), c_void_p(), c_void_p(), | ||||
|         ] | ||||
|  | ||||
|         if refresh or self._stats_refresh: | ||||
|             capi.compute_band_statistics(*stats_args) | ||||
|         else: | ||||
|             # Add additional argument to force computation if there is no | ||||
|             # existing PAM file to take the values from. | ||||
|             force = True | ||||
|             stats_args.insert(2, c_int(force)) | ||||
|             capi.get_band_statistics(*stats_args) | ||||
|  | ||||
|         result = smin.value, smax.value, smean.value, sstd.value | ||||
|  | ||||
|         # Check if band is empty (in that case, set all statistics to None) | ||||
|         if any((math.isnan(val) for val in result)): | ||||
|             result = (None, None, None, None) | ||||
|  | ||||
|         self._stats_refresh = False | ||||
|  | ||||
|         return result | ||||
|  | ||||
|     @property | ||||
|     def min(self): | ||||
|         """ | ||||
|         Returns the minimum pixel value for this band. | ||||
|         Return the minimum pixel value for this band. | ||||
|         """ | ||||
|         return capi.get_band_minimum(self._ptr, byref(c_int())) | ||||
|         return self.statistics()[0] | ||||
|  | ||||
|     @property | ||||
|     def max(self): | ||||
|         """ | ||||
|         Returns the maximum pixel value for this band. | ||||
|         Return the maximum pixel value for this band. | ||||
|         """ | ||||
|         return capi.get_band_maximum(self._ptr, byref(c_int())) | ||||
|         return self.statistics()[1] | ||||
|  | ||||
|     @property | ||||
|     def mean(self): | ||||
|         """ | ||||
|         Return the mean of all pixel values of this band. | ||||
|         """ | ||||
|         return self.statistics()[2] | ||||
|  | ||||
|     @property | ||||
|     def std(self): | ||||
|         """ | ||||
|         Return the standard deviation of all pixel values of this band. | ||||
|         """ | ||||
|         return self.statistics()[3] | ||||
|  | ||||
|     @property | ||||
|     def nodata_value(self): | ||||
| @@ -84,7 +154,7 @@ class GDALBand(GDALBase): | ||||
|         if not isinstance(value, (int, float)): | ||||
|             raise ValueError('Nodata value must be numeric.') | ||||
|         capi.set_band_nodata_value(self._ptr, value) | ||||
|         self.source._flush() | ||||
|         self._flush() | ||||
|  | ||||
|     def datatype(self, as_string=False): | ||||
|         """ | ||||
| @@ -149,7 +219,7 @@ class GDALBand(GDALBase): | ||||
|             else: | ||||
|                 return list(data_array) | ||||
|         else: | ||||
|             self.source._flush() | ||||
|             self._flush() | ||||
|  | ||||
|  | ||||
| class BandList(list): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user