# ImageFiltering.jl

ImageFiltering supports linear and nonlinear filtering operations on arrays, with an emphasis on the kinds of operations used in image processing. The core function is `imfilter`

, and common kernels (filters) are organized in the `Kernel`

and `KernelFactors`

modules.

## Demonstration

Let's start with a simple example of linear filtering:

```
julia> using ImageFiltering, TestImages
julia> img = testimage("mandrill");
julia> imgg = imfilter(img, Kernel.gaussian(3));
julia> imgl = imfilter(img, Kernel.Laplacian());
```

When displayed, these three images look like this:

The most commonly used function for filtering is `imfilter`

.

## Linear filtering: noteworthy features

### Correlation, not convolution

ImageFiltering uses the following formula to calculate the filtered image `F`

from an input image `A`

and kernel `K`

:

\[F[I] = \sum_J A[I+J] K[J]\]

Consequently, the resulting image is the correlation, not convolution, of the input and the kernel. If you want the convolution, first call `reflect`

on the kernel.

### Kernel indices

ImageFiltering exploits a feature introduced into Julia 0.5, the ability to define arrays whose indices span an arbitrary range:

```
julia> Kernel.gaussian(1)
OffsetArray{Float64,2,Array{Float64,2}} with indices -2:2×-2:2:
0.00296902 0.0133062 0.0219382 0.0133062 0.00296902
0.0133062 0.0596343 0.0983203 0.0596343 0.0133062
0.0219382 0.0983203 0.162103 0.0983203 0.0219382
0.0133062 0.0596343 0.0983203 0.0596343 0.0133062
0.00296902 0.0133062 0.0219382 0.0133062 0.00296902
```

The indices of this array span the range `-2:2`

along each axis, and the center of the gaussian is at position `[0,0]`

. As a consequence, this filter "blurs" but does not "shift" the image; were the center instead at, say, `[3,3]`

, the filtered image would be shifted by 3 pixels downward and to the right compared to the original.

The `centered`

function is a handy utility for converting an ordinary array to one that has coordinates `[0,0,...]`

at its center position:

```
julia> centered([1 0 1; 0 1 0; 1 0 1])
OffsetArray{Int64,2,Array{Int64,2}} with indices -1:1×-1:1:
1 0 1
0 1 0
1 0 1
```

See OffsetArrays for more information.

### Factored kernels

A key feature of Gaussian kernels–-along with many other commonly-used kernels–-is that they are *separable*, meaning that `K[j_1,j_2,...]`

can be written as $K_1[j_1] K_2[j_2] \cdots$. As a consequence, the correlation

\[F[i_1,i_2] = \sum_{j_1,j_2} A[i_1+j_1,i_2+j_2] K[j_1,j_2]\]

can be written

\[F[i_1,i_2] = \sum_{j_2} \left(\sum_{j_1} A[i_1+j_1,i_2+j_2] K_1[j_1]\right) K_2[j_2]\]

If the kernel is of size `m×n`

, then the upper version line requires `mn`

operations for each point of `filtered`

, whereas the lower version requires `m+n`

operations. Especially when `m`

and `n`

are larger, this can result in a substantial savings.

To enable efficient computation for separable kernels, `imfilter`

accepts a tuple of kernels, filtering the image by each sequentially. You can either supply `m×1`

and `1×n`

filters directly, or (somewhat more efficiently) call `kernelfactors`

on a tuple-of-vectors:

```
julia> kern1 = centered([1/3, 1/3, 1/3])
OffsetArray{Float64,1,Array{Float64,1}} with indices -1:1:
0.333333
0.333333
0.333333
julia> kernf = kernelfactors((kern1, kern1))
(ImageFiltering.KernelFactors.ReshapedOneD{Float64,2,0,OffsetArray{Float64,1,Array{Float64,1}}}([0.333333,0.333333,0.333333]),ImageFiltering.KernelFactors.ReshapedOneD{Float64,2,1,OffsetArray{Float64,1,Array{Float64,1}}}([0.333333,0.333333,0.333333]))
julia> kernp = broadcast(*, kernf...)
OffsetArray{Float64,2,Array{Float64,2}} with indices -1:1×-1:1:
0.111111 0.111111 0.111111
0.111111 0.111111 0.111111
0.111111 0.111111 0.111111
julia> imfilter(img, kernf) ≈ imfilter(img, kernp)
true
```

If the kernel is a two dimensional array, `imfilter`

will attempt to factor it; if successful, it will use the separable algorithm. You can prevent this automatic factorization by passing the kernel as a tuple, e.g., as `(kernp,)`

.

### Popular kernels in Kernel and KernelFactors modules

The two modules `Kernel`

and `KernelFactors`

implement popular correlation kernels in "dense" and "factored" forms, respectively. Type `?Kernel`

or `?KernelFactors`

at the REPL to see which kernels are supported.

A common task in image processing and computer vision is computing image *gradients* (derivatives), for which there is the dedicated function `imgradients`

.

### Automatic choice of FIR or FFT

For linear filtering with a finite-impulse response filtering, one can either choose a direct algorithm or one based on the fast Fourier transform (FFT). By default, this choice is made based on kernel size. You can manually specify the algorithm using `Algorithm.FFT()`

or `Algorithm.FIR()`

.

### Multithreading

If you launch Julia with `JULIA_NUM_THREADS=n`

(where `n > 1`

), then FIR filtering will by default use multiple threads. You can control the algorithm by specifying a *resource* as defined by ComputationalResources. For example, `imfilter(CPU1(Algorithm.FIR()), img, ...)`

would force the computation to be single-threaded.

## Arbitrary operations over sliding windows

This package also exports `mapwindow`

, which allows you to pass an arbitrary function to operate on the values within a sliding window.

`mapwindow`

has optimized implementations for some functions (currently, `extrema`

).