I am working with some image processing routines, using binary images. In Matlab I can create a lookup table which provides the output for every possible 2^9=512 configurations of 3 x 3 neighbourhoods. That is, I can write a function func
which produces a 0 or 1 for such a neighbourhood, and then create a lookup table with
lut = makelut(func,3)
(the "3" indicating the size of neighbourhood). Then that lookup table can be applied to my binary image im
with
applylut(im, lut)
But how can I do the same thing in Python? There is an example given here:
http://pydoc.net/Python/scikits-image/0.4.2/skimage.morphology.skeletonize/
which certainly works, but seems very complicated, at least compared to Matlab's commands.
The filters defined in scipy.ndimage
may be of use to you. If none of the pre-defined filters match your intent, you can apply a custom filter using
scipy.ndimage.generic_filter
.
For example, you can reproduce the result shown on the Mathworks applylut doc page with:
import numpy as np
import scipy.ndimage as ndimage
from PIL import Image
filename = '/tmp/PerformErosionUsingA2by2NeighborhoodExample_01.png'
img = Image.open(filename).convert('L')
arr = np.array(img)
def func(x):
return (x==255).all()*255
arr2 = ndimage.generic_filter(arr, func, size=(2,2))
new_img = Image.fromarray(arr2.astype('uint8'), 'L')
new_img.save('/tmp/out.png')
PerformErosionUsingA2by2NeighborhoodExample_01.png:
out.png:
Note that in this case, ndimage.grey_erosion
can produce the same result, and
since it is not calling a Python function once for every pixel, it's also a lot
faster:
arr3 = ndimage.grey_erosion(arr, size=(2,2))
print(np.allclose(arr2,arr3))
# True
Depending on the kind of computation you wish to perform in func
, another faster alternative may be to express the result as a NumPy computation on slices. For example, the above grey_erosion
could also be expressed as
arr4 = np.pad(arr.astype(bool), ((1,0),(1,0)), 'reflect')
arr4 = arr4[:-1,:-1] & arr4[1:,:-1] & arr4[:-1,1:] & arr4[1:,1:]
arr4 = arr4.astype('uint8')*255
assert np.allclose(arr3, arr4)
Again this is much faster than using generic_filter
since here the computation is being performed on whole arrays rather than pixel-by-pixel.