3.1.1. fringes package

3.1.1.1. Submodules

3.1.1.2. fringes.filter module

fringes.filter.curvature(s: ndarray, center: bool = False, normalize: bool = False) ndarray[source]

Mean curvature map.

Computed by differentiating a slope map.

Parameters:
  • s (np.ndarray) – Slope map. It is reshaped to video-shape (frames T, height Y, width X, color channels C) before processing.

  • center (bool, optional) – If this flag is set to True, the curvature values get centered around zero using the median. Default is False.

  • normalize (bool) – Flag indicating whether to use the acr-tangent function to non-linearly map the codomain from [-inf, inf] to [-1, 1]. Default is False.

Returns:

c – Curvature map.

Return type:

np.ndarray

fringes.filter.direct(b: ndarray) ndarray[source]

Direct illumination component.

Parameters:

b (np.ndarray) – Modulation

Returns:

d – Direct illumination component.

Return type:

np.ndarray

References

fringes.filter.exposure(a: ndarray, Irec: ndarray, lessbits: bool = True) ndarray[source]

Exposure.

Parameters:
  • a (np.ndarray) – Brightness.

  • Irec (np.ndarray) – Fringe pattern sequence.

  • lessbits (bool, optional) – The camera recorded Irec may contain fewer bits of information than its data type can hold, e.g. 12 bits for dtype uint16. If this flag is activated, it looks for the maximal value in I and sets Imax to the same or next power of two which is divisible by two. Example: If I.max() is 3500, Imax is set to 4095 (the maximal value a 12bit camera can deliver).

Returns:

E – Exposure.

Return type:

np.ndarray

fringes.filter.indirect(a: ndarray, b: ndarray) ndarray[source]

Indirect (global) illumination component.

Parameters:
  • a (np.ndarray) – Brightness.

  • b (np.ndarray) – Modulation

Returns:

g – Indirect (global) illumination component.

Return type:

np.ndarray

References

fringes.filter.visibility(a: ndarray, b: ndarray) ndarray[source]

Visibility.

Parameters:
  • a (np.ndarray) – Brightness.

  • b (np.ndarray) – Modulation

Returns:

V – Visibility.

Return type:

np.ndarray

3.1.1.3. fringes.fringes module

fringes.fringes.Decoded

alias of decoded

fringes.fringes.Decoded_verbose

alias of decoded_verbose

class fringes.fringes.Fringes(*args, X: int = 1920, Y: int = 1200, D: int = 2, K: int = 2, N: int | Sequence[int] = ((4, 4), (4, 4)), v: int | float | Sequence[int | float] | str = ((13.0, 7.0), (13.0, 7.0)), f: int | float | Sequence[int | float] = ((1.0, 1.0), (1.0, 1.0)), h: Sequence[int] | str = ((255, 255, 255),), p0: float = 3.141592653589793, g: float = 1.0, E: float = 0.5, V: float = 1.0, a: float = 1.0, bits: int = 8, dtype: str | dtype = 'uint8', grid: str = 'image', axis: int = 0, SDM: bool = False, WDM: bool = False, FDM: bool = False, static: bool = False, lmin: float = 8.0, indexing: str = 'xy', reverse: bool = False, mode: str = 'fast')[source]

Bases: object

Configure, encode and decode fringe patterns using phase shifting algorithms.

Note

All parameters are implemented as properties (managed attributes) and are parsed when set. Note that some attributes have sub-dependencies, hence dependent attributes might change as well. Circular dependencies are resolved automatically.

Parameters:
  • *args (iterable) – Non-keyword arguments are explicitly discarded. Only keyword arguments are considered.

  • X (int, default = 1920) – Width of fringe patterns.

  • Y (int, default = 1200) – Height of fringe patterns.

  • D (int, default = 2) – Number of directions.

  • K (int, default = 2) – Number of sets (number of fringe patterns with different spatial frequencies).

  • N (array_like, default = ((4, 4), (4, 4))) – Number of (equally distributed) phase shifts.

  • v (array_like, default = ((13.0, 7.0), (13.0, 7.0))) – Spatial frequencies (number of fringe periods across extended coding length Lext).

  • f (array_like, default = ((1.0, 1.0), (1.0, 1.0))) – Temporal frequency (number of periods to shift over).

  • h (array_like, default = ((255, 255, 255),)) – Hues i.e. colors of fringe patterns.

  • p0 (float, default = 3.141592653589793) – Phase offset ∈ (-2pi, +2pi).

  • g (float, default = 1.0) – Gamma correction factor used to compensate nonlinearities of the display response curve.

  • E (float, default = 0.5) – Relative exposure, i.e. relative mean intensity ∈ [0, 1].

  • V (float, default = 1.0) – Fringe visibility (fringe contrast) ∈ [0, 1].

  • a (float, default = 1.0) – Factor for extending the coding length.

  • bits (int, default = 8) – Number of bits.

  • dtype (str, default = uint8) – Data type which can hold 2**`bits` of information.

  • grid (str, default = image) – Coordinate system of the fringe patterns.

  • axis (int, default = 0) – Axis along which to shift if number of directions equals one.

  • SDM (bool, default = False) – Spatial division multiplexing.

  • WDM (bool, default = False) – Wavelength division multiplexing.

  • FDM (bool, default = False) – Frequency division multiplexing.

  • static (bool, default = False) – Flag for creating static fringes (so they remain congruent when shifted).

  • lmin (float, default = 8.0) – Minimum resolvable wavelength.

  • indexing (str, default = xy) – Indexing convention.

  • reverse (bool, default = False) – Flag for shifting fringes in reverse direction.

  • mode (str, default = fast) – Mode for decoding.

encode()[source]

Encode fringe patterns. See encode.

decode()[source]

Decode fringe patterns. See decode.

property A: float

Offset.

property B: float

Amplitude.

property C: int

Number of color channels.

property D: int

Number of directions.

property E: float

Relative exposure, i.e. relative mean intensity ∈ [0, 1].

property FDM: bool

Frequency division multiplexing.

The directions ‘D’ and the sets K are multiplexed, resulting in a crossed fringe pattern if ‘D’ ≡ 2. It can only be activated if ‘D’ ∨ ‘K’ > 1 i.e. ‘D’ * ‘K’ > 1. The amplitude ‘b’ is reduced by the factor ‘D’ * ‘K’. Usually ‘f’ equals 1 and is essentially only changed if frequency division multiplexing (‘FDM’) is activated: Each set per direction receives an individual temporal frequency ‘f’, which is used in temporal demodulation to distinguish the individual sets. A minimal number of shifts Nmin ≥ ⌈ 2 * fmax + 1 ⌉ is required to satisfy the sampling theorem and N is updated automatically if necessary. If one wants a static pattern, i.e. one that remains congruent when shifted, set ‘static’ to True.

property H: int

Number of hues.

property Imax: int

Maximum gray value.

property K: int

Number of sets (number of fringe patterns with different spatial frequencies).

property L: ndarray

Coding lengths, i.e. lengths of fringe patterns for each direction. [L] = px.

property Lext: float

Extended coding length. [Lext] = px.

property Lmax: int

Maximum coding length. [Lmax] = px

property M: int

Number of averaged intensity samples.

property N: ndarray

Number of (equally distributed) phase shifts.

property SDM: bool

Spatial division multiplexing.

The directions ‘D’ are multiplexed, resulting in a crossed fringe pattern. The amplitude ‘B’ is halved. It can only be activated if we have two directions, i.e. ‘D’ ≡ 2. The number of frames ‘T’ is reduced by the factor 2.

property T: int

Number of frames.

property UMR: ndarray

Unambiguous measurement range. [UMR] = px

The coding is only unique within the interval [0, UMR); after that it repeats itself.

The UMR is derived from ‘l’ and ‘v’:

  • If ‘l’ ∈ ℕ, UMR = lcm(‘l’), with lcm() being the least common multiple.

  • Else, if ‘v’ ∈ ℕ, UMR = ‘Lext’ / gcd(‘v’), with gcd() being the greatest common divisor.

  • Else, if ‘l’ ∨ ‘v’ ∈ ℚ, lcm() resp. gcd() are extended to rational numbers.

  • Else, if ‘l’ ∧ ‘v’ ∈ ℝ ∖ ℚ, UMR = prod(‘l’), with prod() being the product operator.

property V: float

Fringe visibility (fringe contrast) ∈ [0, 1].

Screens are extremely nonlinear near the minimum and maximum values, we can avoid them by setting V to e.g. 0.95.

property WDM: bool

Wavelength division multiplexing.

The shifts are multiplexed into the color channel, resulting in an RGB fringe pattern. It can only be activated if all shifts equal 3, i.e. ‘N’ ≡ 3. The number of frames ‘T’ is reduced by the factor 3.

property X: int

Width of fringe patterns. [X] = px.

property Y: int

Height of fringe patterns. [Y] = px.

property a: float

Factor for extending the coding length.

property axis: int

Axis along which to shift if number of directions equals one.

property bits: int

Number of bits.

property crt: ndarray

Coefficients for Chinese remainder theorem.

decode(I: ndarray, bmin: float = 0, Vmin: float = 0, unwrap: bool = True, verbose: bool | str = False, check_overexposure: bool = False, threads: int | None = None, uwr_func: str = 'ski') decoded | decoded_verbose[source]

Decode fringe patterns.

Parameters:
  • I (np.ndarray) –

    Fringe pattern sequence. It is reshaped to vshape (frames T, height Y, width X, color channels C) before processing.

    Note

    I must have been encoded with the same parameters set to the Fringes instance as the current one.

  • bmin (float, default=0) – Minimum modulation for measurement to be valid. Can accelerate decoding.

  • Vmin (float, default=0) – Minimum visibility for measurement to be valid. Can accelerate decoding.

  • unwrap (bool, default=True) – Flag for unwrapping.

  • verbose (bool or str, default=False) – Flag for returning intermediate and verbose results.

  • check_overexposure (bool, default=False) – Flag for checking if ‘I’ is overexposed. Logs a warning message if so.

  • threads (int, optional) – Number of threads to use. Default is all threads.

  • uwr_func ({'ski', 'cv2'}, optional) –

    Spatial unwrapping function to use.

Returns:

  • a (np.ndarray) – Brightness: average signal.

  • b (np.ndarray) – Modulation: amplitude of the cosine signal.

  • x (np.ndarray) – Registration: decoded screen coordinates.

  • p (np.ndarray, optional) – Local phase.

  • k (np.ndarray, optional) – Fringe order.

  • r (np.ndarray, optional) – Residuals from the optimization-based unwrapping process.

  • u (np.ndarray, optional) – Uncertainty of positional decoding in pixel units

Raises:
  • ValueError – If the number of frames of I and the attribute T of the Fringes instance don’t match.

  • ValueError – If WDM is active but I does not have 3 color channels.

References

Examples

>>> from fringes import Fringes
>>> f = Fringes()
>>> I = f.encode()
>>> Irec = I  # todo: replace this line with the recorded data as in 'record.py'
>>> a, b, x = f.decode(Irec)

Also return intermediate and verbose results:

>>> a, b, x, p, k, r, u = f.decode(Irec, verbose=True)
property dtype: dtype

Data type which can hold 2**`bits` of information.

encode(frames: int | Sequence[int] | None = None) ndarray[source]

Encode fringe patterns.

Parameters:

frames (Sequence of ints, optional) – Indices of the frames to be encoded. The default, frames=None, will encode all frames at once. If frames is negative, it counts from the last to the first frame. If frames contains numbers whose magnitude is larger than the total number of frames (as specified by the attribute T of the Fringes instance), it is wrapped around. If frames is a tuple of ints, only the frames specified in the tuple are encoded. If indices occur more than once, only the first occurence is encoded.

Returns:

I – Fringe pattern sequence.

Return type:

np.ndarray

Notes

To receive the frames iteratively (i.e. in a lazy manner), simply iterate over the Fringes instance.

Examples

>>> from fringes import Fringes
>>> f = Fringes()

Encode the complete fringe pattern sequence.

>>> I = f.encode()

Create a generator to receive the frames iteratively, i.e. in a lazy manner.

>>> I = (frame for frame in f)

Call the instance to encode the complete fringe pattern sequence.

>>> I = f()
property eta: float

Spatial coding efficiency.

property f: ndarray

Temporal frequency (number of periods to shift over).

property g: float

Gamma correction factor used to compensate nonlinearities of the display response curve.

property gcd: ndarray

Greatest common divisor of moduli.

Must be smaller than noise.

property grid: str

Coordinate system of the fringe patterns.

The following values can be set:

‘image’: The top left corner pixel of the grid is the origin and positive directions are right- resp. downwards.

‘Cartesian’: The center of grid is the origin and positive directions are right- resp. upwards.

‘polar’: The center of grid is the origin and positive directions are clockwise resp. outwards.

‘log-polar’: The center of grid is the origin and positive directions are clockwise resp. outwards.

property h: ndarray

Hues i.e. colors of fringe patterns.

Possible values are any sequence of RGB color triples ∈ [0, 255]. However, black (0, 0, 0) is not allowed.

The hue values can also be set by assigning any combination of the following characters as a string:

  • ‘r’: red

  • ‘g’: green

  • ‘b’: blue

  • ‘c’: cyan

  • ‘m’: magenta

  • ‘y’: yellow

  • ‘w’: white

Before decoding, repeating hues will be fused by averaging.

property indexing: str

Indexing convention.

Cartesian indexing xy (the default) will index the row first, while matrix indexing ij will index the colum first. This equivalent to the argument ‘indexing’ in numpy.meshgrid().

property l: ndarray

Wavelengths of fringe periods. [l] = px.

When Lext changes, v is kept constant and only l is changed.

property lmin: float

Minimum resolvable wavelength. [lmin] = px.

load(fname: str | None = None) None[source]

Load parameters from a config file to the Fringes instance.

Warning

The parameters are only loaded if the config file provides the section fringes.

Parameters:

fname (str, optional) – File name of the file to load. Supported file formats are: *.json, *.yaml. If fname is not provided, the file .fringes.yaml within the user home directory is loaded.

Examples

>>> import os
>>> fname = os.path.join(os.path.expanduser("~"), ".fringes.yaml")
>>> from fringes import Fringes
>>> f = Fringes()
>>> f.N = f.N + 1
>>> f.save(fname)
>>> f_ = Fringes()
>>> f_.load(fname)
>>> f_ == f
True
property mode: str

Mode for decoding.

The following values can be set:

  • ‘fast’

  • ‘precise’

mtf(v: Sequence[float] | None = None, PSF: float = 0.0) ndarray[source]

Modulation Transfer Function,

normalized to values ∈ [0, 1].

Parameters:
  • v (array_like) – Spatial frequencies at which to determine the normalized modulation.

  • PSF (float, default=0) – Standard deviation of the Point Spread Function for defocus.

Returns:

b – Relative modulation, at spatial frequencies ‘v’. ‘b’ is in the same shape as ‘v’.

Return type:

np.ndarray

Raises:

ValueError – If ‘v’ contains negative numbers.

Notes

  • If the private attribute _mtf of the Fringes instance is not None, the MTF is interpolated from previous measurements.

  • Else, if the attribute PSF of the Fringes instance is larger than zero, the MTF is computed from the optical transfer function of the optical system, i.e. as the magnitude of the Fourier-transformed ‘Point Spread Function’ (PSF).

  • Else, it returns ones.

property p0: float

Phase offset ∈ (-2pi, +2pi).

It can be used to e.g. let the fringe patterns start (at the origin) with a gray value of zero.

reset() None[source]

Reset parameters of the Fringes instance to default values.

property reverse: bool

Flag for shifting fringes in reverse direction.

save(fname: str | None = None) None[source]

Save the parameters of the Fringes instance to a config file.

Within the file, the parameters are written to the section fringes.

Parameters:

fname (str, optional) – File name of the file to save. Supported file formats are: *.json, *.yaml. If fname is not provided, the parameters are saved to the file .fringes.yaml within the user home directory.

Examples

>>> import os
>>> fname = os.path.join(os.path.expanduser("~"), ".fringes.yaml")
>>> from fringes import Fringes
>>> f = Fringes()
>>> f.save(fname)
set_mtf(b: ndarray)[source]

Set the modulation transfer function (MTF).

Parameters:

b (np.ndarray) – Measured modulation.

Raises:

ValueError – If ‘b’ contains negative values.

Notes

The normalized modulation transfer function is a cubic spline interpolator. It is set to the private attribute ‘_mtf’ and used when the method ‘mtf()’ is called.

property shape: tuple[int, int, int, int]

Shape of fringe pattern sequence in video shape (frames, height, with, color channels).

property static: bool

Flag for creating static fringes (so they remain congruent when shifted).

uncertainty(ui: float | ndarray = np.float64(0.28867513459481287), b: float | ndarray | None = None, a: float | ndarray | None = None, K: float | None = None, dark_noise: float | None = None) ndarray[source]

Uncertainty of positional decoding, in pixel units.

Using inverse variance weighting in unwrapping and assuming no fringe order errors.

Parameters:
  • ui (float | np.ndarray, default=np.sqrt(1 / 12)) – Standard deviation of intensity noise. The default assumes only quantization noise. If np.ndarray, it must have image shape (Y, X, C).

  • b (float | np.ndarray, optional) – Modulation. If np.ndarray, it must have video shape (T, Y, X, C).

  • a (float | np.ndarray, optional) – Offset (mean number of gray values). If np.ndarray, it must have video shape (T, Y, X, C).

  • K (float, optional) – System gain of used camera, in units DN/electron.

  • dark_noise (float, optional) – Dark noise of used camera, in units electrons.

Returns:

u – Uncertainty of positional decoding, in pixel units.

Return type:

np.ndarray

Note

If a, K and dark_noise are given, ui is ignored and calculated from them. In any case, if either ui, b or a is a numpy.ndarray, they must be broadcastable and hence their shape must end in the same (Y, X, C) values (the function takes care of those who are in front).

Examples

>>> from fringes import Fringes
>>> f = Fringes()

Assuming only quantization noise and using f.B as b (both by default):

>>> u = f.uncertainty()

Setting ui and b with floats:

>>> u = f.uncertainty(ui=2.28, b=100)

Using decoded values (numpy.ndarrays) and camera parameters:

>>> I = f.encode()
>>> Irec = I  # todo: replace this line with the recorded data as in 'record.py'
>>> a, b, x = f.decode(Irec)
>>> u = f.uncertainty(b=b, a=a, K=0.038, dark_noise=13.7)
property uwr: str

Phase unwrapping method.

property v: ndarray

Spatial frequencies (number of fringe periods across extended coding length Lext).

property vmax: float

Maximum resolvable spatial frequency.

property x: ndarray

Coordinate matrices of the coordinate system defined in grid.

Indexing order is defined in indexing. This is always a fleshed out representation.

property x0: float

Coordinate offset.

property xc: ndarray

Coordinate matrices as in x but with an additional axis for the color channel. This is useful when running tests.

3.1.1.4. fringes.grid module

fringes.grid.cart(Y: int = 720, X: int = 720, a: float = 0)[source]
fringes.grid.img(Y: int = 720, X: int = 720, a: float = 0)[source]
fringes.grid.inner_circ(Y: int = 720, X: int = 720)[source]

Boolean mask with True values inside inscribed circle.

fringes.grid.logpol(Y: int = 720, X: int = 720, a: float = 0)[source]
fringes.grid.pol(Y: int = 720, X: int = 720, a: float = 0)[source]
fringes.grid.rot(uu, vv, a)[source]

3.1.1.5. fringes.gui module

3.1.1.6. fringes.util module

fringes.util.circular_distance(a: float | ndarray, b: float | ndarray, c: float) ndarray[source]

Circular distance.

Parameters:
  • a (float or np.ndarray) – Start points.

  • b (float or np.ndarray) – End points.

  • c (float) – Circumference (distance) after which wrapping occurs.

Returns:

d – Circular distance from a to b.

Return type:

float or np.ndarray

Notes

For more details, see https://ieeexplore.ieee.org/document/9771407.

fringes.util.gamma_auto_correct(I: ndarray) ndarray[source]

Automatically estimate and apply the gamma correction factor to linearize the display/camera response curve.

Parameters:

I (np.ndarray) – Recorded data.

Returns:

Ilin – Linearized data.

Return type:

np.ndarray

fringes.util.unzip(I: ndarray, T: int) ndarray[source]

Unzip pattern sequences.

This applies for pattern sequences recorded with a line scan camera, where each frame has been displayed and captured as the object moved one pixel.

Parameters:
  • I (np.ndarray) – Pattern sequence. It is reshaped to video-shape (frames T, height Y, width X, color channels C) before processing.

  • T (int) – Number of frames of the pattern sequence.

Returns:

I – Deinterlaced pattern sequence.

Return type:

np.ndarray

Raises:

ValueError – If the number of frames of I and the number of frames of the pattern sequence T don’t match.

Examples

>>> from fringes import Fringes
>>> from fringes.util import unzip
>>> f = Fringes()
>>> I = f.encode()
>>> Irec = I.swapaxes(0, 1).reshape(-1, f.T, f.X, f.C)  # zip; this is how a line camera would record
>>> Irec = unzip(Irec, f.T)
fringes.util.vshape(data: ndarray, channels: Sequence[int] = (1, 3, 4)) ndarray[source]

Standardizes the input data shape.

Transforms video data into the standardized shape (T, Y, X, C), where T is number of frames, Y is height, X is width, and C is number of color channels.

Inspired from scikit-video.

Parameters:
  • data (ndarray) – Input data of arbitrary shape.

  • channels (list | tuple) – Allowed number of color channels.

Returns:

videodata – Standardized version of data, in shape (T, Y, X, C), where T is number of frames, Y is height, X is width, and C is number of color channels.

Return type:

ndarray

Notes

Ensures that the array becomes 4-dimensional and that the length of the last dimension is in channels. To do this, leading dimensions may be flattened.

Examples

>>> from fringes import vshape
>>> data = np.ones(shape=(100))
>>> videodata = vshape(data)
>>> videodata.shape
(100, 1, 1, 1)
>>> data = np.ones(shape=(1200, 1920))
>>> videodata = vshape(data)
>>> videodata.shape
(1, 1200, 1920, 1)
>>> data = np.ones(shape=(1200, 1920, 3))
>>> videodata = vshape(data)
>>> videodata.shape
(1, 1200, 1920, 3)
>>> data = np.ones(shape=(100, 1200, 1920))
>>> videodata = vshape(data)
>>> videodata.shape
(100, 1200, 1920, 1)
>>> data = np.ones(shape=(100, 1200, 1920, 3))
>>> videodata = vshape(data)
>>> videodata.shape
(100, 1200, 1920, 3)
>>> data = np.ones(shape=(2, 3, 4, 1200, 1920))
>>> videodata = vshape(data)
>>> videodata.shape
(24, 1200, 1920, 1)

3.1.1.7. Module contents