Skip to content

Commit

Permalink
Merge branch 'main' into restart_workers_patch_new
Browse files Browse the repository at this point in the history
  • Loading branch information
Adityya-K authored Jan 22, 2025
2 parents fb4a67f + def8f2d commit 543219d
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 34 deletions.
18 changes: 18 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
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

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 All @@ -53,6 +70,7 @@ geolocation:
cluster_estimation:
min_activation_threshold: 25
min_new_points_to_run: 5
max_num_components: 10
random_state: 0

communications:
Expand Down
8 changes: 7 additions & 1 deletion main_2024.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ def main() -> int:

MIN_ACTIVATION_THRESHOLD = config["cluster_estimation"]["min_activation_threshold"]
MIN_NEW_POINTS_TO_RUN = config["cluster_estimation"]["min_new_points_to_run"]
MAX_NUM_COMPONENTS = config["cluster_estimation"]["max_num_components"]
RANDOM_STATE = config["cluster_estimation"]["random_state"]

COMMUNICATIONS_TIMEOUT = config["communications"]["timeout"]
Expand Down Expand Up @@ -327,7 +328,12 @@ def main() -> int:
result, cluster_estimation_worker_properties = worker_manager.WorkerProperties.create(
count=1,
target=cluster_estimation_worker.cluster_estimation_worker,
work_arguments=(MIN_ACTIVATION_THRESHOLD, MIN_NEW_POINTS_TO_RUN, RANDOM_STATE),
work_arguments=(
MIN_ACTIVATION_THRESHOLD,
MIN_NEW_POINTS_TO_RUN,
MAX_NUM_COMPONENTS,
RANDOM_STATE,
),
input_queues=[geolocation_to_cluster_estimation_queue],
output_queues=[cluster_estimation_to_communications_queue],
controller=controller,
Expand Down
49 changes: 30 additions & 19 deletions modules/cluster_estimation/cluster_estimation.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,6 @@ class ClusterEstimation:
works by predicting 'cluster centres' from groups of closely placed landing pad
detections.
ATTRIBUTES
----------
min_activation_threshold: int
Minimum total data points before model runs.
min_new_points_to_run: int
Minimum number of new data points that must be collected before running model.
random_state: int
Seed for randomizer, to get consistent results.
METHODS
-------
run()
Expand Down Expand Up @@ -62,9 +51,6 @@ class ClusterEstimation:
__MEAN_PRECISION_PRIOR = 1e-6
__MAX_MODEL_ITERATIONS = 1000

# Real-world scenario Hyperparameters
__MAX_NUM_COMPONENTS = 10 # assumed maximum number of real landing pads

# Hyperparameters to clean up model outputs
__WEIGHT_DROP_THRESHOLD = 0.1
__MAX_COVARIANCE_THRESHOLD = 10
Expand All @@ -74,24 +60,48 @@ def create(
cls,
min_activation_threshold: int,
min_new_points_to_run: int,
max_num_components: int,
random_state: int,
local_logger: logger.Logger,
) -> "tuple[bool, ClusterEstimation | None]":
"""
Data requirement conditions for estimation model to run.
PARAMETERS:
min_activation_threshold: int
Minimum total data points before model runs. Must be at least max_num_components.
min_new_points_to_run: int
Minimum number of new data points that must be collected before running model. Must be at least 0.
max_num_components: int
Max number of real landing pads. Must be at least 1.
random_state: int
Seed for randomizer, to get consistent results. Must be at least 0.
local_logger: logger.Logger
The local logger to log this object's information.
RETURNS: The ClusterEstimation object if all conditions pass, otherwise False, None
"""
# These parameters must be positive
if min_new_points_to_run < 0 or random_state < 0:
if min_activation_threshold < max_num_components:
return False, None

if min_new_points_to_run < 0:
return False, None

if max_num_components < 1:
return False, None

# At least 1 point for model to fit
if min_activation_threshold < 1:
if random_state < 0:
return False, None

return True, ClusterEstimation(
cls.__create_key,
min_activation_threshold,
min_new_points_to_run,
max_num_components,
random_state,
local_logger,
)
Expand All @@ -101,6 +111,7 @@ def __init__(
class_private_create_key: object,
min_activation_threshold: int,
min_new_points_to_run: int,
max_num_components: int,
random_state: int,
local_logger: logger.Logger,
) -> None:
Expand All @@ -112,7 +123,7 @@ def __init__(
# Initializes VGMM
self.__vgmm = sklearn.mixture.BayesianGaussianMixture(
covariance_type=self.__COVAR_TYPE,
n_components=self.__MAX_NUM_COMPONENTS,
n_components=max_num_components,
init_params=self.__MODEL_INIT_PARAM,
weight_concentration_prior=self.__WEIGHT_CONCENTRATION_PRIOR,
mean_precision_prior=self.__MEAN_PRECISION_PRIOR,
Expand Down
5 changes: 5 additions & 0 deletions modules/cluster_estimation/cluster_estimation_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
def cluster_estimation_worker(
min_activation_threshold: int,
min_new_points_to_run: int,
max_num_components: int,
random_state: int,
input_queue: queue_proxy_wrapper.QueueProxyWrapper,
output_queue: queue_proxy_wrapper.QueueProxyWrapper,
Expand All @@ -31,6 +32,9 @@ def cluster_estimation_worker(
min_new_points_to_run: int
Minimum number of new data points that must be collected before running model.
max_num_components: int
Max number of real landing pads.
random_state: int
Seed for randomizer, to get consistent results.
Expand All @@ -57,6 +61,7 @@ def cluster_estimation_worker(
result, estimator = cluster_estimation.ClusterEstimation.create(
min_activation_threshold,
min_new_points_to_run,
max_num_components,
random_state,
local_logger,
)
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
3 changes: 2 additions & 1 deletion tests/unit/test_cluster_detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@

MIN_TOTAL_POINTS_THRESHOLD = 100
MIN_NEW_POINTS_TO_RUN = 10
MAX_NUM_COMPONENTS = 10
RNG_SEED = 0
CENTRE_BOX_SIZE = 500


# Test functions use test fixture signature names and access class privates
# No enable
# pylint: disable=protected-access,redefined-outer-name
Expand All @@ -34,6 +34,7 @@ def cluster_model() -> cluster_estimation.ClusterEstimation: # type: ignore
result, model = cluster_estimation.ClusterEstimation.create(
MIN_TOTAL_POINTS_THRESHOLD,
MIN_NEW_POINTS_TO_RUN,
MAX_NUM_COMPONENTS,
RNG_SEED,
test_logger,
)
Expand Down
Loading

0 comments on commit 543219d

Please sign in to comment.