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 the ndimage documentaion.

A nice function in scipy.ndimage is the generic_filter. This allows us to quickly make a prototype of a filter and test it on image. It won´t be fast but you get results (a working program) 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.

1f = plt.imread(ipcv_image_path('trui.png'))
2g = generic_filter(f, np.mean, size=(19,19))
../../../_images/unif19x19.png

Fig. 5.2 Uniform Filter.

Here we have used the numpy function np.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 np.mean into np.median:

1f = plt.imread(ipcv_image_path('trui.png'))
2g = generic_filter(f, np.median, size=(19,19))
../../../_images/median19x19.png

Fig. 5.3 Median Filter.

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 consecutive 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 level image processing algorithm (like a 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, i.e. to test new ideas (and of course as a language to glue all kinds of low level operators implemented in a low level language together, this is how a lot of the modern CV and ML frame works are often used, like OpenCV for computer vision and PyTorch for machine learning).