Image filtering with scikit-image?

Alasdair picture Alasdair · Apr 22, 2014 · Viewed 9.2k times · Source

I'm moving to python from a Matlab background, and there are a few elementary operations I've yet to conquer in Python/skimage:

  1. How can I apply a user-generated linear filter (given as a small 2d array) to an image? I can do it with scipy.ndimage.convolve, but is there a method in skimage?

  2. In Matlab, image filtering always returns a result of the same numeric type as its input, be it uint8 or float. Does skimage behave the same way?

  3. Does skimage include unsharp masking somewhere? (I've found an unsharp masking filter in PIL but that's a bit of a pain, as PIL uses its own Image class, rather than ndarrays).

  4. Is there a method, maybe similar to Matlab's "colfilt" by which a user can apply a non-linear filter to an image? The idea is that the user supplies a function which produces a single number from a 3x3 array, say; then that function is applied across the image as a spatial filter.

Answer

Tony S Yu picture Tony S Yu · Apr 25, 2014

How can I apply a user-generated linear filter (given as a small 2d array) to an image? I can do it with scipy.ndimage.convolve, but is there a method in skimage?

The goal of scikit-image (and the scikits, in general) is to extend the functionality of scipy. (Smaller, more focused projects tend to evolve more rapidly than larger ones.) It tries not to duplicate any functionality, and only does so if it can improve upon that functionality.

In Matlab, image filtering always returns a result of the same numeric type as its input, be it uint8 or float. Does skimage behave the same way?

No, there is no such guarantee. Sometimes it's just more efficient to convert to a single type. (Sometimes, it's just a lack of time/man-power.) Here's some documentation on the matter:

http://scikit-image.org/docs/0.9.x/user_guide/data_types.html#output-types

There are convenient methods (e.g. img_as_float, img_as_ubyte) for transforming images if you need a certain type (and they check if the input type is the desired type, so you don't go wasting time with unnecessary conversion).

Does skimage include unsharp masking somewhere? (I've found an unsharp masking filter in PIL but that's a bit of a pain, as PIL uses its own Image class, rather than ndarrays).

Not that I know of, but you could roll your own. Something like the following would work:

from skimage import data
from skimage import filter
from skimage import img_as_float
import matplotlib.pyplot as plt


unsharp_strength = 0.8
blur_size = 8  # Standard deviation in pixels.

# Convert to float so that negatives don't cause problems
image = img_as_float(data.camera())
blurred = filter.gaussian_filter(image, blur_size)
highpass = image - unsharp_strength * blurred
sharp = image + highpass


fig, axes = plt.subplots(ncols=2)
axes[0].imshow(image, vmin=0, vmax=1)
axes[1].imshow(sharp, vmin=0, vmax=1)
plt.show()

Homebrew unsharp-mask

There are, however, many ways to implement unsharp masking.

Is there a method, maybe similar to Matlab's "colfilt" by which a user can apply a non-linear filter to an image? The idea is that the user supplies a function which produces a single number from a 3x3 array, say; then that function is applied across the image as a spatial filter.

Not in scikit-image, but there's generic filtering capability in scipy.ndimage:

https://docs.scipy.org/doc/scipy-0.19.0/reference/generated/scipy.ndimage.generic_filter.html