Skip to content
This repository was archived by the owner on Nov 13, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,23 @@ detect_target:
model_path: "tests/model_example/yolov8s_ultralytics_pretrained_default.pt" # See autonomy OneDrive for latest model
save_prefix: "log_comp"

detect_brightspot:
brightspot_percentile_threshold: 99.9
filter_by_color: True
blob_color: 255
filter_by_circularity: False
min_circularity: 0.01
min_circularity: 1
filter_by_inertia: True
min_inertia_ratio: 0.2
max_inertia_ratio: 1
filter_by_convexity: False
min_convexity: 0.01
min_convexity: 1
filter_by_area: True
min_area_pixels: 50
max_area_pixels: 640

flight_interface:
# Port 5762 connects directly to the simulated auto pilot, which is more realistic
# than connecting to port 14550, which is the ground station
Expand Down
94 changes: 83 additions & 11 deletions modules/detect_target/detect_target_brightspot.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,84 @@
from ..common.modules.logger import logger


BRIGHTSPOT_PERCENTILE = 99.9

# Label for brightspots; is 1 since 0 is used for blue landing pads
DETECTION_LABEL = 1
# SimpleBlobDetector is a binary detector, so a detection has confidence 1.0 by default
CONFIDENCE = 1.0


# Class has 15 attributes
# pylint: disable=too-many-instance-attributes
class DetectTargetBrightspotConfig:
"""
Configuration for DetectTargetBrightspot.
"""

def __init__(
self,
brightspot_percentile_threshold: float,
filter_by_color: bool,
blob_color: int,
filter_by_circularity: bool,
min_circularity: float,
max_circularity: float,
filter_by_inertia: bool,
min_inertia_ratio: float,
max_inertia_ratio: float,
filter_by_convexity: bool,
min_convexity: float,
max_convexity: float,
filter_by_area: bool,
min_area_pixels: int,
max_area_pixels: int,
) -> None:
"""
Initializes the configuration for DetectTargetBrightspot.

brightspot_percentile_threshold: Percentile threshold for bright spots.
filter_by_color: Whether to filter by color.
blob_color: Color of the blob.
filter_by_circularity: Whether to filter by circularity.
min_circularity: Minimum circularity.
max_circularity: Maximum circularity.
filter_by_inertia: Whether to filter by inertia.
min_inertia_ratio: Minimum inertia ratio.
max_inertia_ratio: Maximum inertia ratio.
filter_by_convexity: Whether to filter by convexity.
min_convexity: Minimum convexity.
max_convexity: Maximum convexity.
filter_by_area: Whether to filter by area.
min_area_pixels: Minimum area in pixels.
max_area_pixels: Maximum area in pixels.
"""
self.brightspot_percentile_threshold = brightspot_percentile_threshold
self.filter_by_color = filter_by_color
self.blob_color = blob_color
self.filter_by_circularity = filter_by_circularity
self.min_circularity = min_circularity
self.max_circularity = max_circularity
self.filter_by_inertia = filter_by_inertia
self.min_inertia_ratio = min_inertia_ratio
self.max_inertia_ratio = max_inertia_ratio
self.filter_by_convexity = filter_by_convexity
self.min_convexity = min_convexity
self.max_convexity = max_convexity
self.filter_by_area = filter_by_area
self.min_area_pixels = min_area_pixels
self.max_area_pixels = max_area_pixels


# pylint: enable=too-many-instance-attributes


class DetectTargetBrightspot(base_detect_target.BaseDetectTarget):
"""
Detects bright spots in images.
"""

def __init__(
self,
config: DetectTargetBrightspotConfig,
local_logger: logger.Logger,
show_annotations: bool = False,
save_name: str = "",
Expand All @@ -38,6 +101,7 @@ def __init__(
show_annotations: Display annotated images.
save_name: Filename prefix for logging detections and annotated images.
"""
self.__config = config
self.__counter = 0
self.__local_logger = local_logger
self.__show_annotations = show_annotations
Expand Down Expand Up @@ -68,7 +132,9 @@ def run(
)
return False, None

brightspot_threshold = np.percentile(grey_image, BRIGHTSPOT_PERCENTILE)
brightspot_threshold = np.percentile(
grey_image, self.__config.brightspot_percentile_threshold
)

# Apply thresholding to isolate bright spots
threshold_used, bw_image = cv2.threshold(
Expand All @@ -80,14 +146,20 @@ def run(

# Set up SimpleBlobDetector
params = cv2.SimpleBlobDetector_Params()
params.filterByColor = True
params.blobColor = 255
params.filterByCircularity = False
params.filterByInertia = True
params.minInertiaRatio = 0.2
params.filterByConvexity = False
params.filterByArea = True
params.minArea = 50 # pixels
params.filterByColor = self.__config.filter_by_color
params.blobColor = self.__config.blob_color
params.filterByCircularity = self.__config.filter_by_circularity
params.minCircularity = self.__config.min_circularity
params.maxCircularity = self.__config.max_circularity
params.filterByInertia = self.__config.filter_by_inertia
params.minInertiaRatio = self.__config.min_inertia_ratio
params.maxInertiaRatio = self.__config.max_inertia_ratio
params.filterByConvexity = self.__config.filter_by_convexity
params.minConvexity = self.__config.min_convexity
params.maxConvexity = self.__config.max_convexity
params.filterByArea = self.__config.filter_by_area
params.minArea = self.__config.min_area_pixels
params.maxArea = self.__config.max_area_pixels

detector = cv2.SimpleBlobDetector_create(params)
keypoints = detector.detect(bw_image)
Expand Down
23 changes: 22 additions & 1 deletion tests/brightspot_example/generate_expected.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,24 @@
pathlib.Path(f"ir_no_detections_{i}.png") for i in range(0, NUMBER_OF_IMAGES_NO_DETECTIONS)
]

DETECT_TARGET_BRIGHTSPOT_CONFIG = detect_target_brightspot.DetectTargetBrightspotConfig(
brightspot_percentile_threshold=99.9,
filter_by_color=True,
blob_color=255,
filter_by_circularity=False,
min_circularity=0.01,
max_circularity=1,
filter_by_inertia=True,
min_inertia_ratio=0.2,
max_inertia_ratio=1,
filter_by_convexity=False,
min_convexity=0.01,
max_convexity=1,
filter_by_area=True,
min_area_pixels=50,
max_area_pixels=640,
)


def main() -> int:
"""
Expand All @@ -43,7 +61,10 @@ def main() -> int:
return 1

detector = detect_target_brightspot.DetectTargetBrightspot(
local_logger=temp_logger, show_annotations=False, save_name=""
config=DETECT_TARGET_BRIGHTSPOT_CONFIG,
local_logger=temp_logger,
show_annotations=False,
save_name="",
)

for image_file, annotated_image_path, expected_detections_path in zip(
Expand Down
22 changes: 21 additions & 1 deletion tests/unit/test_detect_target_brightspot.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,24 @@
BOUNDING_BOX_PRECISION_TOLERANCE = 3
CONFIDENCE_PRECISION_TOLERANCE = 6

DETECT_TARGET_BRIGHTSPOT_CONFIG = detect_target_brightspot.DetectTargetBrightspotConfig(
brightspot_percentile_threshold=99.9,
filter_by_color=True,
blob_color=255,
filter_by_circularity=False,
min_circularity=0.01,
max_circularity=1,
filter_by_inertia=True,
min_inertia_ratio=0.2,
max_inertia_ratio=1,
filter_by_convexity=False,
min_convexity=0.01,
max_convexity=1,
filter_by_area=True,
min_area_pixels=50,
max_area_pixels=640,
)


# Test functions use test fixture signature names and access class privates
# No enable
Expand Down Expand Up @@ -121,7 +139,9 @@ def detector() -> detect_target_brightspot.DetectTargetBrightspot: # type: igno
assert result
assert test_logger is not None

detection = detect_target_brightspot.DetectTargetBrightspot(test_logger)
detection = detect_target_brightspot.DetectTargetBrightspot(
DETECT_TARGET_BRIGHTSPOT_CONFIG, test_logger
)
yield detection # type: ignore


Expand Down
Loading