From ebc6de355703960af74d83f553aa227ee1e8d51c Mon Sep 17 00:00:00 2001 From: Diego Freitas Date: Tue, 12 May 2026 19:28:24 -0300 Subject: [PATCH] =?UTF-8?q?ajustes=20nas=20regras=20de=20controle=20radiom?= =?UTF-8?q?=C3=A9trico?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Python/OAK/datasets/oak-fcc-3/_0_capture.py | 1 + .../oak-fcc-3/calibration/module_params.json | 368 +++++++---- .../calibration/radiometric_config.json | 570 ++++++++++++------ .../oak-fcc-3/core/radiometric_controller.py | 116 +++- 4 files changed, 745 insertions(+), 310 deletions(-) diff --git a/Python/OAK/datasets/oak-fcc-3/_0_capture.py b/Python/OAK/datasets/oak-fcc-3/_0_capture.py index 9ac55c75d..ae9c5ce21 100644 --- a/Python/OAK/datasets/oak-fcc-3/_0_capture.py +++ b/Python/OAK/datasets/oak-fcc-3/_0_capture.py @@ -234,6 +234,7 @@ def main(): packed_by_camera = frame preview_bgr, raw3_preview, preview_source_id = cam.build_preview_from_raw_payload(frame=frame, meta=meta) + preview_bgr = cv2.cvtColor(preview_bgr, cv2.COLOR_RGB2BGR) if beauty_preview: rgb_preview = None diff --git a/Python/OAK/datasets/oak-fcc-3/calibration/module_params.json b/Python/OAK/datasets/oak-fcc-3/calibration/module_params.json index b9bf368a5..c807ba816 100644 --- a/Python/OAK/datasets/oak-fcc-3/calibration/module_params.json +++ b/Python/OAK/datasets/oak-fcc-3/calibration/module_params.json @@ -1,6 +1,6 @@ { "schema": "multispec_module_params_v3", - "saved_at": "2026-05-12 10:07:11", + "saved_at": "2026-05-12 14:20:13", "frame_type": "RAW_BRUTO", "capture_mode_requested": "AUTO", "capture_mode_effective": "AUTO", @@ -98,9 +98,9 @@ "spectral_control_mode": "shared", "control_metric": "p50", "target_value": 0.5, - "deadband": 0.035, - "p95_limit": 0.94, - "saturation_limit_pct": 0.5, + "deadband": 0.055, + "p95_limit": 0.975, + "saturation_limit_pct": 5.0, "alpha": 0.18, "exp_step_gain": 0.55, "prefer_exposure": true, @@ -118,30 +118,30 @@ "nir" ], "roi_pct": { - "x0": 0.304688, - "y0": 0.8275, - "x1": 0.364063, - "y1": 0.9875 + "x0": 0.26875, + "y0": 0.8175, + "x1": 0.328906, + "y1": 0.985 }, "target_value": 0.08, "weight": 0.7, "roi_pct_by_role": { "rgb": { - "x0": 0.304688, - "y0": 0.8275, - "x1": 0.364063, - "y1": 0.9875 + "x0": 0.26875, + "y0": 0.8175, + "x1": 0.328906, + "y1": 0.985 }, "re": { - "x0": 0.275, - "y0": 0.8225, - "x1": 0.334375, - "y1": 0.995 + "x0": 0.235156, + "y0": 0.8175, + "x1": 0.289062, + "y1": 0.985 }, "nir": { - "x0": 0.3375, - "y0": 0.8325, - "x1": 0.4, + "x0": 0.3, + "y0": 0.83125, + "x1": 0.360938, "y1": 0.9925 } }, @@ -151,13 +151,25 @@ "name": "rgb_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.304688, - "y0": 0.8275, - "x1": 0.364063, - "y1": 0.9875 + "x0": 0.26875, + "y0": 0.8175, + "x1": 0.328906, + "y1": 0.985 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:53:26" + "updated_at": "2026-05-12 14:16:15" + }, + { + "name": "black_rgb_02", + "enabled": true, + "roi_pct": { + "x0": 0.813281, + "y0": 0.8275, + "x1": 0.873437, + "y1": 0.9875 + }, + "created_at": "2026-05-12 14:16:20", + "updated_at": "2026-05-12 14:16:32" } ], "re": [ @@ -165,13 +177,25 @@ "name": "re_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.275, - "y0": 0.8225, - "x1": 0.334375, - "y1": 0.995 + "x0": 0.235156, + "y0": 0.8175, + "x1": 0.289062, + "y1": 0.985 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:54:15" + "updated_at": "2026-05-12 14:17:39" + }, + { + "name": "black_re_02", + "enabled": true, + "roi_pct": { + "x0": 0.79375, + "y0": 0.83, + "x1": 0.85625, + "y1": 0.99125 + }, + "created_at": "2026-05-12 14:17:42", + "updated_at": "2026-05-12 14:17:49" } ], "nir": [ @@ -179,13 +203,25 @@ "name": "nir_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.3375, - "y0": 0.8325, - "x1": 0.4, + "x0": 0.3, + "y0": 0.83125, + "x1": 0.360938, "y1": 0.9925 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:54:44" + "updated_at": "2026-05-12 14:19:03" + }, + { + "name": "black_nir_02", + "enabled": true, + "roi_pct": { + "x0": 0.851562, + "y0": 0.82, + "x1": 0.910156, + "y1": 0.97625 + }, + "created_at": "2026-05-12 14:19:04", + "updated_at": "2026-05-12 14:19:16" } ] } @@ -199,36 +235,36 @@ "nir" ], "roi_pct": { - "x0": 0.238281, + "x0": 0.198437, "y0": 0.82625, - "x1": 0.298438, - "y1": 0.9875 + "x1": 0.257812, + "y1": 0.985 }, "target_value": 0.35, "target_value_by_role": { - "rgb": 0.34, - "re": 0.24, - "nir": 0.3 + "rgb": 0.285, + "re": 0.22, + "nir": 0.27 }, "weight": 1.0, "roi_pct_by_role": { "rgb": { - "x0": 0.238281, + "x0": 0.198437, "y0": 0.82625, - "x1": 0.298438, - "y1": 0.9875 + "x1": 0.257812, + "y1": 0.985 }, "re": { - "x0": 0.203125, - "y0": 0.82625, - "x1": 0.266406, - "y1": 0.995 + "x0": 0.163281, + "y0": 0.8175, + "x1": 0.221875, + "y1": 0.98625 }, "nir": { - "x0": 0.266406, - "y0": 0.83125, - "x1": 0.332031, - "y1": 0.99625 + "x0": 0.228906, + "y0": 0.8325, + "x1": 0.290625, + "y1": 0.99125 } }, "roi_list_by_role": { @@ -237,13 +273,25 @@ "name": "rgb_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.238281, + "x0": 0.198437, "y0": 0.82625, - "x1": 0.298438, - "y1": 0.9875 + "x1": 0.257812, + "y1": 0.985 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:53:18" + "updated_at": "2026-05-12 14:16:46" + }, + { + "name": "gray_rgb_02", + "enabled": true, + "roi_pct": { + "x0": 0.744531, + "y0": 0.8275, + "x1": 0.804688, + "y1": 0.98625 + }, + "created_at": "2026-05-12 14:16:48", + "updated_at": "2026-05-12 14:16:59" } ], "re": [ @@ -251,13 +299,25 @@ "name": "re_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.203125, - "y0": 0.82625, - "x1": 0.266406, - "y1": 0.995 + "x0": 0.163281, + "y0": 0.8175, + "x1": 0.221875, + "y1": 0.98625 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:53:55" + "updated_at": "2026-05-12 14:18:03" + }, + { + "name": "gray_re_02", + "enabled": true, + "roi_pct": { + "x0": 0.722656, + "y0": 0.83, + "x1": 0.7875, + "y1": 0.99125 + }, + "created_at": "2026-05-12 14:18:05", + "updated_at": "2026-05-12 14:18:15" } ], "nir": [ @@ -265,13 +325,25 @@ "name": "nir_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.266406, - "y0": 0.83125, - "x1": 0.332031, - "y1": 0.99625 + "x0": 0.228906, + "y0": 0.8325, + "x1": 0.290625, + "y1": 0.99125 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:54:33" + "updated_at": "2026-05-12 14:19:24" + }, + { + "name": "gray_nir_02", + "enabled": true, + "roi_pct": { + "x0": 0.782031, + "y0": 0.8225, + "x1": 0.84375, + "y1": 0.98 + }, + "created_at": "2026-05-12 14:19:25", + "updated_at": "2026-05-12 14:19:30" } ] } @@ -285,31 +357,31 @@ "nir" ], "roi_pct": { - "x0": 0.166406, - "y0": 0.82625, - "x1": 0.228906, - "y1": 0.99125 + "x0": 0.126562, + "y0": 0.8225, + "x1": 0.189062, + "y1": 0.9825 }, "target_value": 0.82, "weight": 0.8, "roi_pct_by_role": { "rgb": { - "x0": 0.166406, - "y0": 0.82625, - "x1": 0.228906, - "y1": 0.99125 + "x0": 0.126562, + "y0": 0.8225, + "x1": 0.189062, + "y1": 0.9825 }, "re": { - "x0": 0.132812, - "y0": 0.82625, - "x1": 0.194531, - "y1": 0.995 + "x0": 0.090625, + "y0": 0.8175, + "x1": 0.148438, + "y1": 0.985 }, "nir": { - "x0": 0.195312, - "y0": 0.83625, - "x1": 0.260156, - "y1": 0.99125 + "x0": 0.154688, + "y0": 0.83125, + "x1": 0.21875, + "y1": 0.99625 } }, "roi_list_by_role": { @@ -318,13 +390,25 @@ "name": "rgb_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.166406, - "y0": 0.82625, - "x1": 0.228906, - "y1": 0.99125 + "x0": 0.126562, + "y0": 0.8225, + "x1": 0.189062, + "y1": 0.9825 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:53:36" + "updated_at": "2026-05-12 14:17:12" + }, + { + "name": "white_rgb_02", + "enabled": true, + "roi_pct": { + "x0": 0.675, + "y0": 0.83, + "x1": 0.735156, + "y1": 0.985 + }, + "created_at": "2026-05-12 14:17:13", + "updated_at": "2026-05-12 14:17:23" } ], "re": [ @@ -332,13 +416,25 @@ "name": "re_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.132812, - "y0": 0.82625, - "x1": 0.194531, - "y1": 0.995 + "x0": 0.090625, + "y0": 0.8175, + "x1": 0.148438, + "y1": 0.985 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:54:04" + "updated_at": "2026-05-12 14:18:29" + }, + { + "name": "white_re_02", + "enabled": true, + "roi_pct": { + "x0": 0.648438, + "y0": 0.83, + "x1": 0.714063, + "y1": 0.99125 + }, + "created_at": "2026-05-12 14:18:31", + "updated_at": "2026-05-12 14:18:45" } ], "nir": [ @@ -346,19 +442,31 @@ "name": "nir_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.195312, - "y0": 0.83625, - "x1": 0.260156, - "y1": 0.99125 + "x0": 0.154688, + "y0": 0.83125, + "x1": 0.21875, + "y1": 0.99625 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:54:56" + "updated_at": "2026-05-12 14:19:45" + }, + { + "name": "white_nir_02", + "enabled": true, + "roi_pct": { + "x0": 0.713281, + "y0": 0.825, + "x1": 0.775, + "y1": 0.98125 + }, + "created_at": "2026-05-12 14:19:46", + "updated_at": "2026-05-12 14:19:54" } ] } } ], - "exp_apply_threshold_us": 80, + "exp_apply_threshold_us": 15, "gain_apply_threshold": 0.05, "apply_same_spectral_to_both": true, "spectral_roles": [ @@ -367,17 +475,17 @@ ], "dark_limit_pct": 35.0, "control_strategy": "ratio", - "ratio_alpha": 0.35, - "ratio_min": 0.65, - "ratio_max": 1.35, + "ratio_alpha": 0.42, + "ratio_min": 0.72, + "ratio_max": 1.38, "reduce_fast_factor": 0.8, - "factor_min": 0.55, - "factor_max": 1.28, + "factor_min": 0.62, + "factor_max": 1.42, "gain_return_enabled": true, "gain_reduce_on_saturation": true, - "gain_increase_required_cycles": 5, - "gain_decrease_required_cycles": 2, - "gain_step_up": 0.2, + "gain_increase_required_cycles": 3, + "gain_decrease_required_cycles": 1, + "gain_step_up": 0.3, "gain_step_down": 0.5, "gain_hard_reset_on_saturation": false, "exp_high_ratio_for_gain": 0.95, @@ -391,13 +499,13 @@ }, "re": { "exp_min_us": 100, - "exp_max_us": 2500, + "exp_max_us": 3500, "gain_min": 1.0, "gain_max": 2.0 }, "nir": { "exp_min_us": 100, - "exp_max_us": 3000, + "exp_max_us": 3500, "gain_min": 1.0, "gain_max": 2.0 } @@ -406,8 +514,8 @@ "patch_control_mode": "gray_primary", "patch_require_order": true, "patch_min_separation": 0.08, - "patch_white_sat_limit_pct": 0.5, - "patch_white_p95_limit": 0.94, + "patch_white_sat_limit_pct": 5.0, + "patch_white_p95_limit": 0.985, "patch_black_dark_limit_pct": 80.0, "patch_black_max_p50": 0.2, "patch_gray_min_p50": 0.08, @@ -421,36 +529,42 @@ "x0": 0.05, "y0": 0.05, "x1": 0.95, - "y1": 0.95 + "y1": 0.76 }, "global_guard_sat_threshold": 0.985, "global_guard_near_sat_threshold": 0.94, - "global_guard_sat_pct_soft": 0.05, - "global_guard_sat_pct_hard": 0.2, - "global_guard_sat_pct_extreme": 0.8, - "global_guard_blob_pct_soft": 0.015, - "global_guard_blob_pct_hard": 0.08, - "global_guard_blob_pct_extreme": 0.25, + "global_guard_sat_pct_soft": 0.50, + "global_guard_sat_pct_hard": 1.5, + "global_guard_sat_pct_extreme": 5.0, + "global_guard_blob_pct_soft": 0.20, + "global_guard_blob_pct_hard": 0.80, + "global_guard_blob_pct_extreme": 2.2, "global_guard_min_blob_px": 48, "global_guard_downsample_max_side": 320, - "global_guard_reduce_factor_soft": 0.82, - "global_guard_reduce_factor_hard": 0.6, - "global_guard_reduce_factor_extreme": 0.35, + "global_guard_reduce_factor_soft": 0.96, + "global_guard_reduce_factor_hard": 0.82, + "global_guard_reduce_factor_extreme": 0.62, "sun_guard_enabled": true, - "sun_guard_p99_threshold": 0.9, - "sun_guard_near_sat_pct_threshold": 0.8, - "sun_guard_freeze_increase_cycles": 2, + "sun_guard_p99_threshold": 0.96, + "sun_guard_near_sat_pct_threshold": 2.0, + "sun_guard_freeze_increase_cycles": 1, "sun_guard_allow_decrease": true, "guard_force_apply_enabled": true, - "guard_force_apply_soft": true, + "guard_force_apply_soft": false, "guard_force_apply_hard": true, "guard_force_apply_extreme": true, "guard_force_apply_on_patch_saturation": true, - "guard_freeze_cycles_soft": 3, - "guard_freeze_cycles_hard": 5, - "guard_freeze_cycles_extreme": 8, + "guard_freeze_cycles_soft": 1, + "guard_freeze_cycles_hard": 2, + "guard_freeze_cycles_extreme": 3, "guard_reapply_min_exp_on_emergency": true, - "guard_min_exp_margin_us": 80 + "guard_min_exp_margin_us": 80, + "patch_two_roi_soften_risk": true, + "patch_two_roi_white_risk_percentile": 75, + "patch_two_roi_other_risk_percentile": 50, + "patch_white_single_roi_saturation_reject": true, + "patch_white_roi_reject_sat_pct": 5.0, + "patch_white_roi_reject_p95": 0.995 }, "radiometric_normalization": { "enabled": false, @@ -492,7 +606,7 @@ "save_patch_stats": true }, "rgb_calibration": { - "enabled": true, + "enabled": false, "gains": { "R": 1.2500000000000002, "G": 1.0, diff --git a/Python/OAK/datasets/oak-fcc-3/calibration/radiometric_config.json b/Python/OAK/datasets/oak-fcc-3/calibration/radiometric_config.json index 3ef0797ef..0ee5e0333 100644 --- a/Python/OAK/datasets/oak-fcc-3/calibration/radiometric_config.json +++ b/Python/OAK/datasets/oak-fcc-3/calibration/radiometric_config.json @@ -1,6 +1,6 @@ { "schema": "multispec_radiometric_config_profiles_v4", - "saved_at": "2026-05-12 09:55:04", + "saved_at": "2026-05-12 14:20:05", "active_profile": "three_reference_patches_mode", "global_scene_mode": { "radiometric_config": { @@ -158,30 +158,30 @@ "nir" ], "roi_pct": { - "x0": 0.304688, - "y0": 0.8275, - "x1": 0.364063, - "y1": 0.9875 + "x0": 0.26875, + "y0": 0.8175, + "x1": 0.328906, + "y1": 0.985 }, "target_value": 0.08, "weight": 0.7, "roi_pct_by_role": { "rgb": { - "x0": 0.304688, - "y0": 0.8275, - "x1": 0.364063, - "y1": 0.9875 + "x0": 0.26875, + "y0": 0.8175, + "x1": 0.328906, + "y1": 0.985 }, "re": { - "x0": 0.275, - "y0": 0.8225, - "x1": 0.334375, - "y1": 0.995 + "x0": 0.235156, + "y0": 0.8175, + "x1": 0.289062, + "y1": 0.985 }, "nir": { - "x0": 0.3375, - "y0": 0.8325, - "x1": 0.4, + "x0": 0.3, + "y0": 0.83125, + "x1": 0.360938, "y1": 0.9925 } }, @@ -191,13 +191,25 @@ "name": "rgb_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.304688, - "y0": 0.8275, - "x1": 0.364063, - "y1": 0.9875 + "x0": 0.26875, + "y0": 0.8175, + "x1": 0.328906, + "y1": 0.985 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:53:26" + "updated_at": "2026-05-12 14:16:15" + }, + { + "name": "black_rgb_02", + "enabled": true, + "roi_pct": { + "x0": 0.813281, + "y0": 0.8275, + "x1": 0.873437, + "y1": 0.9875 + }, + "created_at": "2026-05-12 14:16:20", + "updated_at": "2026-05-12 14:16:32" } ], "re": [ @@ -205,13 +217,25 @@ "name": "re_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.275, - "y0": 0.8225, - "x1": 0.334375, - "y1": 0.995 + "x0": 0.235156, + "y0": 0.8175, + "x1": 0.289062, + "y1": 0.985 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:54:15" + "updated_at": "2026-05-12 14:17:39" + }, + { + "name": "black_re_02", + "enabled": true, + "roi_pct": { + "x0": 0.79375, + "y0": 0.83, + "x1": 0.85625, + "y1": 0.99125 + }, + "created_at": "2026-05-12 14:17:42", + "updated_at": "2026-05-12 14:17:49" } ], "nir": [ @@ -219,13 +243,25 @@ "name": "nir_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.3375, - "y0": 0.8325, - "x1": 0.4, + "x0": 0.3, + "y0": 0.83125, + "x1": 0.360938, "y1": 0.9925 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:54:44" + "updated_at": "2026-05-12 14:19:03" + }, + { + "name": "black_nir_02", + "enabled": true, + "roi_pct": { + "x0": 0.851562, + "y0": 0.82, + "x1": 0.910156, + "y1": 0.97625 + }, + "created_at": "2026-05-12 14:19:04", + "updated_at": "2026-05-12 14:19:16" } ] } @@ -239,10 +275,10 @@ "nir" ], "roi_pct": { - "x0": 0.238281, + "x0": 0.198437, "y0": 0.82625, - "x1": 0.298438, - "y1": 0.9875 + "x1": 0.257812, + "y1": 0.985 }, "target_value": 0.35, "target_value_by_role": { @@ -253,22 +289,22 @@ "weight": 1.0, "roi_pct_by_role": { "rgb": { - "x0": 0.238281, + "x0": 0.198437, "y0": 0.82625, - "x1": 0.298438, - "y1": 0.9875 + "x1": 0.257812, + "y1": 0.985 }, "re": { - "x0": 0.203125, - "y0": 0.82625, - "x1": 0.266406, - "y1": 0.995 + "x0": 0.163281, + "y0": 0.8175, + "x1": 0.221875, + "y1": 0.98625 }, "nir": { - "x0": 0.266406, - "y0": 0.83125, - "x1": 0.332031, - "y1": 0.99625 + "x0": 0.228906, + "y0": 0.8325, + "x1": 0.290625, + "y1": 0.99125 } }, "roi_list_by_role": { @@ -277,13 +313,25 @@ "name": "rgb_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.238281, + "x0": 0.198437, "y0": 0.82625, - "x1": 0.298438, - "y1": 0.9875 + "x1": 0.257812, + "y1": 0.985 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:53:18" + "updated_at": "2026-05-12 14:16:46" + }, + { + "name": "gray_rgb_02", + "enabled": true, + "roi_pct": { + "x0": 0.744531, + "y0": 0.8275, + "x1": 0.804688, + "y1": 0.98625 + }, + "created_at": "2026-05-12 14:16:48", + "updated_at": "2026-05-12 14:16:59" } ], "re": [ @@ -291,13 +339,25 @@ "name": "re_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.203125, - "y0": 0.82625, - "x1": 0.266406, - "y1": 0.995 + "x0": 0.163281, + "y0": 0.8175, + "x1": 0.221875, + "y1": 0.98625 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:53:55" + "updated_at": "2026-05-12 14:18:03" + }, + { + "name": "gray_re_02", + "enabled": true, + "roi_pct": { + "x0": 0.722656, + "y0": 0.83, + "x1": 0.7875, + "y1": 0.99125 + }, + "created_at": "2026-05-12 14:18:05", + "updated_at": "2026-05-12 14:18:15" } ], "nir": [ @@ -305,13 +365,25 @@ "name": "nir_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.266406, - "y0": 0.83125, - "x1": 0.332031, - "y1": 0.99625 + "x0": 0.228906, + "y0": 0.8325, + "x1": 0.290625, + "y1": 0.99125 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:54:33" + "updated_at": "2026-05-12 14:19:24" + }, + { + "name": "gray_nir_02", + "enabled": true, + "roi_pct": { + "x0": 0.782031, + "y0": 0.8225, + "x1": 0.84375, + "y1": 0.98 + }, + "created_at": "2026-05-12 14:19:25", + "updated_at": "2026-05-12 14:19:30" } ] } @@ -325,31 +397,31 @@ "nir" ], "roi_pct": { - "x0": 0.166406, - "y0": 0.82625, - "x1": 0.228906, - "y1": 0.99125 + "x0": 0.126562, + "y0": 0.8225, + "x1": 0.189062, + "y1": 0.9825 }, "target_value": 0.82, "weight": 0.8, "roi_pct_by_role": { "rgb": { - "x0": 0.166406, - "y0": 0.82625, - "x1": 0.228906, - "y1": 0.99125 + "x0": 0.126562, + "y0": 0.8225, + "x1": 0.189062, + "y1": 0.9825 }, "re": { - "x0": 0.132812, - "y0": 0.82625, - "x1": 0.194531, - "y1": 0.995 + "x0": 0.090625, + "y0": 0.8175, + "x1": 0.148438, + "y1": 0.985 }, "nir": { - "x0": 0.195312, - "y0": 0.83625, - "x1": 0.260156, - "y1": 0.99125 + "x0": 0.154688, + "y0": 0.83125, + "x1": 0.21875, + "y1": 0.99625 } }, "roi_list_by_role": { @@ -358,13 +430,25 @@ "name": "rgb_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.166406, - "y0": 0.82625, - "x1": 0.228906, - "y1": 0.99125 + "x0": 0.126562, + "y0": 0.8225, + "x1": 0.189062, + "y1": 0.9825 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:53:36" + "updated_at": "2026-05-12 14:17:12" + }, + { + "name": "white_rgb_02", + "enabled": true, + "roi_pct": { + "x0": 0.675, + "y0": 0.83, + "x1": 0.735156, + "y1": 0.985 + }, + "created_at": "2026-05-12 14:17:13", + "updated_at": "2026-05-12 14:17:23" } ], "re": [ @@ -372,13 +456,25 @@ "name": "re_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.132812, - "y0": 0.82625, - "x1": 0.194531, - "y1": 0.995 + "x0": 0.090625, + "y0": 0.8175, + "x1": 0.148438, + "y1": 0.985 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:54:04" + "updated_at": "2026-05-12 14:18:29" + }, + { + "name": "white_re_02", + "enabled": true, + "roi_pct": { + "x0": 0.648438, + "y0": 0.83, + "x1": 0.714063, + "y1": 0.99125 + }, + "created_at": "2026-05-12 14:18:31", + "updated_at": "2026-05-12 14:18:45" } ], "nir": [ @@ -386,13 +482,25 @@ "name": "nir_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.195312, - "y0": 0.83625, - "x1": 0.260156, - "y1": 0.99125 + "x0": 0.154688, + "y0": 0.83125, + "x1": 0.21875, + "y1": 0.99625 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:54:56" + "updated_at": "2026-05-12 14:19:45" + }, + { + "name": "white_nir_02", + "enabled": true, + "roi_pct": { + "x0": 0.713281, + "y0": 0.825, + "x1": 0.775, + "y1": 0.98125 + }, + "created_at": "2026-05-12 14:19:46", + "updated_at": "2026-05-12 14:19:54" } ] } @@ -540,30 +648,30 @@ "nir" ], "roi_pct": { - "x0": 0.304688, - "y0": 0.8275, - "x1": 0.364063, - "y1": 0.9875 + "x0": 0.26875, + "y0": 0.8175, + "x1": 0.328906, + "y1": 0.985 }, "target_value": 0.08, "weight": 0.7, "roi_pct_by_role": { "rgb": { - "x0": 0.304688, - "y0": 0.8275, - "x1": 0.364063, - "y1": 0.9875 + "x0": 0.26875, + "y0": 0.8175, + "x1": 0.328906, + "y1": 0.985 }, "re": { - "x0": 0.275, - "y0": 0.8225, - "x1": 0.334375, - "y1": 0.995 + "x0": 0.235156, + "y0": 0.8175, + "x1": 0.289062, + "y1": 0.985 }, "nir": { - "x0": 0.3375, - "y0": 0.8325, - "x1": 0.4, + "x0": 0.3, + "y0": 0.83125, + "x1": 0.360938, "y1": 0.9925 } }, @@ -573,13 +681,25 @@ "name": "rgb_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.304688, - "y0": 0.8275, - "x1": 0.364063, - "y1": 0.9875 + "x0": 0.26875, + "y0": 0.8175, + "x1": 0.328906, + "y1": 0.985 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:53:26" + "updated_at": "2026-05-12 14:16:15" + }, + { + "name": "black_rgb_02", + "enabled": true, + "roi_pct": { + "x0": 0.813281, + "y0": 0.8275, + "x1": 0.873437, + "y1": 0.9875 + }, + "created_at": "2026-05-12 14:16:20", + "updated_at": "2026-05-12 14:16:32" } ], "re": [ @@ -587,13 +707,25 @@ "name": "re_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.275, - "y0": 0.8225, - "x1": 0.334375, - "y1": 0.995 + "x0": 0.235156, + "y0": 0.8175, + "x1": 0.289062, + "y1": 0.985 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:54:15" + "updated_at": "2026-05-12 14:17:39" + }, + { + "name": "black_re_02", + "enabled": true, + "roi_pct": { + "x0": 0.79375, + "y0": 0.83, + "x1": 0.85625, + "y1": 0.99125 + }, + "created_at": "2026-05-12 14:17:42", + "updated_at": "2026-05-12 14:17:49" } ], "nir": [ @@ -601,13 +733,25 @@ "name": "nir_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.3375, - "y0": 0.8325, - "x1": 0.4, + "x0": 0.3, + "y0": 0.83125, + "x1": 0.360938, "y1": 0.9925 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:54:44" + "updated_at": "2026-05-12 14:19:03" + }, + { + "name": "black_nir_02", + "enabled": true, + "roi_pct": { + "x0": 0.851562, + "y0": 0.82, + "x1": 0.910156, + "y1": 0.97625 + }, + "created_at": "2026-05-12 14:19:04", + "updated_at": "2026-05-12 14:19:16" } ] } @@ -621,10 +765,10 @@ "nir" ], "roi_pct": { - "x0": 0.238281, + "x0": 0.198437, "y0": 0.82625, - "x1": 0.298438, - "y1": 0.9875 + "x1": 0.257812, + "y1": 0.985 }, "target_value": 0.35, "target_value_by_role": { @@ -635,22 +779,22 @@ "weight": 1.0, "roi_pct_by_role": { "rgb": { - "x0": 0.238281, + "x0": 0.198437, "y0": 0.82625, - "x1": 0.298438, - "y1": 0.9875 + "x1": 0.257812, + "y1": 0.985 }, "re": { - "x0": 0.203125, - "y0": 0.82625, - "x1": 0.266406, - "y1": 0.995 + "x0": 0.163281, + "y0": 0.8175, + "x1": 0.221875, + "y1": 0.98625 }, "nir": { - "x0": 0.266406, - "y0": 0.83125, - "x1": 0.332031, - "y1": 0.99625 + "x0": 0.228906, + "y0": 0.8325, + "x1": 0.290625, + "y1": 0.99125 } }, "roi_list_by_role": { @@ -659,13 +803,25 @@ "name": "rgb_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.238281, + "x0": 0.198437, "y0": 0.82625, - "x1": 0.298438, - "y1": 0.9875 + "x1": 0.257812, + "y1": 0.985 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:53:18" + "updated_at": "2026-05-12 14:16:46" + }, + { + "name": "gray_rgb_02", + "enabled": true, + "roi_pct": { + "x0": 0.744531, + "y0": 0.8275, + "x1": 0.804688, + "y1": 0.98625 + }, + "created_at": "2026-05-12 14:16:48", + "updated_at": "2026-05-12 14:16:59" } ], "re": [ @@ -673,13 +829,25 @@ "name": "re_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.203125, - "y0": 0.82625, - "x1": 0.266406, - "y1": 0.995 + "x0": 0.163281, + "y0": 0.8175, + "x1": 0.221875, + "y1": 0.98625 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:53:55" + "updated_at": "2026-05-12 14:18:03" + }, + { + "name": "gray_re_02", + "enabled": true, + "roi_pct": { + "x0": 0.722656, + "y0": 0.83, + "x1": 0.7875, + "y1": 0.99125 + }, + "created_at": "2026-05-12 14:18:05", + "updated_at": "2026-05-12 14:18:15" } ], "nir": [ @@ -687,13 +855,25 @@ "name": "nir_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.266406, - "y0": 0.83125, - "x1": 0.332031, - "y1": 0.99625 + "x0": 0.228906, + "y0": 0.8325, + "x1": 0.290625, + "y1": 0.99125 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:54:33" + "updated_at": "2026-05-12 14:19:24" + }, + { + "name": "gray_nir_02", + "enabled": true, + "roi_pct": { + "x0": 0.782031, + "y0": 0.8225, + "x1": 0.84375, + "y1": 0.98 + }, + "created_at": "2026-05-12 14:19:25", + "updated_at": "2026-05-12 14:19:30" } ] } @@ -707,31 +887,31 @@ "nir" ], "roi_pct": { - "x0": 0.166406, - "y0": 0.82625, - "x1": 0.228906, - "y1": 0.99125 + "x0": 0.126562, + "y0": 0.8225, + "x1": 0.189062, + "y1": 0.9825 }, "target_value": 0.82, "weight": 0.8, "roi_pct_by_role": { "rgb": { - "x0": 0.166406, - "y0": 0.82625, - "x1": 0.228906, - "y1": 0.99125 + "x0": 0.126562, + "y0": 0.8225, + "x1": 0.189062, + "y1": 0.9825 }, "re": { - "x0": 0.132812, - "y0": 0.82625, - "x1": 0.194531, - "y1": 0.995 + "x0": 0.090625, + "y0": 0.8175, + "x1": 0.148438, + "y1": 0.985 }, "nir": { - "x0": 0.195312, - "y0": 0.83625, - "x1": 0.260156, - "y1": 0.99125 + "x0": 0.154688, + "y0": 0.83125, + "x1": 0.21875, + "y1": 0.99625 } }, "roi_list_by_role": { @@ -740,13 +920,25 @@ "name": "rgb_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.166406, - "y0": 0.82625, - "x1": 0.228906, - "y1": 0.99125 + "x0": 0.126562, + "y0": 0.8225, + "x1": 0.189062, + "y1": 0.9825 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:53:36" + "updated_at": "2026-05-12 14:17:12" + }, + { + "name": "white_rgb_02", + "enabled": true, + "roi_pct": { + "x0": 0.675, + "y0": 0.83, + "x1": 0.735156, + "y1": 0.985 + }, + "created_at": "2026-05-12 14:17:13", + "updated_at": "2026-05-12 14:17:23" } ], "re": [ @@ -754,13 +946,25 @@ "name": "re_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.132812, - "y0": 0.82625, - "x1": 0.194531, - "y1": 0.995 + "x0": 0.090625, + "y0": 0.8175, + "x1": 0.148438, + "y1": 0.985 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:54:04" + "updated_at": "2026-05-12 14:18:29" + }, + { + "name": "white_re_02", + "enabled": true, + "roi_pct": { + "x0": 0.648438, + "y0": 0.83, + "x1": 0.714063, + "y1": 0.99125 + }, + "created_at": "2026-05-12 14:18:31", + "updated_at": "2026-05-12 14:18:45" } ], "nir": [ @@ -768,13 +972,25 @@ "name": "nir_legacy_01", "enabled": true, "roi_pct": { - "x0": 0.195312, - "y0": 0.83625, - "x1": 0.260156, - "y1": 0.99125 + "x0": 0.154688, + "y0": 0.83125, + "x1": 0.21875, + "y1": 0.99625 }, "created_at": "2026-05-07 14:36:25", - "updated_at": "2026-05-12 09:54:56" + "updated_at": "2026-05-12 14:19:45" + }, + { + "name": "white_nir_02", + "enabled": true, + "roi_pct": { + "x0": 0.713281, + "y0": 0.825, + "x1": 0.775, + "y1": 0.98125 + }, + "created_at": "2026-05-12 14:19:46", + "updated_at": "2026-05-12 14:19:54" } ] } diff --git a/Python/OAK/datasets/oak-fcc-3/core/radiometric_controller.py b/Python/OAK/datasets/oak-fcc-3/core/radiometric_controller.py index cb1b760cf..c9c363fa1 100644 --- a/Python/OAK/datasets/oak-fcc-3/core/radiometric_controller.py +++ b/Python/OAK/datasets/oak-fcc-3/core/radiometric_controller.py @@ -273,6 +273,13 @@ class RadiometricController: "re": {"exp": None, "gain": None}, } + self.patch_two_roi_soften_risk = bool(cfg.get("patch_two_roi_soften_risk", True)) + self.patch_two_roi_white_risk_percentile = float(cfg.get("patch_two_roi_white_risk_percentile", 75.0)) + self.patch_two_roi_other_risk_percentile = float(cfg.get("patch_two_roi_other_risk_percentile", 50.0)) + self.patch_white_single_roi_saturation_reject = bool(cfg.get("patch_white_single_roi_saturation_reject", True)) + self.patch_white_roi_reject_sat_pct = float(cfg.get("patch_white_roi_reject_sat_pct", 5.0)) + self.patch_white_roi_reject_p95 = float(cfg.get("patch_white_roi_reject_p95", 0.995)) + def _load_config_json(self, path): if not path: return {} @@ -796,18 +803,67 @@ class RadiometricController: if self.patch_roi_outlier_reject and len(valid) >= 3: kept = [] + for r in valid: p50 = float(r["stats"].get("p50", 0.0)) + if abs(p50 - median_p50) <= self.patch_roi_max_p50_delta: kept.append(r) else: rejected.append(r) + if kept: used = kept + if rejected: warnings.append(f"roi_outliers_rejected:{len(rejected)}") + elif self.patch_roi_outlier_reject and len(valid) == 2 and spread_p50 > self.patch_roi_max_p50_delta: + # Com apenas 2 ROIs não dá para saber qual é o outlier. + # Então não descartamos nenhuma. Usamos as duas, mas marcamos que + # existe divergência para a etapa de agregação suavizar p95/saturação. warnings.append(f"roi_p50_spread_high:{spread_p50:.3f}") + used = valid + + patch_type_norm = str(patch_type or "reference").lower() + + # ------------------------------------------------------------ + # Caso especial: branco com 2 ROIs + # ------------------------------------------------------------ + # Se apenas uma ROI branca saturou muito e a outra está limpa, + # tratamos a saturada como reflexo/ROI ruim naquele ciclo. + # Se as duas saturaram, mantém as duas e deixa o controller reduzir. + if ( + patch_type_norm == "white" + and self.patch_white_single_roi_saturation_reject + and len(used) == 2 + ): + clean_rois = [] + saturated_rois = [] + + for r in used: + st = r.get("stats", {}) or {} + roi_sat = float(st.get("sat_pct", 0.0)) + roi_p95 = float(st.get("p95", 0.0)) + + is_bad_white_roi = ( + roi_sat > self.patch_white_roi_reject_sat_pct + or roi_p95 >= self.patch_white_roi_reject_p95 + ) + + if is_bad_white_roi: + saturated_rois.append(r) + else: + clean_rois.append(r) + + # Só rejeita se exatamente uma saturou e existe uma ROI limpa. + # Se as duas saturaram, é saturação real do branco, então reduz exposição. + if len(saturated_rois) == 1 and len(clean_rois) == 1: + bad_name = str(saturated_rois[0].get("name", "unknown")) + warnings.append(f"white_single_saturated_roi_rejected:{bad_name}") + + rejected.extend(saturated_rois) + used = clean_rois if len(used) < self.patch_roi_min_valid_rois: warnings.append(f"valid_roi_count_low:{len(used)}<{self.patch_roi_min_valid_rois}") @@ -830,9 +886,39 @@ class RadiometricController: reducer = np.mean if reduce_method == "mean_valid_rois" else np.median - # Para brilho/controle usamos redução robusta; para guardas de risco, - # mantemos máximos de p95/saturação. Assim um cartão branco saturado - # ainda força redução de exposição. + # ------------------------------------------------------------ + # Agregação robusta de risco para múltiplas ROIs + # ------------------------------------------------------------ + # Para o valor de controle usamos redução robusta. + # Para risco de saturação, o código antigo usava sempre o máximo. + # Isso é seguro, mas com 2 cartões pode deixar uma única ROI mandar + # derrubar a exposição inteira. Então suavizamos quando há divergência. + two_roi_disagreement = ( + self.patch_two_roi_soften_risk + and self.patch_roi_outlier_reject + and len(valid) == 2 + and spread_p50 > self.patch_roi_max_p50_delta + ) + + patch_type_norm = str(patch_type or "reference").lower() + + if two_roi_disagreement: + if patch_type_norm == "white": + risk_percentile = self.patch_two_roi_white_risk_percentile + else: + risk_percentile = self.patch_two_roi_other_risk_percentile + + p95_agg = float(np.percentile(p95s, risk_percentile)) + sat_agg = float(np.percentile(sats, risk_percentile)) + + warnings.append( + f"roi_risk_softened_for_2_rois:{patch_type_norm}:p{risk_percentile:.0f}" + ) + else: + p95_agg = float(np.max(p95s)) + sat_agg = float(np.max(sats)) + + stats = { "valid": True, "pixels": pixels, @@ -840,8 +926,11 @@ class RadiometricController: "std": float(reducer(stds)), "p05": float(reducer(p05s)), "p50": float(reducer(p50s)), - "p95": float(np.max(p95s)), - "sat_pct": float(np.max(sats)), + + # Proteção suavizada quando há exatamente 2 ROIs divergentes. + "p95": p95_agg, + "sat_pct": sat_agg, + "dark_pct": float(reducer(darks)), "roi_reduce_method": reduce_method, "roi_count": int(len(roi_results)), @@ -850,6 +939,7 @@ class RadiometricController: "roi_rejected_count": int(len(rejected)), "roi_p50_values": [float(v) for v in p50_values.tolist()], "roi_p50_spread": spread_p50, + "roi_two_roi_disagreement": bool(two_roi_disagreement), } quality = { @@ -1753,6 +1843,17 @@ class RadiometricController: "gain_policy": gain_policy, } + def should_apply_exposure(self, old_exp: int, new_exp: int) -> bool: + delta = abs(int(new_exp) - int(old_exp)) + + # Threshold menor quando a exposição está baixa. + relative_threshold = int(max(8, old_exp * 0.03)) + + # Mantém limite absoluto máximo para não ficar insensível. + threshold = min(self.exp_apply_threshold_us, relative_threshold) + + return delta >= threshold + def apply_control(self, role: str, decision: dict): role = str(role).lower() new_exp = int(decision["new_exp"]) @@ -1771,7 +1872,10 @@ class RadiometricController: if role == "rgb": responses["awb"] = self.client.svc.set_awb_enable(role=role, enable=False) self._ae_disabled.add(role) - exp_delta_ok = last["exp"] is None or abs(new_exp - last["exp"]) >= self.exp_apply_threshold_us + if last["exp"] is None: + exp_delta_ok = True + else: + exp_delta_ok = self.should_apply_exposure(last["exp"], new_exp) if force_apply_exposure or exp_delta_ok: responses["exposure"] = self.client.svc.set_exposure_time(role=role, exposure_time_us=new_exp) last["exp"] = new_exp