Detection Modules

Utilities

Shared utilities for thermal object detection.

Provides common data structures and utility functions used across different detection modules.

class pythermal.detections.utils.DetectedObject(center_x: float, center_y: float, width: int, height: int, area: int, avg_temperature: float, max_temperature: float, min_temperature: float)[source]

Bases: object

Represents a detected object with its center and properties

center_x: float
center_y: float
width: int
height: int
area: int
avg_temperature: float
max_temperature: float
min_temperature: float
__init__(center_x: float, center_y: float, width: int, height: int, area: int, avg_temperature: float, max_temperature: float, min_temperature: float) None
pythermal.detections.utils.convert_to_celsius(temp_array: ndarray, min_temp: float, max_temp: float) ndarray[source]

Convert temperature array to Celsius.

Parameters:
  • temp_array – Temperature array (uint16 or float32)

  • min_temp – Minimum temperature in Celsius from metadata

  • max_temp – Maximum temperature in Celsius from metadata

Returns:

Temperature array in Celsius (float32)

pythermal.detections.utils.cluster_objects(objects: List[DetectedObject], max_distance: float = 30.0) List[List[DetectedObject]][source]

Cluster detected objects that are close to each other.

Uses simple distance-based clustering.

Parameters:
  • objects – List of DetectedObject instances

  • max_distance – Maximum distance between objects to be in the same cluster (default: 30.0)

Returns:

List of clusters, where each cluster is a list of DetectedObject instances

pythermal.detections.utils.calculate_aspect_ratio(obj: DetectedObject) float[source]

Calculate aspect ratio of detected object.

Parameters:

obj – DetectedObject instance

Returns:

Aspect ratio (width/height). Values > 1.0 indicate wider objects.

pythermal.detections.utils.calculate_compactness(obj: DetectedObject) float[source]

Calculate compactness (circularity approximation) of detected object.

Uses bounding box approximation: 4π*area/(width+height)² Higher values (closer to 1.0) indicate more circular/compact objects.

Parameters:

obj – DetectedObject instance

Returns:

Compactness value (0.0 to 1.0)

pythermal.detections.utils.calculate_circularity(contour: ndarray, area: float) float[source]

Calculate true circularity from contour.

Circularity = 4π*area/perimeter² Higher values (closer to 1.0) indicate more circular objects.

Parameters:
  • contour – Contour points (numpy array)

  • area – Contour area

Returns:

Circularity value (0.0 to 1.0)

pythermal.detections.utils.calculate_convexity_ratio(contour: ndarray, area: float) float[source]

Calculate convexity ratio from contour.

Convexity = area / convex_hull_area Higher values (closer to 1.0) indicate more convex objects.

Parameters:
  • contour – Contour points (numpy array)

  • area – Contour area

Returns:

Convexity ratio (0.0 to 1.0)

pythermal.detections.utils.filter_by_aspect_ratio(objects: List[DetectedObject], min_ratio: float | None = None, max_ratio: float | None = None) List[DetectedObject][source]

Filter objects by aspect ratio (width/height).

Parameters:
  • objects – List of DetectedObject instances

  • min_ratio – Minimum aspect ratio (default: None, no minimum)

  • max_ratio – Maximum aspect ratio (default: None, no maximum)

Returns:

Filtered list of objects

pythermal.detections.utils.filter_by_compactness(objects: List[DetectedObject], min_compactness: float | None = None, max_compactness: float | None = None) List[DetectedObject][source]

Filter objects by compactness (circularity approximation).

Parameters:
  • objects – List of DetectedObject instances

  • min_compactness – Minimum compactness (default: None, no minimum)

  • max_compactness – Maximum compactness (default: None, no maximum)

Returns:

Filtered list of objects

pythermal.detections.utils.filter_by_area(objects: List[DetectedObject], min_area: int | None = None, max_area: int | None = None) List[DetectedObject][source]

Filter objects by area.

Parameters:
  • objects – List of DetectedObject instances

  • min_area – Minimum area in pixels (default: None, no minimum)

  • max_area – Maximum area in pixels (default: None, no maximum)

Returns:

Filtered list of objects

pythermal.detections.utils.filter_by_shape(objects: List[DetectedObject], min_aspect_ratio: float | None = None, max_aspect_ratio: float | None = None, min_compactness: float | None = None, max_compactness: float | None = None, min_area: int | None = None, max_area: int | None = None) List[DetectedObject][source]

Filter objects by multiple shape criteria.

Convenience function that applies all shape filters at once.

Parameters:
  • objects – List of DetectedObject instances

  • min_aspect_ratio – Minimum aspect ratio (width/height)

  • max_aspect_ratio – Maximum aspect ratio (width/height)

  • min_compactness – Minimum compactness (0.0-1.0)

  • max_compactness – Maximum compactness (0.0-1.0)

  • min_area – Minimum area in pixels

  • max_area – Maximum area in pixels

Returns:

Filtered list of objects

Temperature Detection

Temperature-based object detection.

Provides functions to detect objects based on temperature ranges.

pythermal.detections.temperature_detection.detect_object_centers(temp_array: ndarray, min_temp: float, max_temp: float, temp_min: float = 31.0, temp_max: float = 39.0, min_area: int = 50) List[DetectedObject][source]

Detect object centers from temperature map based on temperature range.

Parameters:
  • temp_array – Temperature array (96x96, uint16 or float32)

  • min_temp – Minimum temperature in Celsius from metadata

  • max_temp – Maximum temperature in Celsius from metadata

  • temp_min – Minimum temperature threshold in Celsius (default: 31.0 for human body)

  • temp_max – Maximum temperature threshold in Celsius (default: 39.0 for human body)

  • min_area – Minimum area in pixels for detected objects (default: 50)

Returns:

List of DetectedObject instances with center coordinates and properties

pythermal.detections.temperature_detection.detect_humans_adaptive(temp_array: ndarray, min_temp: float, max_temp: float, environment_temp: float | None = None, alpha_min: float = 0.4, alpha_max: float = 0.7, core_temp: float = 37.0, min_area: int = 50, temp_margin: float = 2.0, min_temp_above_env: float = 2.0, max_temp_limit: float = 42.0, max_aspect_ratio: float = 4.0, min_aspect_ratio: float = 0.4) List[DetectedObject][source]

Advanced human detection using adaptive temperature thresholds based on environment temperature.

This method estimates the expected body temperature range from the environment temperature using the formula: Ts = Te + α × (Tc − Te)

Where: - Ts = Skin temperature (estimated body temperature) - Te = Environment temperature - Tc = Core body temperature (default: 37°C) - α = Blood flow regulation coefficient (0.5-0.7 for face/torso)

The detection focuses on warmer body parts (face/torso) and includes additional filters: - Minimum temperature above environment (to exclude cold objects) - Maximum temperature limit (to exclude hot objects like heaters) - Aspect ratio filtering (to match human body proportions) - Temperature consistency checks

Parameters:
  • temp_array – Temperature array (96x96, uint16 or float32)

  • min_temp – Minimum temperature in Celsius from metadata

  • max_temp – Maximum temperature in Celsius from metadata

  • environment_temp – Environment/room temperature in Celsius. If None, will be estimated from the frame using the 5th percentile method.

  • alpha_min – Minimum alpha value for detection (default: 0.4, includes some cooler body parts)

  • alpha_max – Maximum alpha value for detection (default: 0.7, face/torso)

  • core_temp – Core body temperature in Celsius (default: 37.0)

  • min_area – Minimum area in pixels for detected objects (default: 50)

  • temp_margin – Temperature margin in Celsius to add around estimated range (default: 2.0)

  • min_temp_above_env – Minimum temperature above environment to consider (default: 2.0°C) This helps exclude objects that are only slightly warmer than room

  • max_temp_limit – Maximum temperature limit to avoid detecting very hot objects (default: 42.0°C)

  • max_aspect_ratio – Maximum aspect ratio (width/height or height/width) for human detection (default: 4.0)

  • min_aspect_ratio – Minimum aspect ratio for human detection (default: 0.4)

Returns:

List of DetectedObject instances representing detected humans

Examples

>>> # Detect humans with estimated environment temperature
>>> objects = detect_humans_adaptive(temp_array, min_temp, max_temp)
>>> # Detect humans with known room temperature
>>> objects = detect_humans_adaptive(temp_array, min_temp, max_temp, environment_temp=22.0)

Motion Detection

Motion detection using background subtraction.

Provides background subtraction and motion detection for thermal images.

class pythermal.detections.motion_detection.BackgroundSubtractor(learning_rate: float = 0.01, history_size: int = 30, min_frames_for_background: int = 10)[source]

Bases: object

Background subtraction for thermal images using running average.

Maintains a background model and detects moving objects by comparing current frame to the background.

__init__(learning_rate: float = 0.01, history_size: int = 30, min_frames_for_background: int = 10)[source]

Initialize background subtractor.

Parameters:
  • learning_rate – Rate at which background model updates (0.0-1.0, default: 0.01) Lower values = slower adaptation, more stable background

  • history_size – Number of frames to keep in history for median-based background (default: 30)

  • min_frames_for_background – Minimum frames needed before background is considered stable (default: 10)

update(temp_celsius: ndarray) ndarray[source]

Update background model with new frame.

Parameters:

temp_celsius – Temperature array in Celsius (float32)

Returns:

Foreground mask (binary, uint8) - pixels that differ from background

get_background() ndarray | None[source]

Get current background model.

Returns:

Background temperature array in Celsius, or None if not initialized

reset()[source]

Reset background model.

is_ready() bool[source]

Check if background model is ready for use.

Returns:

True if background has been initialized with enough frames

pythermal.detections.motion_detection.detect_moving_objects(temp_array: ndarray, min_temp: float, max_temp: float, background_subtractor: BackgroundSubtractor, temp_threshold: float = 2.0, min_area: int = 50, combine_with_temp_range: bool = True, temp_min: float | None = None, temp_max: float | None = None) Tuple[List[DetectedObject], ndarray][source]

Detect moving objects using background subtraction.

Parameters:
  • temp_array – Temperature array (96x96, uint16 or float32)

  • min_temp – Minimum temperature in Celsius from metadata

  • max_temp – Maximum temperature in Celsius from metadata

  • background_subtractor – BackgroundSubtractor instance

  • temp_threshold – Temperature difference threshold in Celsius for motion detection (default: 2.0)

  • min_area – Minimum area in pixels for detected objects (default: 50)

  • combine_with_temp_range – If True, also filter by temperature range (default: True)

  • temp_min – Minimum temperature for filtering (only used if combine_with_temp_range=True)

  • temp_max – Maximum temperature for filtering (only used if combine_with_temp_range=True)

Returns:

Tuple of (list of DetectedObject instances, foreground mask)

ROI Management

Region of Interest (ROI) support for thermal detection.

Provides ROI management and zone monitoring capabilities.

class pythermal.detections.roi.ROI(x: int, y: int, width: int, height: int, name: str = 'ROI', temp_min: float | None = None, temp_max: float | None = None)[source]

Bases: object

Region of Interest definition.

Represents a rectangular region with optional temperature thresholds.

x: int
y: int
width: int
height: int
name: str = 'ROI'
temp_min: float | None = None
temp_max: float | None = None
contains(x: float, y: float) bool[source]

Check if point (x, y) is within this ROI.

get_mask(image_shape: Tuple[int, int]) ndarray[source]

Create a binary mask for this ROI.

Parameters:

image_shape – (height, width) of the image

Returns:

Binary mask (uint8) where ROI region is 255, rest is 0

__init__(x: int, y: int, width: int, height: int, name: str = 'ROI', temp_min: float | None = None, temp_max: float | None = None) None
class pythermal.detections.roi.ROIManager(image_width: int = 96, image_height: int = 96)[source]

Bases: object

Manages multiple ROIs for zone monitoring.

Supports multiple ROIs with different temperature thresholds.

__init__(image_width: int = 96, image_height: int = 96)[source]

Initialize ROI manager.

Parameters:
  • image_width – Width of the thermal image (default: 96)

  • image_height – Height of the thermal image (default: 96)

rois: List[ROI]
add_roi(x: int, y: int, width: int, height: int, name: str = 'ROI', temp_min: float | None = None, temp_max: float | None = None) ROI[source]

Add a new ROI.

Parameters:
  • x – X coordinate of top-left corner

  • y – Y coordinate of top-left corner

  • width – Width of ROI

  • height – Height of ROI

  • name – Name/label for this ROI

  • temp_min – Optional minimum temperature threshold for this ROI

  • temp_max – Optional maximum temperature threshold for this ROI

Returns:

The created ROI instance

add_center_roi(size: int = 30, name: str = 'Center', temp_min: float | None = None, temp_max: float | None = None) ROI[source]

Add a centered ROI.

Parameters:
  • size – Size of the square ROI (default: 30)

  • name – Name/label for this ROI

  • temp_min – Optional minimum temperature threshold for this ROI

  • temp_max – Optional maximum temperature threshold for this ROI

Returns:

The created ROI instance

remove_roi(name: str) bool[source]

Remove ROI by name.

Parameters:

name – Name of ROI to remove

Returns:

True if ROI was found and removed, False otherwise

clear()[source]

Remove all ROIs.

get_combined_mask() ndarray[source]

Get combined mask for all ROIs.

Returns:

Binary mask (uint8) where any ROI region is 255, rest is 0

filter_objects_by_roi(objects: List[DetectedObject], roi_name: str | None = None) List[DetectedObject][source]

Filter detected objects to only include those within ROI(s).

Parameters:
  • objects – List of detected objects

  • roi_name – If specified, only filter by this ROI. Otherwise, filter by all ROIs.

Returns:

Filtered list of objects within ROI(s)

filter_objects_by_temperature(objects: List[DetectedObject], temp_celsius: ndarray, roi_name: str | None = None) List[DetectedObject][source]

Filter detected objects by ROI temperature thresholds.

Parameters:
  • objects – List of detected objects

  • temp_celsius – Temperature array in Celsius

  • roi_name – If specified, only check this ROI. Otherwise, check all ROIs.

Returns:

Filtered list of objects that meet ROI temperature criteria

get_roi_statistics(temp_celsius: ndarray, roi_name: str | None = None) Dict[str, Dict[str, float]][source]

Get temperature statistics for each ROI.

Parameters:
  • temp_celsius – Temperature array in Celsius

  • roi_name – If specified, only get stats for this ROI. Otherwise, get stats for all ROIs.

Returns:

Dictionary mapping ROI names to their statistics (min, max, avg)

YOLO Detection

YOLO Object Detection

YOLO v11 Object Detection for Thermal Images

Provides object detection using YOLO v11 models. Supports both default official models and custom thermal-specific models.

class pythermal.detections.yolo.object_detection.YOLOObjectDetector(model_path: str | None = None, model_size: str = 'nano', conf_threshold: float = 0.25, iou_threshold: float = 0.45, device: str | None = None)[source]

Bases: object

YOLO v11 Object Detector for thermal images.

Supports both default official YOLO v11 models and custom thermal-specific models. Models are automatically downloaded on first use if not present.

DEFAULT_MODEL = 'yolo11n.pt'
MODEL_OPTIONS = {'large': 'yolo11l.pt', 'medium': 'yolo11m.pt', 'nano': 'yolo11n.pt', 'small': 'yolo11s.pt', 'xlarge': 'yolo11x.pt'}
__init__(model_path: str | None = None, model_size: str = 'nano', conf_threshold: float = 0.25, iou_threshold: float = 0.45, device: str | None = None)[source]

Initialize YOLO object detector.

Parameters:
  • model_path – Path to custom model file. If None, uses default official model. Can be absolute path or relative to models directory.

  • model_size – Model size for default model (“nano”, “small”, “medium”, “large”, “xlarge”). Only used if model_path is None.

  • conf_threshold – Confidence threshold for detections (0.0-1.0)

  • iou_threshold – IoU threshold for NMS (0.0-1.0)

  • device – Device to run inference on (“cpu”, “cuda”, “mps”, etc.). If None, auto-detects.

Raises:
detect(image: ndarray, classes: List[int] | None = None, verbose: bool = False) List[Dict[str, Any]][source]

Detect objects in thermal image.

Parameters:
  • image – Input image (BGR or RGB, numpy array)

  • classes – List of class IDs to detect (None = all classes)

  • verbose – Whether to print detection details

Returns:

  • “bbox”: [x1, y1, x2, y2] bounding box coordinates

  • ”confidence”: Detection confidence (0.0-1.0)

  • ”class_id”: Class ID

  • ”class_name”: Class name

  • ”center”: (x, y) center coordinates

  • ”width”: Bounding box width

  • ”height”: Bounding box height

Return type:

List of detection dictionaries, each containing

detect_batch(images: List[ndarray], classes: List[int] | None = None, verbose: bool = False) List[List[Dict[str, Any]]][source]

Detect objects in multiple images (batch processing).

Parameters:
  • images – List of input images

  • classes – List of class IDs to detect (None = all classes)

  • verbose – Whether to print detection details

Returns:

List of detection lists (one per image)

get_class_names() Dict[int, str][source]

Get mapping of class IDs to class names.

Returns:

Dictionary mapping class_id -> class_name

visualize(image: ndarray, detections: List[Dict[str, Any]], show_labels: bool = True, show_conf: bool = True) ndarray[source]

Visualize detections on image.

Parameters:
  • image – Input image (BGR format)

  • detections – List of detection dictionaries from detect()

  • show_labels – Whether to show class labels

  • show_conf – Whether to show confidence scores

Returns:

Image with detections drawn (BGR format)

YOLO Pose Detection

YOLO v11 Pose Detection for Thermal Images

Provides pose/keypoint detection using YOLO v11 pose models. Supports both default official models and custom thermal-specific models.

class pythermal.detections.yolo.pose_detection.YOLOPoseDetector(model_path: str | None = None, model_size: str = 'nano', conf_threshold: float = 0.25, iou_threshold: float = 0.45, device: str | None = None)[source]

Bases: object

YOLO v11 Pose Detector for thermal images.

Supports both default official YOLO v11 pose models and custom thermal-specific models. Models are automatically downloaded on first use if not present.

DEFAULT_MODEL = 'yolo11n-pose.pt'
MODEL_OPTIONS = {'large': 'yolo11l-pose.pt', 'medium': 'yolo11m-pose.pt', 'nano': 'yolo11n-pose.pt', 'small': 'yolo11s-pose.pt', 'xlarge': 'yolo11x-pose.pt'}
KEYPOINT_NAMES = ['nose', 'left_eye', 'right_eye', 'left_ear', 'right_ear', 'left_shoulder', 'right_shoulder', 'left_elbow', 'right_elbow', 'left_wrist', 'right_wrist', 'left_hip', 'right_hip', 'left_knee', 'right_knee', 'left_ankle', 'right_ankle']
SKELETON_CONNECTIONS = [(0, 1), (0, 2), (1, 3), (2, 4), (5, 6), (5, 11), (6, 12), (11, 12), (5, 7), (7, 9), (6, 8), (8, 10), (11, 13), (13, 15), (12, 14), (14, 16)]
__init__(model_path: str | None = None, model_size: str = 'nano', conf_threshold: float = 0.25, iou_threshold: float = 0.45, device: str | None = None)[source]

Initialize YOLO pose detector.

Parameters:
  • model_path – Path to custom model file. If None, uses default official model. Can be absolute path or relative to models directory.

  • model_size – Model size for default model (“nano”, “small”, “medium”, “large”, “xlarge”). Only used if model_path is None.

  • conf_threshold – Confidence threshold for detections (0.0-1.0)

  • iou_threshold – IoU threshold for NMS (0.0-1.0)

  • device – Device to run inference on (“cpu”, “cuda”, “mps”, etc.). If None, auto-detects.

Raises:
detect(image: ndarray, verbose: bool = False) List[Dict[str, Any]][source]

Detect poses/keypoints in thermal image.

Parameters:
  • image – Input image (BGR or RGB, numpy array)

  • verbose – Whether to print detection details

Returns:

  • “bbox”: [x1, y1, x2, y2] bounding box coordinates

  • ”confidence”: Detection confidence (0.0-1.0)

  • ”keypoints”: List of (x, y, confidence) tuples for each keypoint (17 keypoints)

  • ”keypoints_dict”: Dictionary mapping keypoint names to (x, y, confidence)

  • ”center”: (x, y) center coordinates of person

  • ”width”: Bounding box width

  • ”height”: Bounding box height

Return type:

List of pose detection dictionaries, each containing

detect_batch(images: List[ndarray], verbose: bool = False) List[List[Dict[str, Any]]][source]

Detect poses in multiple images (batch processing).

Parameters:
  • images – List of input images

  • verbose – Whether to print detection details

Returns:

List of pose detection lists (one per image)

visualize(image: ndarray, detections: List[Dict[str, Any]], show_bbox: bool = True, show_keypoints: bool = True, show_skeleton: bool = True, show_labels: bool = False, keypoint_radius: int = 3, skeleton_thickness: int = 2) ndarray[source]

Visualize pose detections on image.

Parameters:
  • image – Input image (BGR format)

  • detections – List of pose detection dictionaries from detect()

  • show_bbox – Whether to show bounding boxes

  • show_keypoints – Whether to show keypoints

  • show_skeleton – Whether to show skeleton connections

  • show_labels – Whether to show keypoint labels

  • keypoint_radius – Radius of keypoint circles

  • skeleton_thickness – Thickness of skeleton lines

Returns:

Image with pose detections drawn (BGR format)