Recherche d'alternative aux statistiques focales ArcGIS dans Python open source

Sep 10 2020

J'ai du mal à faire l'agrégation de pixels de raster en python open-source comme le fait la fonction de statistiques ArcGIS Focal, je voudrais créer une fenêtre rectangulaire 5 x 5 sur laquelle la fonction du programme calculera la moyenne du pixel central en utilisant pixels voisins tombant à l'intérieur de la fenêtre définie. Mes valeurs raster en entrée sont au format flottant 0 - 1. Quelqu'un peut-il suggérer une façon possible de le faire en python?

J'ai essayé le code ci-dessous, cela ne fonctionne pas

import time 
import glob
import os
import gdal
import osr
import numpy as np 

start_time_script = time.clock()

path_ras=r'D:\Firm_SM\F1A/'

for rasterfile in glob.glob(os.path.join(path_ras,'*.tif')):
    rasterfile_name=str(rasterfile[rasterfile.find('IMG'):rasterfile.find('.tif')])

print ('Processing:'+ ' ' + str(rasterfile_name))

ds = gdal.Open(rasterfile,gdal.GA_ReadOnly)
ds_xform = ds.GetGeoTransform()

print (ds_xform)

ds_driver = gdal.GetDriverByName('Gtiff')
srs = osr.SpatialReference()
#srs.ImportFromEPSG(4726)

ds_array = ds.ReadAsArray()

sz = ds_array.itemsize

print ('This is the size of the neighbourhood:' + ' ' + str(sz))

h,w = ds_array.shape

print ('This is the size of the Array:' + ' ' + str(h) + ' ' + str(w))

bh, bw = 5,5

shape = (h/bh, w/bw, bh, bw)

print ('This is the new shape of the Array:' + ' ' + str(shape))

strides = sz*np.array([w*bh,bw,w,1])

blocks = np.lib.stride_tricks.as_strided(ds_array,shape=shape,strides=strides)

resized_array = ds_driver.Create(rasterfile_name + '_resized_to_52m.tif',shape[1],shape[0],1,gdal.GDT_Float32)
resized_array.SetGeoTransform((ds_xform[0],ds_xform[1]*2,ds_xform[2],ds_xform[3],ds_xform[4],ds_xform[5]*2))
resized_array.SetProjection(srs.ExportToWkt())
band = resized_array.GetRasterBand(1)

zero_array = np.zeros([shape[0],shape[1]],dtype=np.float32)

print ('I start calculations using neighbourhood')
start_time_blocks = time.clock()

for i in xrange(len(blocks)):
    for j in xrange(len(blocks[i])):

        zero_array[i][j] = np.mean(blocks[i][j])

print ('I finished calculations and I am going to write the new array')

band.WriteArray(zero_array)

end_time_blocks = time.clock() - start_time_blocks

print ('Image Processed for:' + ' ' + str(end_time_blocks) + 'seconds' + '\n')

end_time = time.clock() - start_time_script
print ('Program ran for: ' + str(end_time) + 'seconds')  

MOdified code basé sur la suggestion @Neprin, cependant, je voudrais le modifier en fonction de ma structure de fichier, veuillez aider à ce sujet

import numpy as np
import gdal
import cv2
import matplotlib.pyplot as plt
import seaborn as sns

img = gdal.Open('20180305.tif').ReadAsArray() # i have multiple raster i.e.20180305, 20180306, 20180305 so on  
 # i want put give the path of folder where i kept my input raster 
img2 = np.zeros(np.array(img.shape) + 10)
img2[5:-5,5:-5] = img  # fix edge interpolation
kernel = np.ones((5,5),np.float32)
dst = cv2.filter2D(img2,-1,kernel)/25

# Save the output raster in same name as input with projection
  

Réponses

Neperin Sep 10 2020 at 03:29

une autre alternative consiste à utiliser le filtrage d'images opencv2 ( lien ):

import numpy as np
import cv2
import matplotlib.pyplot as plt
import seaborn as sns

img = np.diag([1, 1, 1, 1, 1, 1, 1]).astype('float')
img2 = np.zeros(np.array(img.shape) + 10)
img2[5:-5,5:-5] = img  # fix edge interpolation
kernel = np.ones((5,5),np.float32)
dst = cv2.filter2D(img2,-1,kernel)/25

plt.figure(figsize=(15,10))
plt.subplot(121)
sns.heatmap(img2[5:-5, 5:-5], annot=True, cbar=False)
plt.title('original')
plt.subplot(122)
sns.heatmap(dst[5:-5, 5:-5], annot=True, cbar=False)
plt.title('focal')

Aaron Sep 09 2020 at 22:29

L' r.neighborsoutil de GRASS est similaire aux statistiques focales d'ArcGIS. Chacun permet des statistiques calculées dans une fenêtre mobile.

r.neighbors - Fait de chaque valeur de catégorie de cellule une fonction des valeurs de catégorie affectées aux cellules qui l'entourent et stocke les nouvelles valeurs de cellule dans une couche de carte raster en sortie.

mikewatt Sep 10 2020 at 02:33

Vous pouvez utiliser le ndimage.convolve de scipy :

from scipy.ndimage import convolve

weights = np.ones((5, 5))

focal_mean = convolve(ds_array, weights) / np.sum(weights)
radouxju Sep 10 2020 at 03:00

Une autre solution consiste à utiliser Orfeo Toolbox. Il a une fonction appelée BandMathX qui effectue la statistique focale basée sur n'importe quel voisinage et une grande variété de fonctions, ou l'application de lissage avec moins de choix mais avec la fonction moyenne. Le lissage est plus facile à utiliser mais BandMathX est plus flexible. Voici un exemple d'utilisation de l'application Smoothing, avec plus de détails ici sur la façon d'installer l'API Python.

# The python module providing access to OTB applications is otbApplication
import otbApplication as otb

# Let's create the application with codename "Smoothing"
app = otb.Registry.CreateApplication("Smoothing")

# We set its parameters
app.SetParameterString("in", "my_input_image.tif")
app.SetParameterString("type", "mean")
app.SetParameterString("out", "my_output_image.tif")
app.SetParameterString("type.mean.radius",2)

# This will execute the application and save the output file
app.ExecuteAndWriteOutput()