pyoptics.processing

Module that defines image processing classes.

The following processors are defined:

  • Scaler: scale images to a given peak, mean or total value of the field strength or of the intensity

  • CameraNoiser: apply a camera noise model (Gaussian, Poisson photon noise or a full linear camera model following EMVA 1288)

  • Shifter: shift images

  • Centerer: center images on their intensity centroid

All processors are callables that accept a single image (2d array) or an image stack (3d array, the last index numbering the images). Images may be complex valued fields E or (real) intensities. The intensity of a field is taken as |E|**2 throughout this module, without the prefactor n/(2 Z_0) of utils.I().

References

EMVA Standard 1288, “Standard for Characterization of Image Sensors and Cameras”, Release 4.0, European Machine Vision Association (2021).

    1. Janesick, “Photon Transfer”, SPIE Press (2007).

Classes

CameraNoiser

Processor that applies a camera noise model to images.

Centerer

Processor that centers images on their intensity centroid.

ImageProcessor

Base class for all image processor.

Scaler

Processor that scales an image or an image stack.

Shifter

Processor that shifts images.

class pyoptics.processing.ImageProcessor[source]

Bases: object

Base class for all image processor.

All derived classes need to

  • have a constructor that correctly sets the processor up

  • implement process_single_image(self, image, *params)

abstractmethod process_single_image(image, *params)[source]

Define how a single image is processed.

The image may either be a complex valued field or an intensity.

Parameters:
imagearray
class pyoptics.processing.Scaler(value, measure='peak', quantity='intensity', image_type='auto', per_image=True, pixel_area=1.0)[source]

Bases: ImageProcessor

Processor that scales an image or an image stack.

The image is multiplied by a real factor such that a chosen measure of either the field strength |E| or the intensity I = |E|**2 equals a given value. Images may be fields or intensities: a field is multiplied by c, an intensity by c**2 if the field strength is to be scaled by c.

Parameters:
valuefloat

Target value of the measure.

measurestr, optional

“peak” (maximum), “mean” or “total”. For the intensity, “total” is the power sum(I)*pixel_area; for the field strength it is the norm sqrt(sum(|E|**2)*pixel_area), so that scaling the field to a total of sqrt(P) is the same as scaling the intensity to a total of P.

quantitystr, optional

“intensity” or “field”: the quantity whose measure is set to value.

image_typestr, optional

What the input images are: “field”, “intensity” or “auto” (complex images are fields, real images are intensities). Use “field” for real valued amplitudes.

per_imagebool, optional

If True (default), every image of a stack is scaled individually. If False, one common factor is used for the stack so that relative intensities are preserved; the measure is then taken over the whole stack (global peak, global mean, total averaged over the images).

pixel_areafloat, optional

Pixel area dx*dy used for measure=”total”.

Examples

>>> to_photons = Scaler(1000.0)   # peak intensity: 1000 photons per pixel
>>> unit_power = Scaler(1.0, measure="total", pixel_area=dx*dy)
get_measure(data)[source]

Return the chosen measure of the chosen quantity of an image or (for a stack) of the whole stack as used with per_image=False.

get_factor(data)[source]

Return the factor the image (field or intensity) is multiplied by.

process_single_image(image)[source]

Define how a single image is processed.

The image may either be a complex valued field or an intensity.

Parameters:
imagearray
class pyoptics.processing.CameraNoiser(model='camera', sigma=0.0, relative=False, quantum_efficiency=1.0, dark_current=0.0, exposure_time=1.0, read_noise=0.0, full_well=None, gain=1.0, offset=0.0, bit_depth=None, prnu=0.0, dsnu=0.0, rng=None)[source]

Bases: ImageProcessor

Processor that applies a camera noise model to images.

Three models are available:

  • “gaussian”: additive white Gaussian noise of standard deviation sigma (absolute, or relative to the image’s peak if relative=True). The image may be an intensity or a field; for a complex field, independent noise is added to the real and imaginary parts.

  • “poisson”: photon shot noise only. The image is the expected number of photons per pixel; the result is a Poisson distributed photon count.

  • “camera”: linear camera model following the EMVA 1288 standard. The image is the expected number of photons per pixel and exposure. The chain is

    photons --(Poisson, quantum_efficiency)--> photo electrons
    + dark electrons (Poisson, dark_current*exposure_time)
    -> clipped at full_well
    * (1 + PRNU pattern)
    + read noise (Gaussian, read_noise) + DSNU pattern
    * gain + offset
    -> rounded and clipped to [0, 2**bit_depth - 1] (if bit_depth)
    

    The result is in digital numbers (DN). The fixed pattern noise (PRNU, DSNU) is drawn once per image shape and then stays the same for all images processed by this noiser, like on a real sensor.

For the “poisson” and “camera” models, fields are converted to intensities |E|**2 first. Use a Scaler to bring images to photon numbers, e.g. Scaler(1000.0) for a peak of 1000 photons per pixel.

Parameters:
modelstr, optional

“gaussian”, “poisson” or “camera”.

sigmafloat, optional

Standard deviation of the “gaussian” model.

relativebool, optional

If True, sigma is relative to the peak of each image (“gaussian” model only).

quantum_efficiencyfloat, optional

Fraction of photons converted to electrons.

dark_currentfloat, optional

Dark current in electrons per pixel and unit time.

exposure_timefloat, optional

Exposure time (in the time unit of dark_current).

read_noisefloat, optional

Read noise (temporal dark noise) in electrons rms.

full_wellfloat, optional

Full well capacity in electrons; None means no saturation.

gainfloat, optional

System gain in DN per electron (K in EMVA 1288).

offsetfloat, optional

Dark offset (bias) in DN.

bit_depthint, optional

ADC resolution in bits; None means no quantization or clipping.

prnufloat, optional

Photo response non-uniformity: relative rms gain variation from pixel to pixel.

dsnufloat, optional

Dark signal non-uniformity: rms offset variation from pixel to pixel in electrons.

rngint, numpy.random.Generator or None, optional

Seed or random number generator for reproducible noise.

fixed_pattern(shape)[source]

Return the fixed pattern noise (relative gain deviation, offset deviation in electrons) for images of the given shape.

mean_signal(photons)[source]

Expected output of the “camera” model in DN for the given expected photon numbers, ignoring fixed pattern noise, saturation and quantization.

temporal_noise(photons)[source]

Expected temporal noise (standard deviation) of the “camera” model in DN for the given expected photon numbers (EMVA 1288 eq. for the linear model, without quantization noise).

process_single_image(image)[source]

Define how a single image is processed.

The image may either be a complex valued field or an intensity.

Parameters:
imagearray
class pyoptics.processing.Shifter(delta_x, delta_y, x, y)[source]

Bases: ImageProcessor

Processor that shifts images.

The shift uses the Fourier shift theorem: it is periodic (content leaving the grid on one side enters it on the other side) and works for subpixel shifts. For real images the real part of the result is returned.

shift(img, delta_x, delta_y)[source]

Shift an image with the Fourier shift theorem (periodic shift).

Parameters:
img2d array

Image on the grid of the processor.

delta_x, delta_ynumbers

Shifts in the units of x and y.

Returns:
shifted2d array

Real for a real input image.

process_single_image(img)[source]

Define how a single image is processed.

The image may either be a complex valued field or an intensity.

Parameters:
imagearray
class pyoptics.processing.Centerer(x, y, x0=0.0, y0=0.0, threshold=0.0, per_image=True, iterations=1)[source]

Bases: Shifter

Processor that centers images on their intensity centroid.

Every image is shifted (with the periodic Fourier shift of Shifter) such that its intensity centroid (center of mass, see utils.center_of_mass()) lies at (x0, y0). Fields are centered on the centroid of |E|**2.

Parameters:
x, yarrays

1d coordinate grids of the images (image shape (len(y), len(x))).

x0, y0float, optional

Target position of the centroid; default is the origin.

thresholdfloat, optional

Pixels with an intensity below threshold times the image’s peak are ignored when computing the centroid. A threshold suppresses the influence of background and noise far away from the spot.

per_imagebool, optional

If True (default), every image of a stack is centered individually, e.g. to remove beam jitter. If False, the whole stack is shifted by one common shift that centers the centroid of the summed intensity, which preserves the relative positions of the images (e.g. a drifting focus).

iterationsint, optional

Number of centroid/shift passes. Since the shift is periodic, the first pass may be inexact for spots near the edge or with strong background; further passes refine the result.

centroid(image)[source]

Return the intensity centroid (x_c, y_c) of an image.

get_shift(image)[source]

Return the shift (delta_x, delta_y) that centers an image.

get_shifts(data)[source]

Return the shifts (one row (delta_x, delta_y) per image) applied to the images of a stack in the first pass.

process_single_image(img)[source]

Define how a single image is processed.

The image may either be a complex valued field or an intensity.

Parameters:
imagearray