I want to apply a circular neighborhood operation on a 2D numpy array where each pixel value is replaced by the minimum within circular neighborhood (radius = x).
I can apply a kernel based generic_filter and get the minimum but the operation takes in a square neighborhood, so that gives incorrect output.
I have tried using a for loop and perform the operation using a radius lookup table which basically is an array that gives the distance from the first pixel and uses if conditions to get the minimum. Something like this:
import numpy as np
radiusGrid = np.random.randint(6, size=100).reshape(10,10)
radiusLUT = np.ones((6,6))
print radiusGrid
for i in xrange(6):
for j in xrange(6):
radiusLUT[i][j] = max(i,j) + (min(i,j)/2)
radius = 3
for y in xrange(10):
intermediateGridRow = intermediateGrid[y]
centerRadiusGridRow = radiusGrid[y]
for x in xrange(10):
startRow = max(y - radius,0)
startCol = max(x - radius,0)
endRow = min(y + radius +1, 10)
endCol = min(x + radius +1, 10)
minRadius = centerRadiusGridRow[x]
for row in xrange(startRow,endRow):
radiusGridRow = radiusGrid[row]
radiusLUTRow = radiusLUT[abs(y-row)]
for col in xrange(startCol,endCol):
if radiusLUTRow[abs(x-col)] < radius and radiusGridRow[col] < minRadius:
minRadius = radiusGridRow[col]
intermediateGridRow[x] = minRadius
intermediateGrid[y] = intermediateGridRow
print intermediateGrid
The above was built was to get minimum within radius of 3.
The for loop implementation does work but is slow for larger arrays. I'm not inclined to use Cython or f2py. Is there a way to optimize this?
import numpy as np
from scipy.ndimage.filters import generic_filter as gf
kernel = np.zeros((2*radius+1, 2*radius+1))
y,x = np.ogrid[-radius:radius+1, -radius:radius+1]
mask = x**2 + y**2 <= radius**2
kernel[mask] = 1
#calculate
circular_min = gf(data, np.min, footprint=kernel)