Module Reference

Analysis

class flametrack.analysis.flamespread.EdgeFn(*args, **kwargs)[source]

Bases: Protocol

class flametrack.analysis.flamespread.EdgeMethodSpec(short_id: str, display_name: str, description: str, make_fn: Callable[[float], EdgeFn], default_threshold_ir: float, default_threshold_image: float, use_otsu_masking: bool = True)[source]

Bases: object

Descriptor for a named edge-detection method variant.

default_threshold_image: float
default_threshold_ir: float
description: str
display_name: str
make_fn: Callable[[float], EdgeFn]
short_id: str
use_otsu_masking: bool = True
flametrack.analysis.flamespread.band_filter(frame: ndarray, low: float | None = None, high: float | None = None) ndarray[source]

Clip intensity values between low and high threshold.

Parameters:
  • frame (np.ndarray) – Input image.

  • low (float) – Lower clipping limit.

  • high (float) – Upper clipping limit.

Returns:

Filtered image.

Return type:

np.ndarray

flametrack.analysis.flamespread.calculate_edge_data(data: ~numpy.ndarray, find_edge_point: ~flametrack.analysis.flamespread.EdgeFn, custom_filter: ~collections.abc.Callable[[~numpy.ndarray], ~numpy.ndarray] = <function <lambda>>, use_otsu_masking: bool = True) list[list[int]][source]

Calculates the edge position for each row of each frame.

Parameters:
  • data (np.ndarray) – 3D array of shape (H, W, T).

  • find_edge_point (Callable) – Method to find edge in 1D data.

  • custom_filter (Callable) – Optional filter to apply to each frame.

  • use_otsu_masking (bool) – If True (default), apply Otsu thresholding and morphological dilation to restrict the per-row search window. Set False to scan the full row without any masking (useful when a fixed intensity threshold alone is sufficient and Otsu would over-shrink the window, e.g. with a deliberately low threshold such as 117).

Returns:

Edge coordinates per frame.

Return type:

list[list[int]]

flametrack.analysis.flamespread.calculate_edge_results_for_exp_name(exp_name: str, left: bool = False, dewarped_data: ndarray | None = None, save: bool = True) ndarray | None[source]

Run full edge detection pipeline for a given experiment name.

Parameters:
  • exp_name (str) – Experiment identifier.

  • left (bool) – Whether to process left side.

  • dewarped_data (np.ndarray) – Optional preloaded data.

  • save (bool) – Whether to write result to HDF5.

Returns:

Edge data (if save=False).

Return type:

np.ndarray

flametrack.analysis.flamespread.find_peaks_in_gradient(y: ndarray, min_distance: int = 10, min_height: float = 2, min_width: int = 2) ndarray[source]

Find peaks in the negative gradient of a 1D signal.

Parameters:
  • y (np.ndarray) – 1D signal.

  • min_distance (int) – Minimum distance between peaks.

  • min_height (float) – Minimum peak height.

  • min_width (float) – Minimum peak width.

Returns:

Indices of detected peaks.

Return type:

np.ndarray

flametrack.analysis.flamespread.highest_peak(y: ndarray, min_distance: int = 10, min_height: float = 2, min_width: int = 2) int[source]

Return the index of the peak with the highest gradient.

Returns:

Index of the highest peak, or 0.

Return type:

int

flametrack.analysis.flamespread.highest_peak_to_lowest_value(y: ndarray, min_distance: int = 10, min_height: float = 2, min_width: int = 2, ambient_weighting: float = 2, high_val: float = 0, low_val: float = 10000000000.0, direction_weighting: float = 0.0, previous_peak: int | None = None, previous_velocity: float = 0) int[source]

Find the most plausible flame front peak using gradient + ambient suppression + direction.

Returns:

Index of selected edge point.

Return type:

int

flametrack.analysis.flamespread.left_edge_of_rightmost_cluster(y: ndarray, threshold: float = 128, params: dict | None = None) int[source]

Find the leftmost pixel of the rightmost contiguous cluster above threshold.

This is the correct edge function for a flame spreading right-to-left in image/video data (0–255 range). Unlike left_most_point_over_threshold, it ignores isolated bright artefacts (reflections, glare) that are not part of the main hot region.

Algorithm:
  1. Find the rightmost pixel above threshold.

  2. Walk left while still above threshold.

  3. Return the index one step past the last hot pixel (= leftmost edge).

Returns len(y) when no pixel exceeds the threshold.

flametrack.analysis.flamespread.left_most_point_over_threshold(y: ndarray, threshold: float = 0, params: dict | None = None) int[source]

Find the first point in the signal above the given threshold.

Parameters:
  • y (np.ndarray) – 1D signal.

  • threshold (float) – Threshold value.

  • params – Unused; kept for compatibility.

Returns:

Index of the first point above threshold, or len(y).

Return type:

int

flametrack.analysis.flamespread.plot_edge(frame: ~numpy.ndarray, find_edge_point: ~collections.abc.Callable[[~numpy.ndarray], int] = <function right_most_peak>) None[source]

Plot detected edge for each line in the frame.

Parameters:
  • frame (np.ndarray) – 2D thermal frame.

  • find_edge_point (Callable) – Edge detection function.

flametrack.analysis.flamespread.right_edge_of_leftmost_cluster(y: ndarray, threshold: float = 128, params: dict | None = None) int[source]

Find the rightmost pixel of the leftmost contiguous cluster above threshold.

Mirror of left_edge_of_rightmost_cluster for flames spreading left-to-right.

Returns 0 when no pixel exceeds the threshold.

flametrack.analysis.flamespread.right_most_peak(y: ndarray, min_distance: int = 10, min_height: float = 2, min_width: int = 2) int[source]

Return the right-most peak in the gradient of the signal.

Returns:

Index of last detected peak, or 0.

Return type:

int

flametrack.analysis.flamespread.right_most_point_over_threshold(y: ndarray, threshold: float = 0, params: dict | None = None) int[source]

Find the last point in the signal above the given threshold.

Parameters:
  • y (np.ndarray) – 1D signal.

  • threshold (float) – Threshold value.

  • params – Unused; kept for compatibility.

Returns:

Index of the last point above threshold, or 0.

Return type:

int

flametrack.analysis.flamespread.show_flame_contour(data: ndarray, edge_results: ndarray, frame: int) tuple[Figure, Axes][source]

Overlay detected edge on thermal image for a given frame.

Parameters:
  • data (np.ndarray) – 3D image data.

  • edge_results (np.ndarray) – Edge matrix.

  • frame (int) – Frame index.

Returns:

Matplotlib figure and axis.

Return type:

fig, ax

flametrack.analysis.flamespread.show_flame_spread(edge_results: ndarray, y_coord: int) tuple[Figure, Axes][source]

Plot flame front x-coordinate over time at a given y-line.

Parameters:
  • edge_results (np.ndarray) – Edge matrix.

  • y_coord (int) – Line index from bottom.

Returns:

Matplotlib figure and axis.

Return type:

fig, ax

flametrack.analysis.flamespread.show_flame_spread_velocity(edge_results: ndarray, y_coord: int, rolling_window: int = 3) tuple[Figure, Axes][source]

Plot local velocity of flame front at a fixed y-line.

Parameters:
  • edge_results (np.ndarray) – Edge data.

  • y_coord (int) – Line index.

  • rolling_window (int) – Smoothing window size.

Returns:

Matplotlib figure and axis.

Return type:

fig, ax

flametrack.analysis.dataset_handler.assert_h5_schema(h5: File, experiment_type: str) None[source]

Verifiziere, dass die nötigen Gruppen existieren. Praktisch für frühe, klare Fehlermeldungen.

flametrack.analysis.dataset_handler.close_file() None[source]

Close the currently opened HDF5 file, if any.

flametrack.analysis.dataset_handler.create_h5_file(exp_name: str | None = None, filename: str | None = None) File[source]

Create a new HDF5 file. Diese Funktion erzeugt KEINE experiment-spezifischen Gruppen.

flametrack.analysis.dataset_handler.get_data(exp_name: str, group_name: str, left: bool = False) Dataset[source]

Retrieve dataset for given experiment and group.

Parameters:
  • exp_name – Experiment name.

  • group_name – Group name in HDF5 file (‘dewarped_data’ or ‘edge_results’).

  • left – Use left variant if True.

Returns:

Dataset object.

Return type:

h5py.Dataset

flametrack.analysis.dataset_handler.get_dewarped_data(exp_name: str, left: bool = False) Dataset[source]

Get dewarped data dataset from the experiment file.

flametrack.analysis.dataset_handler.get_dewarped_metadata(exp_name: str, left: bool = False) dict[source]

Get metadata attributes from dewarped_data group.

flametrack.analysis.dataset_handler.get_edge_results(exp_name: str, left: bool = False) Dataset[source]

Get edge results dataset from the experiment file.

flametrack.analysis.dataset_handler.get_file(exp_name: str, mode: Literal['r', 'a'] = 'r', left: bool = False) File[source]

Open or reuse HDF5 file for the experiment.

flametrack.analysis.dataset_handler.get_h5_file_path(exp_name: str, left: bool = False) str[source]
flametrack.analysis.dataset_handler.init_h5_for_experiment(h5: File, experiment_type: str) None[source]

Lege die nötigen Gruppen je Experimenttyp an. Kann z. B. direkt nach create_h5_file(…) aufgerufen werden.

flametrack.analysis.dataset_handler.save_edge_results(exp_name: str, edge_results: ndarray[tuple[int, ...], dtype[floating]] | ndarray[tuple[int, ...], dtype[integer]], left: bool = False) None[source]

Save edge results array to the experiment’s HDF5 file.

Opens a fresh file handle just for this write (no global handle usage).

flametrack.analysis.ir_analysis.compute_remap_from_homography(homography: ndarray[tuple[int, ...], dtype[float32]] | ndarray[tuple[int, ...], dtype[float64]], width: int, height: int) tuple[ndarray[tuple[int, ...], dtype[float32]], ndarray[tuple[int, ...], dtype[float32]]][source]

Compute pixelwise remap grids from a homography.

Parameters:
  • homography (numpy.ndarray) – 3×3 homography mapping output → input coordinates.

  • width (int) – Target image width in pixels.

  • height (int) – Target image height in pixels.

Returns:

Two arrays (src_x, src_y) with shape (height, width), dtype float32 suitable for cv2.remap.

Return type:

tuple[numpy.ndarray, numpy.ndarray]

flametrack.analysis.ir_analysis.get_dewarp_parameters(corners: ndarray[tuple[int, ...], dtype[float32]] | Sequence[tuple[float, float]], target_pixels_width: int | None = None, target_pixels_height: int | None = None, target_ratio: float | None = None, *, plate_width_m: float | None = None, plate_height_m: float | None = None, pixels_per_millimeter: int = 1) dict[str, Any][source]

Calculate homography and target geometry for dewarping.

You can either pass physical plate dimensions (plate_width_m, plate_height_m) plus a pixel density, or infer target geometry from the selected corners and a desired aspect ratio.

Parameters:
  • corners (numpy.ndarray | Sequence[tuple[float, float]]) – Four corner points in pixel coordinates, ordered clockwise starting at top-left.

  • target_pixels_width (int, optional) – Target width in pixels. If omitted, it will be derived from target_ratio and the measured corner distances.

  • target_pixels_height (int, optional) – Target height in pixels. If omitted, it will be derived from target_ratio and the measured corner distances.

  • target_ratio (float, optional) – Desired aspect ratio height / width. Required if target size is not specified and no physical plate size is provided.

  • plate_width_m (float, optional) – Physical plate width in meters. Used with pixels_per_millimeter to derive target size if provided with plate_height_m.

  • plate_height_m (float, optional) – Physical plate height in meters. Used with pixels_per_millimeter to derive target size if provided with plate_width_m.

  • pixels_per_millimeter (int, optional) – Pixel density (px/mm) used when physical dimensions are given. Default is 1.

Returns:

Dictionary with:
  • transformation_matrix (numpy.ndarray): 3×3 homography (float32).

  • target_pixels_width (int): Target width in pixels.

  • target_pixels_height (int): Target height in pixels.

  • target_ratio (float): height / width of the target.

Return type:

dict[str, Any]

Raises:

ValueError – If neither physical dimensions nor a target ratio are provided.

Notes

Current conversion multiplies meter values by pixels_per_millimeter. For strict unit consistency, consider using millimeters or pixels_per_meter.

flametrack.analysis.ir_analysis.read_ir_data(filename: str) ndarray[tuple[int, ...], dtype[float64]][source]

Read raw IR data from a CSV-like ASCII export.

The file is scanned until a line [Data] is found; subsequent lines are parsed using ; as delimiter and a comma-to-dot decimal replacement.

Parameters:

filename (str) – Path to the IR data file.

Returns:

2D array of IR values (dtype float64).

Return type:

numpy.ndarray

Raises:

ValueError – If no [Data] section is found in the file.

GUI

The GUI layer (flametrack.gui) is based on PySide6 and is excluded from the API reference — Qt widget subclasses are best understood by reading the source directly. The architecture overview is in Architecture Overview.

flametrack.gui.plotting_utils.rotate_points(points, image_shape, rotation_index)[source]

Converts points from a np.rot90-rotated display frame back to unrotated image coordinates.

Parameters:
  • points – Liste von (x, y)-Punkten im rotierten Bild

  • image_shape – Form des UNROTIERTEN Bildes als (Höhe, Breite)

  • rotation_index – 0 = 0°, 1 = 90° CCW, 2 = 180°, 3 = 270° CCW

Returns:

Punkte im unrotierten Bildkoordinatensystem als Liste von (x, y)

flametrack.gui.plotting_utils.sort_corner_points(points, experiment_type='Room Corner', direction='clockwise') list[source]

Sort corner points depending on experiment type. - For ‘room_corner’ (6 points): Sort using angle-based method with defined start point - For ‘lateral_flame_spread’ (4 points): Sort using center angle

Processing

class flametrack.processing.dewarping.CornerSets(left: numpy.ndarray[tuple[int, ...], numpy.dtype[numpy.float32]], right: numpy.ndarray[tuple[int, ...], numpy.dtype[numpy.float32]])[source]

Bases: object

left: ndarray[tuple[int, ...], dtype[float32]]
right: ndarray[tuple[int, ...], dtype[float32]]
class flametrack.processing.dewarping.DewarpConfig(target_ratio: float, target_pixels_width: int, target_pixels_height: int, plate_width_mm: float | None = None, plate_height_mm: float | None = None, rotation_index: int = 0, frequency: int = 1, testing: bool = False, filename: str | None = None, datatype: str = 'IR')[source]

Bases: object

datatype: str = 'IR'
filename: str | None = None
frequency: int = 1
plate_height_mm: float | None = None
plate_width_mm: float | None = None
rotation_index: int = 0
target_pixels_height: int
target_pixels_width: int
target_ratio: float
testing: bool = False
flametrack.processing.dewarping.dewarp_lateral_flame_spread(experiment: Any, points: Sequence[tuple[float, float]], config: DewarpConfig) Generator[int, None, None][source]

Dewarp für Lateral Flame Spread (warpPerspective).

flametrack.processing.dewarping.dewarp_room_corner_remap(experiment: Any, points: ndarray[tuple[int, ...], dtype[float32]] | Sequence[tuple[float, float]], config: DewarpConfig) Generator[int, None, None][source]

Dewarp für Room Corner anhand vorberechneter Remap‑Grids.

flametrack.processing.dewarping.rotate_image_and_points(image: ndarray[tuple[int, ...], dtype[float32]] | ndarray[tuple[int, ...], dtype[uint8]], points: ndarray[tuple[int, ...], dtype[float32]], angle_degrees: float) tuple[ndarray[tuple[int, ...], dtype[float32]], ndarray[tuple[int, ...], dtype[float32]]][source]

Rotate both image and corresponding points.

Parameters:
  • image – Input image.

  • points – Nx2 array of (x, y) points.

  • angle_degrees – Rotation angle in degrees.

Returns:

A tuple (rotated_image, rotated_points)

Utils

flametrack.utils.math_utils.compute_target_ratio(width: float, height: float) float[source]
flametrack.utils.math_utils.estimate_resolution_from_points(p0, p1, p3, plate_width_mm, plate_height_mm, *, assumed_error_px: float = 0.5) dict[source]

Estimate spatial resolution and absolute measurement uncertainty based on manually marked rectangle.

Parameters:
  • p0 (array-like) – Top-left point of rectangle in pixels.

  • p1 (array-like) – Top-right point of rectangle in pixels.

  • p3 (array-like) – Bottom-left point of rectangle in pixels.

  • plate_width_mm (float) – Real-world width of the physical plate in millimeters.

  • plate_height_mm (float) – Real-world height of the physical plate in millimeters.

  • assumed_error_px (float, optional) – Pixel accuracy assumed for manual point selection (default is ±0.5 px).

Returns:

Dictionary with estimated resolution and error terms (all float): - mm_per_px_width - mm_per_px_height - error_mm_width - error_mm_height - assumed_pixel_error

Return type:

dict