Julia package LocalFilters implements multi-dimensional local
filters such as discrete convolution or correlation, local mean, mathematical morphology,
etc., and provides support to build custom local filters.
The Reference Manual provides more
exhaustive documentation. This page summarizes the principles and the features of
LocalFilters:
-
Available filters lists ready to use filters.
-
Kernels and neighborhoods describes the concept of kernels and neighborhoods which define which (and how) values are involved in a local filter.
-
Build your own filters explains how to implement custom local filters.
-
Local mapping and reduction describes methods for computing local mappings and reductions.
-
Installation gives instructions to install the package.
Packages with overlapping functionalities:
-
ImageFiltering for local filters on multidimensional arrays (not just images), also implement various boundary conditions;
-
ImageMorphology for fast morphological operations with separable structuring elements.
LocalFilters provides a number of linear and non-linear filters. All methods have an
in-place counterpart which can be called to avoid allocations.
LocalFilters provides the following linear filters:
-
localmean(A,B=3)performs a local averaging ofAin a neighborhood defined byB. -
correlate(A,B)performs a discrete correlation ofAby the kernelB. This is the most general linear filter. -
convolve(A,B)performs a discrete convolution ofAby the kernelB. This is the same as a discrete correlation ofAbyreverse_kernel(B).
LocalFilters implements the following mathematical
morphology operations:
-
erode(A,B=3)performs an erosion (local minimum) ofAby the structuring elementB; -
dilate(A,B=3)performs a dilation (local maximum) ofAby the structuring elementB; -
localextrema(A,B=3)yields the erosion and the dilation ofAby the structuring elementB; -
opening(A,B=3)performs an erosion followed by a dilation ofAby the structuring elementB; -
closing(A,B=3)performs a dilation followed by an erosion ofAby the structuring elementB; -
top_hat(A,B=3[,S])performs a summit detection ofAby the structuring elementB(argumentSmay be optionally supplied to pre-smoothAbyS); -
bottom_hat(A,B=3[,S])performs a valley detection ofAby the structuring elementB(argumentSmay be optionally supplied to pre-smoothAbyS).
In mathematical morphology, the structuring element B defines the local neighborhood of
each index in the source array. It can be a sliding hyper-rectangular Cartesian window or
an array of Booleans to define a more complex neighborhood shape. If B is a single odd
integer (as it is by default), the structuring element is assumed to be a centered sliding
window of size B along every dimension of A.
LocalFilters provides an instance of the bilateral
filter:
bilateralfilter(A,F,G,B)performs a bilateral filtering of arrayAwithFthe range kernel for smoothing differences in values,Gthe spatial kernel for smoothing differences in coordinates, andBthe neighborhood. Alternatively one can specify the range and spatial parametersbilateralfilter(A,σr,σs,B=2*round(Int,3σs)+1)for using Gaussian kernels with standard deviationsσrandσs.
Neighborhoods define which array elements around the element of interest are involved in
the result of the local filter. Neighborhoods can be represented by arrays of Booleans,
they are also known as sliding windows in image processing or as structuring element
in mathematical morphology. Neighborhoods whose elements are uniformly true are equivalent
to hyper-rectangular sliding wondows whose axes are aligned with the Cartesian axes. A
kernel is similar to a neighborhood but its elements have values which represent the
coefficients or the weights of the filter. Kernels and neighborhoods are built by the
kernel function.
In LocalFilters, a local filtering operation, say dst = filter(A, B) with A the
source of the operation and B the neighborhood or the kernel associated with the filter,
is implemented by the following pseudo-code:
for i ∈ indices(dst)
v = initial isa Function ? initial(A[i]) : initial
for j ∈ indices(A) ∩ (indices(B) + i)
v = update(v, A[j], B[j-i])
end
dst[i] = final(v)
endwhere indices(A) denotes the set of indices of A while indices(B) + i denotes the
set of indices j such that j - i ∈ indices(B) with indices(B) the set of indices of
B. In other words, j ∈ indices(A) ∩ (indices(B) + i) means all indices j such that
j ∈ indices(A) and j - i ∈ indices(B), hence A[j] and B[j-i] are in-bounds. In
LocalFilters, indices i and j are Cartesian indices for multi-dimensional arrays,
thus indices(A) is the analogous of CartesianIndices(A) in Julia in that case. For
vectors, indices i and j are linear indices.
The behavior of the filter is completely determined by the neighborhood or kernel B, by
the type of the state variable v initialized by initial for each entry of the
destination, and by the methods update and final.
Such a filter can be applied by calling localfilter! as:
localfilter!(dst, A, B, initial, update, final = identity) -> dstWhen initial is a function, A and dst must have the same indices; localfilter!
will throw a DimensionMismatch if this is not the case.
As shown by the following examples, this simple scheme allows the implementation of a variety of linear and non-linear local filters:
-
Implementing a local average of
Ain a neighborhood defined by an arrayBof Booleans is done with:localfilter!(dst, A, B, #= initial =# (; num = zero(eltype(A)), den = 0), #= update =# (v,a,b) -> ifelse(b, (; num = v.num + a, den = v.den + 1), v), #= final =# (v) -> v.num / v.den)
-
Assuming
T = eltype(dst)is a suitable element type for the result, a discrete correlation ofAbyBcan be implemented with:localfilter!(dst, A, B, #= initial =# zero(T), #= update =# (v,a,b) -> v + a*b)
There are no needs to specify the
finalmethod here, as the defaultfinal = identity, does the job. -
Computing a local maximum (that is, a dilation in mathematical morphology terms) of array
Awith a kernelBwhose entries are Booleans can be done with:localfilter!(dst, A, B, #= initial =# typemin(eltype(A)), #= update =# (v,a,b) -> ((b & (v < a)) ? a : v))
As in the above example, there are no needs to specify the
finalmethod here. Note the use of a bitwise&instead of a&&in theupdatemethod to avoid branching.
Method localmap(f,A,B) yields the result of applying the function f to the vector of
values of A in neighborhoods defined by B. Method localmap!(f,dst,A,B) is the
in-place version of localmap(f,A,B).
Method localreduce(op,A,dims,rngs) applies the van Herk-Gil-Werman algorithm to compute
the reduction by the associative binary operator op of the values of A into contiguous
hyper-rectangular neighborhoods defined by the interval(s) rngs along dimension(s)
dims of A. Method localreduce!(op,dst,A,dims,rngs) is the in-place version of
localreduce(op,A,dims,rngs).
To install the last official version, press the ] key to enter Julia's Pkg REPL mode
and type at the ... pkg> prompt:
add LocalFiltersTo use the last development version, type instead:
add https://github.com/emmt/LocalFilters.jlThe LocalFilters package is pure Julia code and nothing has to be build.