pyIDI source code

Contents

pyIDI source code#

Video Reader#

Module for reading video files from high-speed video recordings.

@author: Ivan Tomac (itomac@fesb.hr), Klemen Zaletelj (klemen.zaletelj@fs.uni-lj.si), Janko Slavič (janko.slavic@fs.uni-lj.si)

class pyidi.video_reader.VideoReader(input_file, root=None, fps=None)[source]#

Bases: object

Manages reading of high-speed video recordings. The video recording can be any of the supported file formats which includes image streams, video files or memory map for “mraw” file format.

This applies to frames from image and video file formats: Reader returns the frame as a monochrome image. For colour images automatic conversion to grayscale (luma channel) is performed. Other channels can be selected (“R”, “G”, “B”) or custom weights can be applied. The reader returns image in 2D “numpy.array” (“height, width”) of type “numpy.uint8” or “numpy.uint16” depending on the bit depth of the originalimage file.

__init__(input_file, root=None, fps=None)[source]#

The video recording is initialized by providing the path to the image/video file, “cih(x)” file from Photron, or “numpy.ndarray”. For image stream it is enough to provide the path to the any image file in the sequence. Images in stream must be in the same directory and named in the way that can be sorted in the correct order, e.g. for stream of 10000 images file names should be: “im_0000.ext, …, im_9999.ext”. Image formats that support multiple images, such as “gif”, “tif” are supported too. Upgrade is needed to enable higher bit depth then 8 bit for video file formats.

Parameters:
  • input_file (str) – path to the image/video or “cih(x)” file

  • root (str) – root directory of the image/video file. Only used when the input file is a “np.ndarray”. Defaults to None.

  • fps (int or None) – frames per second. If None and Photron file is passed, the fps is read from the cih/cihx file. Defaults to None.

configure(**kwargs)[source]#

Configure reader parameters after initialization.

Supported keyword arguments:

  • fps (int): Frames per second.

  • root (str): Root directory for output or image sequence files. Used with “np.ndarray”.The directory is created if it does not exist.

  • video_format (str): PyAV pixel format string used when reading frames. (default: “gray”, “gray16be”, “gray16le”). For custom selection of image channels, or using custom weights for conversion to monochrome, video format must be set to the RGB format, depending on the bit depth of the original image file, e.g. “rgb24”, “rgb48le”, “rgb48be”.

  • channel (str): Colour channel to extract from RGB images. Must be one of “R”, “G”, “B”.

  • channel_weights (list or tuple): Three weights applied to the RGB channels to produce a monochrome image, e.g. luma coefficients [0.299, 0.587, 0.114].

Parameters:

kwargs (dict) – Keyword arguments as described above.

Raises:

ValueError – If channel is not a string or channel_weights is not a list/tuple of length 3.

get_frame(frame_number, *args, **kwargs)[source]#

Returns the “frame_number”-th frame from the video. Frames from image and video files are checked for the bit depth and converted to 8 or 16 bit depth if needed. The frames from “numpy.ndarray” and “mraw” files are returned as they are.

Parameters:
  • frame_number (int) – frame number

  • args – additional arguments to be passed to the image readers to handle

multiple channels in image :param kwargs: additional keyword arguments forwarded to image/video reader methods :type kwargs: dict :return: image (monochrome)

get_frames(frame_range=None, *args, **kwargs)[source]#

Returns all the available frames.

If “mraw” or “np.ndarray”, it returns the frames as they are. If images or mp4, avi, etc., the get_frame method is called in a loop. In this case, the args are passed to the get_frame method (see the get_frame method for details).

Parameters:
  • frame_range (tuple, list, int, None, optional) – The range of the frames to return. If None, all frames are returned. If int, the frames from zero to frame_range are returned. If tuple, the frames from first to second index are returned.

  • args – positional arguments forwarded to get_frame

  • kwargs (dict) – keyword arguments forwarded to get_frame

_get_frame_from_image(frame_number)[source]#

Reads the frame from the image stream, or image file containing multiple images. 8bit and 16 bit images are supported. The bit depth is determined from the image properties. Color images are automatically converted to monochrome using a weighted sum with weights [0.299, 0.587, 0.114] by setting format to “gray” in iio.imread. If the channel is configured as “R”, “G” or “B”, using a configuration method, the corresponding channel is returned or if the custom channel weights are set using a configuration method, the weighted sum of the “RGB” channels is returned.

Parameters:

frame_number (int) – frame number

Returns:

image (monochrome)

_get_frame_from_video_file(frame_number)[source]#

Reads the frame from the video file which is supported by the “imagio.v3” “pyav” plug-in. Returns the frame as a monochrome image (sum with weights [0.299, 0.587, 0.114]). Custom channel selection and custom weights for conversion to monochrome are supported by setting channel or channel_weights using configuration method.

Parameters:

frame_number (int) – frame number

Returns:

monochrome image in 8 bit depth (note: needs upgrade to support higher bit depth)

_initialise_phortron_camera_files(input_file)[source]#

Initialise reader state for Photron cih/cihx sources.

Loads frame data and metadata using pyMRAW and populates core attributes such as frame count, image size, fps and source metadata.

Parameters:

input_file (str) – Path to a Photron header file (.cih or .cihx)

_initialise_slow_files(input_file)[source]#

Initialise reader state for .slow recordings.

Parameters:

input_file (str) – Path to a .slow file

_initalise_image_files(input_file)[source]#

Initialise reader state for image files and image sequences.

Stores metadata from imageio in self.image_meta. The self.image_meta["video_format"] value is later used when reading frames via the pyav plugin to preserve the detected pixel format.

Parameters:

input_file (str) – Path to an image file from the sequence or a multi-image file

_initialise_video_files(input_file)[source]#

Initialise reader state for video containers handled by pyav.

Parameters:

input_file (str) – Path to a supported video file

_initialise_numpy_array(input_file)[source]#

Initialise reader state when source frames are provided as ndarray.

Parameters:

input_file (numpy.ndarray) – Frame stack with shape (N, H, W)

close()[source]#

Close the video and clear the resources. In case of a MRAW video, closes the memory map for “mraw” file format.

gui()[source]#

Starts the GUI for pyIDI.

pyidi.video_reader._rgb2mono(rgb_image, weights)[source]#

Converts “RGB” image to sum weighted monochrome.

Parameters:
  • rgb_image (numpy.array) – “RGB” image “(w, h, channels)”

  • weights (tuple or list of length 3) – conversion weights

Returns:

weighted sum of the “RGB” channels

IDIMetod base class#

class pyidi.methods.idi_method.IDIMethod(video: VideoReader, *args, **kwargs)[source]#

Bases: object

Common functions for all methods.

__init__(video: VideoReader, *args, **kwargs)[source]#

The image displacement identification method constructor.

For more configuration options, see method.configure()

configure()[source]#

Configure the displacement identification method here.

IMPORTANT:#

All of the settings should be passed through this method. Inside the method, each setting should be saved as an attribute of the class, keeping the same name as the argument. This is important as the settings are then saved to the results file and can be used to reproduce the results.

See the LucasKanade example for example usage.

configure_multiprocessing(process_number, progress, task_id)[source]#

Configure the multiprocessing settings here.

Parameters:
  • process_number (int) – The number of the process.

  • progress (multiprocessing.Value) – The progress object.

  • task_id (multiprocessing.Value) – The task ID.

calculate_displacements()[source]#

Calculate the displacements of set points here. The result should be saved into the self.displacements attribute.

create_temp_files(init_multi=False)[source]#

Temporary files to track the solving process.

This is done in case some error occurs. In this eventuality the calculation can be resumed from the last computed time point.

Parameters:

init_multi (bool, optional) – when initialization multiprocessing, defaults to False

clear_temp_files()[source]#

Clearing the temporary files.

update_log(last_time)[source]#

Updating the log file.

A new last time is written in the log file in order to track the solution process.

Parameters:

last_time (int) – Last computed time point (index)

resume_temp_files()[source]#

Reload the settings written in the temporary files.

When resuming the computation of displacement, the settings are loaded from the previously created temporary files.

temp_files_check()[source]#

Checking the settings of computation.

The computation can only be resumed if all the settings and data are the same as with the original analysis. This function checks that (writing all the setting to dict and comparing the json dump of the dicts).

If the settings are the same but the points are not, a new analysis is also started. To set the same points, check the temp_pyidi folder.

Returns:

Whether to resume analysis or not

Return type:

bool

create_settings_dict()[source]#

Make a dictionary of the chosen settings.

_make_comparison_dict()[source]#

Make a dictionary for comparing the original settings with the current settings.

Used for finding out if the analysis should be resumed or not.

Returns:

Settings

Return type:

dict

show_points(figsize=(15, 5), cmap='gray', color='r')[source]#

Shoe points to be analyzed, together with ROI borders.

Parameters:
  • figsize – matplotlib figure size, defaults to (15, 5)

  • cmap – matplotlib colormap, defaults to ‘gray’

  • color – marker and border color, defaults to ‘r’

get_displacements(autosave=True, **kwargs)[source]#

Calculate the displacements based on chosen method.

Parameters:
  • autosave (bool) – Save the results automatically. Default is True.

  • kwargs (dict) – Additional keyword arguments that are ultimately passed to the configure method.

extract_configuration_arguments()[source]#

Extract the configuration arguments from the configure method.

Simplified optical flow#

class pyidi.methods._simplified_optical_flow.SimplifiedOpticalFlow(video: VideoReader, *args, **kwargs)[source]#

Bases: IDIMethod

Displacmenet computation based on Simplified Optical Flow method [1].

Literature:
[1] Javh, J., Slavič, J., & Boltežar, M. (2017). The subpixel resolution

of optical-flow-based modal analysis. Mechanical Systems and Signal Processing, 88, 89–99.

[2] Lucas, B. D., & Kanade, T. (1981). An Iterative Image Registration

Technique with an Application to Stereo Vision. In Proceedings of the 7th International Joint Conference on Artificial Intelligence - Volume 2 (pp. 674–679). San Francisco, CA, USA: Morgan Kaufmann Publishers Inc.

configure(subset_size=3, pixel_shift=False, convert_from_px=1.0, frame_range='all', mean_n_neighbours=0, zero_shift=False, progress_bar=True, reference_range=(0, 100))[source]#

Set the attributes, compute reference image and gradients.

Parameters:
  • video (object) – ‘parent’ object

  • subset_size – size of the averaging subset, defaults to 3

  • subset_size – int, optional

  • pixel_shift – use pixel shift or not?, defaults to False

  • pixel_shift – bool, optional

  • convert_from_px – distance unit per pixel, defaults to 1.

  • convert_from_px – float or int, optional

  • frame_range – what range of images to calculate into displacements, defaults to ‘all’

  • frame_range – str or tuple, optional

  • mean_n_neighbours – average the displacements of neighbouring points (how many points), defaults to 0

  • mean_n_neighbours – int, optional

  • zero_shift – shift the mean of the signal to zero?, defaults to False

  • zero_shift – bool, optional

  • progress_bar – show progress bar while calculating the displacements, defaults to True

  • progress_bar – bool, optional

  • reference_range – what range of images is averaged into reference image, defaults to (0, 100)

  • reference_range – tuple, optional

calculate_displacements()[source]#

Calculate the displacements of set points here. The result should be saved into the self.displacements attribute.

displacement_averaging()[source]#

Calculate the average of displacements.

pixel_shift_fun(i, points, image_shape)[source]#

Pixel shifting implementation. Points that are going outside of the image range are excluded.

_reference()[source]#

Calculation of the reference image, image gradients and gradient amplitudes.

Parameters:
  • images – Images to average. Usually the first 100 images.

  • subset_size – Size of the subset to average.

Returns:

Reference image, image gradient in 0 direction, image gradient in 1 direction, gradient magnitude

subset(data, subset_size)[source]#

Calculating a filtered image.

Calculates a filtered image with subset of d. It sums the area of d x d.

Parameters:
  • data – Image that is to be filtered.

  • subset_size – Size of the subset.

Returns:

Filtered image.

class pyidi.methods._simplified_optical_flow.PickPoints(video, subset, axis, min_grad)[source]#

Bases: object

Pick the area of interest.

Select the points with highest gradient in vertical direction.

__init__(video, subset, axis, min_grad)[source]#
inside_polygon(x, y, points)[source]#

Return True if a coordinate (x, y) is inside a polygon defined by a list of verticies [(x1, y1), (x2, x2), … , (xN, yN)].

Reference: http://www.ariel.com.au/a/python-point-int-poly.html

The Lucas-Kanade algorithm for translations#

class pyidi.methods._lucas_kanade.LucasKanade(video: VideoReader, *args, **kwargs)[source]#

Bases: IDIMethod

Translation identification based on the Lucas-Kanade method using least-squares iterative optimization with the Zero Normalized Cross Correlation optimization criterium.

configure(roi_size=(9, 9), pad=2, max_nfev=20, tol=1e-08, int_order=3, verbose=1, show_pbar=True, processes=1, resume_analysis=False, reference_image=0, frame_range='full')[source]#

Displacement identification based on Lucas-Kanade method, using iterative least squares optimization of translatory transformation parameters to determine image ROI translations.

Parameters:
  • roi_size (tuple, list, int, optional) – (h, w) height and width of the region of interest. ROI dimensions should be odd numbers. Defaults to (9, 9)

  • pad (int, optional) – size of padding around the region of interest in px, defaults to 2

  • max_nfev (int, optional) – maximum number of iterations in least-squares optimization, defaults to 20

  • tol (float, optional) – tolerance for termination of the iterative optimization loop. The minimum value of the optimization parameter vector norm.

  • int_order (int, optional) – interpolation spline order

  • verbose (int, optional) – show text while running, defaults to 1

  • show_pbar (bool, optional) – show progress bar, defaults to True

  • processes (int, optional, defaults to 1.) – number of processes to run

  • resume_analysis – if True, the last analysis results are loaded and computation continues from last computed time point.

  • reference_image (int or tuple or ndarray) – The reference image for computation. Can be index of a frame, tuple (slice) or numpy.ndarray that is taken as a reference.

  • frame_range (tuple or "full") – Part of the video to process. If “full”, a full video is processed. If first element of tuple is not 0, a appropriate reference image should be chosen.

_set_frame_range()[source]#

Set the range of the video to be processed.

calculate_displacements()[source]#

Calculate displacements for set points and roi size.

kwargs are passed to configure method. Pre-set arguments (using configure) are NOT changed!

optimize_translations(G, F_spline, maxiter, tol, d_subpixel_init=(0, 0), point_index=None, frame=None)[source]#

Determine the optimal translation parameters to align the current image subset G with the interpolated reference image subset F.

Parameters:
  • G (array of shape roi_size) – the current image subset.

  • F_spline (scipy.interpolate.RectBivariateSpline) – interpolated referencee image subset

  • maxiter (int) – maximum number of iterations

  • tol (float) – convergence criterium

  • d_subpixel_init – initial subpixel displacement guess, relative to the integrer position of the image subset G

  • point_index (int, optional) – index of the point being processed (for error messages)

  • frame (int, optional) – frame number being processed (for error messages)

Returns:

the obtimal subpixel translation parameters of the current image, relative to the position of input subset G.

Return type:

array of size 2

_padded_slice(point, roi_size, image_shape, pad=None)[source]#

Returns a slice that crops an image around a given point center, roi_size and pad size. If the resulting slice would be out of bounds of the image to be sliced (given by image_shape), the slice is snifted to be on the image edge and a warning is issued.

Parameters:
  • point (array_like of size 2, (y, x)) – The center point coordiante of the desired ROI.

  • roi_size – Size of desired cropped image (y, x). type roi_size: array_like of size 2, (h, w)

  • image_shape – Shape of the image to be sliced, (h, w). type image_shape: array_like of size 2, (h, w)

  • pad (int, optional, defaults to None) – Pad border size in pixels. If None, the video.pad attribute is read.

Return crop_slice:

tuple (yslice, xslice) to use for image slicing.

_set_reference_image(video: VideoReader, reference_image)[source]#

Set the reference image.

_interpolate_reference(video: VideoReader)[source]#

Interpolate the reference image.

Each ROI is interpolated in advanced to save computation costs. Meshgrid for every ROI (without padding) is also determined here and is later called in every time iteration for every point.

Parameters:

video (object) – parent object

show_points(figsize=(15, 5), cmap='gray', color='r')[source]#

Shoe points to be analyzed, together with ROI borders.

Parameters:
  • figsize – matplotlib figure size, defaults to (15, 5)

  • cmap – matplotlib colormap, defaults to ‘gray’

  • color – marker and border color, defaults to ‘r’

pyidi.methods._lucas_kanade.multi(video: VideoReader, idi_method: LucasKanade, processes, configuration_keys: list)[source]#

Splitting the points to multiple processes and creating a pool of workers.

Parameters:
  • video (VideoReader) – VideoReader object

  • idi_method (IDIMethod) – IDIMethod object

  • processes (int) – number of processes to run

  • configuration_keys (list) – list of configuration keys

pyidi.methods._lucas_kanade.worker(points, idi_kwargs, method_kwargs, i, progress, task_id)[source]#

A function that is called when for each job in multiprocessing.

pyidi.methods._lucas_kanade.compute_inverse_numba(Gx, Gy, tol=1e-10)[source]#

Compute the inverse of the gradient matrix for Lucas-Kanade optimization.

Parameters:
  • Gx – x-gradient of the image subset

  • Gy – y-gradient of the image subset

  • tol – tolerance for detecting singular matrix

Returns:

inverse matrix, or None if the matrix is near-singular

Directional Lucas-Kanade#

class pyidi.methods._directional_lucas_kanade.DirectionalLucasKanade(video: VideoReader, *args, **kwargs)[source]#

Bases: IDIMethod

Unidirectional translation identification as introduced in: Masmeijer T., Habtour E., Zaletelj, K., & Slavič, J., (2024). Directional DIC method with automatic feature selection. MSSP. “https://doi.org/10.1016/j.ymssp.2024.112080”. The implementation is based on the Lucas-Kanade method using least-squares iterative optimization with the Zero Normalized Cross Correlation optimization criterium.

configure(roi_size=(9, 9), dij=(1, 0), pad=(2, 2), max_nfev=20, tol=1e-08, int_order=3, verbose=1, show_pbar=True, processes=1, resume_analysis=False, reference_image=0, frame_range='full', use_numba=False)[source]#

Displacement identification based on Directional Lucas-Kanade method, using iterative least squares optimization of translatory transformation parameters to determine image ROI translations.

Parameters:
  • video (object) – parent object

  • roi_size (tuple, list, int, optional) – (h, w) height and width of the region of interest. ROI dimensions should be odd numbers. Defaults to (9, 9)

  • dij (tuple, list, optional) – Assumed vibration direction. If |d| != 1, the vector is normalized. Convention is ‘negative down, positive right’.

  • pad (int, optional) – size of padding around the region of interest in px, defaults to 2

  • max_nfev (int, optional) – maximum number of iterations in least-squares optimization, defaults to 20

  • tol (float, optional) – tolerance for termination of the iterative optimization loop. The minimum value of the optimization parameter vector norm.

  • int_order (int, optional) – interpolation spline order

  • verbose (int, optional) – show text while running, defaults to 1

  • show_pbar (bool, optional) – show progress bar, defaults to True

  • processes (int, optional, defaults to 1.) – number of processes to run

  • resume_analysis (bool, optional) – if True, the last analysis results are loaded and computation continues from last computed time point.

  • reference_image (int or tuple or ndarray) – The reference image for computation. Can be index of a frame, tuple (slice) or numpy.ndarray that is taken as a reference.

  • frame_range (tuple or "full") – Part of the video to process. If “full”, a full video is processed. If first element of tuple is not 0, a appropriate reference image should be chosen.

  • use_numba (bool) – Use numba.njit for computation speedup. Currently not implemented.

_set_frame_range()[source]#

Set the range of the video to be processed.

calculate_displacements(**kwargs)[source]#

Calculate displacements for set points and roi size.

kwargs are passed to configure method. Pre-set arguments (using configure) are NOT changed!

optimize_translations(G, F_spline, maxiter, tol, dij, d_subpixel_init=(0, 0))[source]#

Determine the optimal translation parameters to align the current image subset G with the interpolated reference image subset F.

Parameters:
  • G (array of shape roi_size) – the current image subset. (G already is of type float64)

  • F_spline (scipy.interpolate.RectBivariateSpline) – interpolated referencee image subset

  • maxiter (int) – maximum number of iterations

  • tol (float) – convergence criterium

  • d_subpixel_init – initial subpixel displacement guess, relative to the integrer position of the image subset G

Returns:

the obtimal subpixel translation parameters of the current image, relative to the position of input subset G.

Return type:

array of size 2

_padded_slice(point, roi_size, image_shape, pad=None)[source]#

Returns a slice that crops an image around a given point center, roi_size and pad size. If the resulting slice would be out of bounds of the image to be sliced (given by image_shape), the slice is snifted to be on the image edge and a warning is issued. :param point: The center point coordiante of the desired ROI. :type point: array_like of size 2, (y, x) :param roi_size: Size of desired cropped image (y, x). :type roi_size: array_like of size 2, (h, w) :param image_shape: Shape of the image to be sliced, (h, w). :type image_shape: array_like of size 2, (h, w) :param pad: Pad border size in pixels. If None, the video.pad attribute is read. :type pad: int, optional, defaults to None :return crop_slice: tuple (yslice, xslice) to use for image slicing.

_set_reference_image(video, reference_image)[source]#

Set the reference image.

_interpolate_reference(video)[source]#

Interpolate the reference image.

Each ROI is interpolated in advanced to save computation costs. Meshgrid for every ROI (without padding) is also determined here and is later called in every time iteration for every point.

Parameters:

video (object) – parent object

show_points(figsize=(15, 5), cmap='gray', color='r')[source]#

Shoe points to be analyzed, together with ROI borders.

Parameters:
  • figsize – matplotlib figure size, defaults to (15, 5)

  • cmap – matplotlib colormap, defaults to ‘gray’

  • color – marker and border color, defaults to ‘r’

pyidi.methods._directional_lucas_kanade.multi(video: VideoReader, idi_method: DirectionalLucasKanade, processes, configuration_keys: list)[source]#

Splitting the points to multiple processes and creating a pool of workers.

Parameters:
  • video (VideoReader) – VideoReader object

  • idi_method (IDIMethod) – IDIMethod object

  • processes (int) – number of processes to run

  • configuration_keys (list) – list of configuration keys

pyidi.methods._directional_lucas_kanade.worker(points, idi_kwargs, method_kwargs, i, progress, task_id)[source]#

A function that is called when for each job in multiprocessing.

Digital Image Correlation (DIC)#

Full-field 2D Digital Image Correlation method for pyidi.

This module is a port of the pyDIC library by the LADISK research group (University of Ljubljana, Faculty of Mechanical Engineering) into pyidi’s multi-point IDIMethod framework. The original pyDIC implementation lives at:

Algorithmically, this module mirrors the original: Inverse Compositional Gauss-Newton (IC-GN) optimization with the Zero Normalized Sum of Squared Differences (ZNSSD) criterion, with both a 6-parameter affine and a 3-parameter rigid (translation + in-plane rotation) warp model. Per-point precomputables (gradient, steepest-descent images, Hessian) and the warp update equations follow pyDIC’s py_dic.dic and py_dic.dic_tools modules.

Differences with respect to the upstream pyDIC implementation:

  • The single-ROI, function-call API of pyDIC is wrapped into a multi-point IDIMethod subclass (DIC) so that many subsets can be tracked in a single analysis with the standard pyidi configuration / checkpointing / multiprocessing infrastructure.

  • The full converged warp parameters are exposed per point per frame as self.warp_params (see the DIC class docstring).

  • Subset coordinates are mean-centered so that, at the identity warp, the spline of the target frame is sampled exactly at each point’s center.

class pyidi.methods._dic.DIC(video: VideoReader, *args, **kwargs)[source]#

Bases: IDIMethod

Full-field 2D Digital Image Correlation method using Inverse Compositional Gauss-Newton optimization with the Zero Normalized Sum of Squared Differences (ZNSSD) criterion.

Origin#

This class is a port of the pyDIC library (ladisk/pyDIC, LADISK research group, University of Ljubljana) into the pyidi multi-point IDIMethod framework. The core math (gradient kernel, Jacobians, steepest-descent images, Hessian, inverse-compositional warp update, ZNSSD error image) follows pyDIC’s py_dic.dic and py_dic.dic_tools modules. Please cite the underlying algorithm and the pyDIC repository when using this method.

Outputs#

After get_displacements() two arrays are populated on the instance:

  • self.displacements: shape (n_points, n_frames, 2) with columns [dy, dx]. This is the standard pyidi output (subset-center translation only) and is the value returned by get_displacements.

  • self.warp_params: shape (n_points, n_frames, n_param) holding the full converged warp parameter vector per point per frame.

The contents of warp_params depend on the chosen warp model:

Affine (warp='affine', default, n_param=6): columns are [du/dx, du/dy, u, dv/dx, dv/dy, v] where u, v are the translations in x and y, and du/dx, du/dy, dv/dx, dv/dy are the in-plane displacement gradients (first-order shape function). Useful derived quantities:

eps_xx     = warp_params[..., 0]                      # du/dx
eps_yy     = warp_params[..., 4]                      # dv/dy
shear_xy   = 0.5 * (warp_params[..., 1] + warp_params[..., 3])
rotation   = 0.5 * (warp_params[..., 3] - warp_params[..., 1])  # rad

Green-Lagrange strains follow the standard formulae:

E_xx = du/dx + 0.5 * (du/dx**2 + dv/dx**2)
E_yy = dv/dy + 0.5 * (du/dy**2 + dv/dy**2)
E_xy = 0.5 * (du/dy + dv/dx + du/dx*du/dy + dv/dx*dv/dy)

Rigid (warp='rigid', n_param=3): columns are [u, v, phi] where phi is the in-plane rotation in radians.

Persistence#

When get_displacements(autosave=True) is used, warp_params is pickled to warp_params.pkl next to results.pkl in the analysis folder and is automatically reattached by pyidi.load_analysis.

configure(roi_size=(21, 21), pad=2, max_nfev=100, tol=1e-06, int_order=3, warp='affine', prefilter_gauss=True, verbose=1, show_pbar=True, processes=1, resume_analysis=False, reference_image=0, frame_range='full')[source]#

Configure the DIC method.

Parameters:
  • roi_size (tuple, list, int, optional) – (h, w) height and width of the region of interest. ROI dimensions should be odd numbers. Defaults to (21, 21).

  • pad (int, optional) – padding around the ROI in px (interpolation safety).

  • max_nfev (int, optional) – maximum number of IC-GN iterations per point per frame.

  • tol (float, optional) – convergence threshold on the L2 norm of the parameter increment dp.

  • int_order (int, optional) – interpolation spline order for the target image.

  • warp (str, optional) – warp model name. Either 'affine' (6 parameters) or 'rigid' (3 parameters). Defaults to 'affine'.

  • prefilter_gauss (bool, optional) – if True, use the Gauss-prefiltered finite difference kernel [-0.446, 0, 0.446] for the reference gradient. Otherwise use [-0.5, 0, 0.5].

  • verbose (int, optional) – show text while running.

  • show_pbar (bool, optional) – show progress bar.

  • processes (int, optional) – number of processes to run.

  • resume_analysis (bool, optional) – if True, the last analysis results are loaded and computation continues from the last computed time point.

  • reference_image (int or tuple or ndarray) – reference image. Index of a frame, tuple (slice) or numpy.ndarray.

  • frame_range (tuple or "full") – part of the video to process. If 'full', the full video is processed.

_set_frame_range()[source]#

Set the range of the video to be processed.

calculate_displacements()[source]#

Calculate displacements for the configured points and ROI size.

Convention notes#

  • pyidi points are stored as (y, x) (row, column).

  • The warp matrix W is a 3x3 homogeneous transform whose first row drives the x coordinate and second row the y coordinate. The subset grid coordinates (xx, yy) are centered on zero, so when W = I the spline is sampled exactly at each point’s center.

  • After convergence, W[0, 2] is the subpixel displacement in x and W[1, 2] is the subpixel displacement in y. These are stored as [dy, dx] in self.displacements, matching the LucasKanade output convention.

_announce_run_state()[source]#

Print resume / new-analysis banner and reset resume_analysis if needed.

_run_multiprocessing()[source]#

Run the analysis using multiple processes.

_init_storage()[source]#

Allocate (or resume) the displacement and warp-parameter buffers.

_run_time_loop(video, current_warps)[source]#

Iterate over frames, optimizing each point and storing results.

_process_frame(G_spline, current_warps, frame_index, ii)[source]#

Optimize all points for a single frame and store outputs.

static _print_elapsed(full_time)[source]#

Print the elapsed wall-clock time in min/s or s.

_optimize_warp(G_spline, point, W_init, point_index, frame)[source]#

Run IC-GN optimization for a single point at the current frame.

Parameters:
  • G_spline (scipy.interpolate.RectBivariateSpline) – spline of the target frame G evaluated in image coordinates.

  • point (array_like of size 2) – (y, x) image-space center of the subset.

  • W_init (numpy.ndarray) – initial 3x3 warp matrix (subset-local coordinates).

  • point_index (int) – index of the current point (for diagnostics).

  • frame (int) – current frame index (for diagnostics).

Returns:

converged 3x3 warp matrix.

Return type:

numpy.ndarray

_padded_slice(point, roi_size, image_shape, pad=None)[source]#

Return (yslice, xslice) cropping an image around point.

If the resulting slice would be out of bounds of the image (given by image_shape), the slice is shifted to the image edge and a warning is issued.

Parameters:
  • point (array_like of size 2) – center coordinate of the desired ROI, (y, x).

  • roi_size (array_like of size 2) – size of the cropped image, (h, w).

  • image_shape (array_like of size 2) – shape of the image to be sliced, (h, w).

  • pad (int, optional) – pad border size in pixels. If None, self.pad is used.

Returns:

(yslice, xslice) to use for image slicing.

Return type:

tuple of slice

_set_reference_image(video: VideoReader, reference_image)[source]#

Set the reference image.

_precompute_reference(video: VideoReader)[source]#

Precompute per-point reference quantities for the IC-GN loop.

For every point this stores the reference subset F, its mean and standard deviation, the steepest-descent images SD, and the inverse Hessian inv_H.

Parameters:

video (VideoReader) – parent video object.

show_points(figsize=(15, 5), cmap='gray', color='r')[source]#

Show points to be analyzed, together with ROI borders.

Parameters:
  • figsize – matplotlib figure size, defaults to (15, 5).

  • cmap – matplotlib colormap, defaults to 'gray'.

  • color – marker and border color, defaults to 'r'.

pyidi.methods._dic._jacobian_affine(h, w)[source]#

Affine warp Jacobian on centered subset coordinates.

Parameters:
  • h (int) – subset height.

  • w (int) – subset width.

Returns:

array of shape (2, 6, h, w).

Return type:

numpy.ndarray

pyidi.methods._dic._jacobian_rigid(h, w)[source]#

Rigid warp Jacobian (evaluated at p = 0) on centered coords.

Parameters:
  • h (int) – subset height.

  • w (int) – subset width.

Returns:

array of shape (2, 3, h, w).

Return type:

numpy.ndarray

pyidi.methods._dic._sd_images(grad, jac)[source]#

Compute the steepest-descent images.

Parameters:
  • grad (tuple of numpy.ndarray) – tuple (gx, gy) of subset gradients with shape (h, w).

  • jac (numpy.ndarray) – warp Jacobian with shape (2, n_param, h, w).

Returns:

SD images with shape (n_param, h, w).

Return type:

numpy.ndarray

pyidi.methods._dic._hessian(sd)[source]#

Compute the (Gauss-Newton) Hessian from the SD images.

Parameters:

sd (numpy.ndarray) – SD images with shape (n_param, h, w).

Returns:

Hessian with shape (n_param, n_param).

Return type:

numpy.ndarray

pyidi.methods._dic._affine_warp_matrix(p)[source]#

Build the 3x3 affine warp matrix from parameter vector p.

Parameters:

p (array_like of size 6) – parameters [du/dx, du/dy, u, dv/dx, dv/dy, v].

Returns:

3x3 warp matrix.

Return type:

numpy.ndarray

pyidi.methods._dic._rigid_warp_matrix(p)[source]#

Build the 3x3 rigid warp matrix from parameter vector p.

Parameters:

p (array_like of size 3) – parameters [u, v, phi].

Returns:

3x3 warp matrix.

Return type:

numpy.ndarray

pyidi.methods._dic._params_from_affine_matrix(M)[source]#

Extract the 6-component affine parameter vector from a 3x3 matrix.

Parameters:

M (numpy.ndarray) – 3x3 affine warp matrix.

Returns:

parameter vector [du/dx, du/dy, u, dv/dx, dv/dy, v].

Return type:

numpy.ndarray

pyidi.methods._dic._params_from_rigid_matrix(M)[source]#

Extract the 3-component rigid parameter vector from a 3x3 matrix.

Parameters:

M (numpy.ndarray) – 3x3 rigid warp matrix.

Returns:

parameter vector [u, v, phi].

Return type:

numpy.ndarray

pyidi.methods._dic._gradient_dic(image, prefilter_gauss=True)[source]#

Compute image gradients using a 1-D finite-difference kernel.

Parameters:
  • image (numpy.ndarray) – input 2-D image.

  • prefilter_gauss (bool) – if True, use the Gauss-prefiltered kernel [-0.446, 0, 0.446]. Otherwise use [-0.5, 0, 0.5].

Returns:

tuple (gx, gy) of arrays with the same shape as image.

Return type:

tuple of numpy.ndarray

pyidi.methods._dic._get_initial_guess(target_image, reference_subset)[source]#

Estimate an integer-pixel translation from FFT cross-correlation.

Parameters:
  • target_image (numpy.ndarray) – full target image to search.

  • reference_subset (numpy.ndarray) – reference subset to locate in target_image.

Returns:

integer translation (dy, dx) of the subset upper-left corner relative to its expected position (top-left (0, 0)).

Return type:

tuple of int

pyidi.methods._dic.multi(video: VideoReader, idi_method: DIC, processes, configuration_keys: list)[source]#

Split the points across processes and run the DIC method in parallel.

Parameters:
  • video (VideoReader) – VideoReader object.

  • idi_method (DIC) – DIC instance to clone for each worker.

  • processes (int) – number of processes to run.

  • configuration_keys (list) – list of configuration keys forwarded to workers.

Returns:

tuple (displacements, warp_params) concatenated across workers.

Return type:

tuple of numpy.ndarray

pyidi.methods._dic.worker(points, idi_kwargs, method_kwargs, i, progress, task_id)[source]#

Worker function executed in each process.

Returns:

tuple (displacements, warp_params, i) for reduction.

Return type:

tuple

Postprocessing#

pyidi.postprocessing._motion_magnification.mode_shape_magnification(displacements: ndarray, magnification_factor: int | float, idi: IDIMethod | None = None, image: ndarray | memmap | None = None, points: ndarray | None = None, background_brightness: float = 0.3, show_undeformed: bool = False) ndarray[source]#

Create an image of a magnified mode-shape of a structure. If a IDI method instance is passed as argument idi, the argument image is set to the first image in sequence and the argument points is set to the points stored in the IDI method instance. These values can be overwritten by specifying the image and points arguments explicitly.

Parameters:
  • displacements (numpy.ndarray) – displacement (mode-shape) vector

  • magnification_factor (int or float) – magnification factor

  • idi (IDIMethod or None, optional) – IDI method instance, defaults to None

  • image (numpy.ndarray, numpy.memmap or None, optional) – the reference image, on which mode-shape magnification is performed, defaults to None

  • points (numpy.ndarray or None, optional) – image coordinates, where displacements ‘displacements’ are defined, defaults to None

  • background_brightness – brightness of the background, expected values in range [0, 1], defaults to 0.3

  • show_undeformed (bool, optional) – Show the reference image (argument ‘image’) underneath the magnified mode-shape, defaults to False

Returns:

image of a magnified mode-shape of the structure

Return type:

numpy.ndarray

pyidi.postprocessing._motion_magnification.animate(displacements: ndarray, magnification_factor: int | float, idi: IDIMethod | None = None, image: ndarray | memmap | None = None, points: ndarray | None = None, fps: int = 30, n_periods: int = 3, filename: str = 'mode_shape_mag_video', output_format: str = 'gif', background_brightness: float = 0.3, show_undeformed: bool = False) None[source]#

Create a video of a magnified mode-shape of a structure. If a IDI method instance is passed as argument idi, the argument image is set to the first image in sequence and the argument points is set to the points stored in the IDI method instance. These values can be overwritten by specifying the image and points arguments explicitly.

Parameters:
  • displacements (numpy.ndarray) – displacement vector

  • magnification_factor (int or float) – magnification factor

  • idi (IDIMethod or None, optional) – IDI method instance, defaults to None

  • image (numpy.ndarray, numpy.memmap or None, optional) – the reference image, on which mode-shape magnification is performed, defaults to None

  • points (numpy.ndarray or None, optional) – image coordinates, where displacements ‘displacements’ are defined, defaults to None

  • fps (int, optional) – framerate of the created video, defaults to 30

  • n_periods (int, optional) – number of periods of oscilation to be animated, defaults to 3

  • filename (str) – the name of the output video file defaults to ‘mode_shape_mag_video’

  • output_format (str, optional) – output format of the video, selected from ‘gif’, ‘mp4’, ‘avi’, ‘mov’, defaults to ‘gif’

  • background_brightness – brightness of the background, expected values in range [0, 1], defaults to 0.3

  • show_undeformed (bool, optional) – Show the reference image (argument ‘image’) underneath the magnified mode-shape, defaults to True

pyidi.postprocessing._motion_magnification.create_mesh(points, disp, mag_fact)[source]#

Generates a planar mesh of triangles based on the input set of points. Then generates the deformed planar mesh of triangles based on the displacement vectors ‘disp’, scaled by the magnification factor ‘mag_fact’.

pyidi.postprocessing._motion_magnification.init_output_image(input_image, mesh, mesh_def, bb, bu)[source]#

Initialze the output image. The output image needs to be large enough to prevent clipping of the motion magnified shape.

pyidi.postprocessing._motion_magnification.warp_image_elements(img_in, img_out, mesh, mesh_def, a, b)[source]#

Warp image elements based on mesh and deformed mesh nodes.

pyIDI base class#

class pyidi.pyidi_legacy.pyIDI(input_file, root=None)[source]#

Bases: object

__init__(input_file, root=None)[source]#

This class is no longer used in the new version of pyIDI.

Deprecated since version 1.0: Use VideoReader and method-specific classes instead.

In version 1.0 of pyIDI, some changes were made in the API.

To convert the old code to the new version, you can use the following example:

Old version:

>>> from pyidi import pyIDI
>>> video = pyIDI("path/to/file")
>>> video.set_method(...)
>>> video.set_points(...)
>>> video.method.configure(...)
>>> video.get_displacements()

New version:

>>> from pyidi import VideoReader, SimplifiedOpticalFlow, LucasKanade
>>> video = VideoReader("path/to/file")
>>> idi = SimplifiedOpticalFlow(video)
>>> idi.set_points(...)
>>> idi.configure(...)
>>> idi.get_displacements()

For more information, see the documentation at https://pyidi.readthedocs.io/en/latest/

set_method(method)[source]#

This method is no longer used in the new version of pyIDI.

In version 1.0 of pyIDI, some changes were made in the API.

To convert the old code to the new version, you can use the following example:

Old version:

>>> from pyidi import pyIDI
>>> video = pyIDI("path/to/file")
>>> video.set_method(...)
>>> video.set_points(...)
>>> video.method.configure(...)
>>> video.get_displacements()

New version:

>>> from pyidi import VideoReader, SimplifiedOpticalFlow, LucasKanade
>>> video = VideoReader("path/to/file")
>>> idi = SimplifiedOpticalFlow(video)
>>> idi.set_points(...)
>>> idi.configure(...)
>>> idi.get_displacements()

For more information, see the documentation at https://pyidi.readthedocs.io/en/latest/

set_points(points)[source]#

This method is no longer used in the new version of pyIDI.

In version 1.0 of pyIDI, some changes were made in the API.

To convert the old code to the new version, you can use the following example:

Old version:

>>> from pyidi import pyIDI
>>> video = pyIDI("path/to/file")
>>> video.set_method(...)
>>> video.set_points(...)
>>> video.method.configure(...)
>>> video.get_displacements()

New version:

>>> from pyidi import VideoReader, SimplifiedOpticalFlow, LucasKanade
>>> video = VideoReader("path/to/file")
>>> idi = SimplifiedOpticalFlow(video)
>>> idi.set_points(...)
>>> idi.configure(...)
>>> idi.get_displacements()

For more information, see the documentation at https://pyidi.readthedocs.io/en/latest/

get_displacements(*args, **kwargs)[source]#

This method is no longer used in the new version of pyIDI.

In version 1.0 of pyIDI, some changes were made in the API.

To convert the old code to the new version, you can use the following example:

Old version:

>>> from pyidi import pyIDI
>>> video = pyIDI("path/to/file")
>>> video.set_method(...)
>>> video.set_points(...)
>>> video.method.configure(...)
>>> video.get_displacements()

New version:

>>> from pyidi import VideoReader, SimplifiedOpticalFlow, LucasKanade
>>> video = VideoReader("path/to/file")
>>> idi = SimplifiedOpticalFlow(video)
>>> idi.set_points(...)
>>> idi.configure(...)
>>> idi.get_displacements()

For more information, see the documentation at https://pyidi.readthedocs.io/en/latest/