You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
MAI/HOMOGRAPHY_INTEGRATION.py

144 lines
7.5 KiB
Python

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# ============================================================
# HOMOGRAPHY_INTEGRATION.py
# Как подключить homography-enabled motion saliency в main.py
# ============================================================
# ─────────────────────────────────────────────────────────────
# ИМПОРТЫ
# ─────────────────────────────────────────────────────────────
"""
from camera_motion import (
estimate_ego_motion_adaptive,
estimate_global_homography_ex,
estimate_global_affine_ex,
homography_is_plausible,
affine_is_plausible,
warp_is_plausible,
)
from motion_saliency import MotionSaliency
"""
# ─────────────────────────────────────────────────────────────
# ВАРИАНТ A (простой, рекомендуется начать с него):
# adaptive — homography с автоматическим fallback на affine
# ─────────────────────────────────────────────────────────────
"""
motion_sal = MotionSaliency()
prev_gray_for_ms = None
ms_kind_stats = {"homography": 0, "affine": 0, "none": 0}
# В главном цикле:
gray_eff = cv2.cvtColor(frame_eff_bgr, cv2.COLOR_BGR2GRAY)
M, kind, ego_inliers, ego_outliers = estimate_ego_motion_adaptive(
prev_gray_for_ms, gray_eff
)
ms_kind_stats[kind] = ms_kind_stats.get(kind, 0) + 1
if not warp_is_plausible(M, kind):
M = None
kind = "none"
ego_outliers = np.zeros((0, 2), dtype=np.float32)
# В терминальной фазе отключаем — слишком большой parallax
ms_active = True
if intercept_params is not None:
phase = intercept_params.get("phase", "")
if phase in ("terminal", "critical"):
ms_active = False
if ms_active:
motion_sal.update(gray_eff, prev_gray_for_ms, M, kind=kind,
outlier_pts=ego_outliers)
else:
motion_sal.reset()
prev_gray_for_ms = gray_eff
"""
# ─────────────────────────────────────────────────────────────
# ВАРИАНТ B (dual residual, максимально устойчивый):
# считаем обе модели, берём min residual. Дороже по CPU но
# устойчивее на сценах с несколькими плоскостями (горизонт+земля).
# ─────────────────────────────────────────────────────────────
"""
# Считаем обе модели
H, h_in, h_out, h_meta = estimate_global_homography_ex(
prev_gray_for_ms, gray_eff
)
A, a_in, a_out = estimate_global_affine_ex(
prev_gray_for_ms, gray_eff
)
# Фильтруем по качеству
H_use = H if homography_is_plausible(H, h_meta) else None
A_use = A if affine_is_plausible(A) else None
# Объединяем outliers обеих моделей (точки, не объяснённые НИ одной)
# — пересечение дает самый чистый сигнал, но можно и объединение
if len(h_out) > 0 and len(a_out) > 0:
# Простое объединение обычно достаточно
ego_outliers = np.concatenate([h_out, a_out], axis=0)
elif len(h_out) > 0:
ego_outliers = h_out
elif len(a_out) > 0:
ego_outliers = a_out
else:
ego_outliers = np.zeros((0, 2), dtype=np.float32)
motion_sal.update_dual(
gray_eff, prev_gray_for_ms,
H=H_use, A=A_use,
outlier_pts=ego_outliers,
)
prev_gray_for_ms = gray_eff
"""
# ─────────────────────────────────────────────────────────────
# ТЮНИНГ ПО СЦЕНАМ
# ─────────────────────────────────────────────────────────────
#
# 1) Если в логах ms_kind_stats почти всегда "affine" — значит
# homography не проходит пороги качества. Варианты:
# - понизить HOMO_MIN_INLIERS до 35
# - понизить HOMO_MIN_FILLED_CELLS до 3
# - увеличить CAM_MOTION_MAX_CORNERS чтобы было больше точек
#
# 2) Если homography выбирается часто но daёт странные residual
# (вся земля горит) — это признак того, что она фитится в
# одну плоскость (небо), а земля как вторая плоскость даёт
# fake residual. Решение — переключиться на Variant B (dual),
# min-из-двух карт это исправляет.
#
# 3) Для сложных сцен с ЛЭП и лесом рекомендую сразу Variant B.
# Overhead ~2x по CPU для ego-motion, но motion_saliency
# всё равно дешёвый относительно YOLO, общий FPS просядет
# минимально.
#
# 4) Если летите очень низко над лесом (parallax огромный, никакая
# модель не помогает) — тогда motion saliency просто отключайте
# на такие периоды по высоте/скорости носителя, а полагайтесь
# на KLT+IMM которые у вас уже есть.
#
# 5) Если homography выдаёт вырожденные матрицы часто — уменьшите
# HOMO_MAX_CORNER_SHIFT до 80, это агрессивнее отсеивает плохие
# фиты (ценой иногда пропустить валидный резкий манёвр камеры).
# ─────────────────────────────────────────────────────────────
# ДИАГНОСТИКА
# ─────────────────────────────────────────────────────────────
# В конце сессии напечатайте статистику:
"""
total = sum(ms_kind_stats.values())
if total > 0:
print(f"Ego motion stats: "
f"homography={ms_kind_stats['homography']/total*100:.1f}% "
f"affine={ms_kind_stats['affine']/total*100:.1f}% "
f"none={ms_kind_stats['none']/total*100:.1f}%")
"""
# Здоровая статистика на вашем типе данных:
# homography: 50-80% (когда хватает текстуры)
# affine: 15-40% (чистое небо, слабая текстура)
# none: < 5% (если больше — проблема с LK/feature detection)