Source code for nabu.misc.fourier_filters
# -*- coding: utf-8 -*-
"""
Fourier filters.
"""
from functools import lru_cache
import numpy as np
import scipy.special as spspe
[docs]
@lru_cache(maxsize=10)
def get_lowpass_filter(img_shape, cutoff_par=None, use_rfft=False, data_type=np.float64):
"""Computes a low pass filter using the erfc function.
Parameters
----------
img_shape: tuple
Shape of the image
cutoff_par: float or sequence of two floats
Position of the cut off in pixels, if a sequence is given the second float expresses the
width of the transition region which is given as a fraction of the cutoff frequency.
When only one float is given for this argument a gaussian is applied whose sigma is the
parameter.
When a sequence of two numbers is given then the filter is 1 ( no filtering) till the cutoff
frequency while a smooth erfc transition to zero is done
use_rfft: boolean, optional
Creates a filter to be used with the result of a rfft type of Fourier transform. Defaults to False.
data_type: `numpy.dtype`, optional
Specifies the data type of the computed filter. It defaults to `numpy.float64`
Raises
------
ValueError
In case of malformed cutoff_par
Returns
-------
numpy.array_like
The computed filter
"""
if cutoff_par is None:
return 1
elif isinstance(cutoff_par, (int, float)):
cutoff_pix = cutoff_par
cutoff_trans_fact = None
else:
try:
cutoff_pix, cutoff_trans_fact = cutoff_par
except ValueError:
raise ValueError(
"Argument cutoff_par (which specifies the pass filter shape) must be either a scalar or a"
" sequence of two scalars"
)
if (not isinstance(cutoff_pix, (int, float))) or (not isinstance(cutoff_trans_fact, (int, float))):
raise ValueError(
"Argument cutoff_par (which specifies the pass filter shape) must be one number or a sequence"
"of two numbers"
)
coords = [np.fft.fftfreq(s, 1) for s in img_shape]
coords = np.meshgrid(*coords, indexing="ij")
r = np.sqrt(np.sum(np.array(coords, dtype=data_type) ** 2, axis=0))
if cutoff_trans_fact is not None:
k_cut = 0.5 / cutoff_pix
k_cut_width = k_cut * cutoff_trans_fact
k_pos_rescaled = (r - k_cut) / k_cut_width
res = spspe.erfc(k_pos_rescaled) / 2
else:
res = np.exp(-(np.pi**2) * (r**2) * (cutoff_pix**2) * 2)
# Making sure to force result to chosen data type
res = res.astype(data_type)
if use_rfft:
slicelist = [slice(None)] * (len(res.shape) - 1) + [slice(0, res.shape[-1] // 2 + 1)]
return res[tuple(slicelist)]
else:
return res
[docs]
def get_highpass_filter(img_shape, cutoff_par=None, use_rfft=False, data_type=np.float64):
"""Computes a high pass filter using the erfc function.
Parameters
----------
img_shape: tuple
Shape of the image
cutoff_par: float or sequence of two floats
Position of the cut off in pixels, if a sequence is given the second float expresses the
width of the transition region which is given as a fraction of the cutoff frequency.
When only one float is given for this argument a gaussian is applied whose sigma is the
parameter, and the result is subtracted from 1 to obtain the high pass filter
When a sequence of two numbers is given then the filter is 1 ( no filtering) above the cutoff
frequency and then a smooth transition to zero is done for smaller frequency
use_rfft: boolean, optional
Creates a filter to be used with the result of a rfft type of Fourier transform. Defaults to False.
data_type: `numpy.dtype`, optional
Specifies the data type of the computed filter. It defaults to `numpy.float64`
Raises
------
ValueError
In case of malformed cutoff_par
Returns
-------
numpy.array_like
The computed filter
"""
if cutoff_par is None:
return 1
else:
return 1 - get_lowpass_filter(img_shape, cutoff_par, use_rfft=use_rfft, data_type=data_type)
[docs]
def get_bandpass_filter(img_shape, cutoff_lowpass=None, cutoff_highpass=None, use_rfft=False, data_type=np.float64):
"""Computes a band pass filter using the erfc function.
The cutoff structures should be formed as follows:
- tuple of two floats: the first indicates the cutoff frequency, the second \
determines the width of the transition region, as fraction of the cutoff frequency.
- one float -> it represents the sigma of a gaussian which acts as a filter or anti-filter (1 - filter).
Parameters
----------
img_shape: tuple
Shape of the image
cutoff_lowpass: float or sequence of two floats
Cutoff parameters for the low-pass filter
cutoff_highpass: float or sequence of two floats
Cutoff parameters for the high-pass filter
use_rfft: boolean, optional
Creates a filter to be used with the result of a rfft type of Fourier transform. Defaults to False.
data_type: `numpy.dtype`, optional
Specifies the data type of the computed filter. It defaults to `numpy.float64`
Raises
------
ValueError
In case of malformed cutoff_par
Returns
-------
numpy.array_like
The computed filter
"""
return get_lowpass_filter(
img_shape, cutoff_par=cutoff_lowpass, use_rfft=use_rfft, data_type=data_type
) * get_highpass_filter(img_shape, cutoff_par=cutoff_highpass, use_rfft=use_rfft, data_type=data_type)