5.1. Local Operators in Python

In scipy.ndimage several local image operators are available. Ranging from the linear filters (a.o. convolve, correlate, gaussian, prewitt, sobel) to the morphological filters (a.o. erosion, dilation, opening and closing). See http://docs.scipy.org/doc/scipy/reference/ndimage.html.

A nice function in scipy.ndimage is the generic_filter. This allows you to quickly make a prototype of a filter and test it on image. It won´t be fast but you get results fast.

For instance consider the local filter where the neighborhood is a 19 by 19 window and the resulting value is the mean of this neighborhood: a simple uniform linear filter.

Although the uniform filter is available in specialized form in scipy.ndimage we will discuss what is needed to implement this filter using the generic_filter.

In [1]: from pylab import *

In [2]: from scipy.ndimage import generic_filter

In [3]: f = imread('images/trui.png')

In [4]: subplot(121);

In [5]: imshow(f, cmap=cm.gray);

In [6]: g = generic_filter(f, mean, size=(19,19))

In [7]: subplot(122);

In [8]: imshow(g, cmap=cm.gray);
../../../_images/unif19x19.png

Here we have used the numpy function mean to calculate the mean value of \(19^2\) values. The generic_filter function takes care of

  1. the loop over all pixels,
  2. get all \(19^2\) values from the neighborhood,
  3. taking care of the border (you can specify a way to deal with the border),
  4. call the supplied function (mean in our case) and
  5. setting the pixel in the output image equal to the returned value.

Implementing a median filter then is simple: change mean into median:

In [9]: from pylab import *

In [10]: from scipy.ndimage import generic_filter

In [11]: f = imread('images/trui.png')

In [12]: subplot(121);

In [13]: imshow(f, cmap=cm.gray);

In [14]: g = generic_filter(f, median, size=(19,19))

In [15]: subplot(122);

In [16]: imshow(g, cmap=cm.gray);
../../../_images/median19x19.png

You are not restricted to select a buildin function. You can define your own function and use that. A disavantage of this generic filter function is that all pixel values in the neighborhood are passed to your own function in a 1D array. You can easily figure out in what order they are passed but it is not documented i think.

Note that we have shown two local operators (filters) that are also available as specialized implementations. Without doubt the specialized versions are much faster then the generic ones. The linear uniform filter can be made a lot faster by decomposing it into two consequtive linear filters (this will be discussed in another section on separable kernels.)

The median filter is notably more difficult to speed up. In the section on percentile filtering a classical method to speed up the median image filter is discussed.

A word of warning is important here. Never expect that a low image image processing algorithm (like an local image filter) can be optimally implemented in an interpreted language like Python. Low level image processing is best done in a low level language (like C or C++). Nevertheless languages like Python are very usefull to make prototypes, to test new ideas.