I have a binary raster (.tif) in ArcGIS that shows builtup areas (value=1) and non builtup areas (value=0) like this:
In order to make a proximity analysis, I need to iterate through the raster with arcpy/python and for each cell (i) get the distance to EVERY other cell (j) with value=1 within in a given radius around the current cell (i) and write all those distance values to a list/array.
Is there a performant way to do this using Python?
I know there is the EucDistance tool in ArcGIS:
but it may not be the smartest, to create several thousand new rasters.
My plan was to use a RasterToNumpyArray and then calculate on the numpy array
So far I tried the following Python code:
import numpy
from scipy.spatial import distance
def dist_euclid(cell_a, cell_b):
dist = distance.euclidean(cell_a, cell_b)
return dist
'''Masking is important to speed up processes'''
def cmask(coords, radius, array):
a, b = coords[0], coords[1]
nx, ny = array.shape
y, x = numpy.ogrid[-a:nx - a, -b:ny - b]
# create mask where each value in radius around coords is true and everything else is false
mask = x * x + y * y <= radius * radius
# reshape mask to rectangular shape
i, j = numpy.where(mask)
indices = numpy.meshgrid(numpy.arange(min(i), max(i) + 1),
numpy.arange(min(j), max(j) + 1),
indexing='ij')
masked_array = array[tuple(indices)]
return masked_array
def calcCellDistancesForEachCellInRaster(in_array, buffer_size):
'''For each cell make slice sub-array around the cell and calculate distances to every other cell (value=1)'''
dist_arr = []
for (source_x, source_y), source_value in numpy.ndenumerate(in_array):
if source_value == 1:
masked_array = cmask([source_x, source_y], buffer_size, in_array)
for (target_x, target_y), target_value in numpy.ndenumerate(masked_array):
if target_value == 1 and ([source_x, source_y] != [target_x, target_y]):
dist = dist_euclid([source_x, source_y], [target_x, target_y])
if dist <= buffer_size:
dist_arr.append(dist)
# print("dist from %s to %s = %s" % ([source_x, source_y], [target_x, target_y], dist))
else:
pass
else:
pass
return dist_arr
# Create a simple array from scratch using random values
myArray = numpy.random.randint(2, size=(100, 100))
myArray.shape = (100, 100)
dist_arr = calcCellDistancesForEachCellInRaster(myArray, 2)