SIFT — наиболее точный, ORB — самый быстрый. Автоматический fallback: → AKAZE → ORB
FLANN быстрее на больших наборах, BFMatcher точнее на малых
0.75 0.5 — строгая фильтрация, 0.9 — больше совпадений. Для аэроснимков рекомендуется 0.80–0.85
Больше = точнее гомография, но медленнее. Рекомендуется 500–2000
5.0 Максимальная ошибка репроекции для инлаера. 3–5 для точных, 5–10 для грубого поиска
Больше итераций — надёжнее, но медленнее. Рекомендуется 2000–10000
0.999 Вероятность нахождения правильной модели. 0.99–0.999 рекомендуется
Минимум 4 (математический минимум для гомографии). Рекомендуется 4–10
0.08 Доля инлаеров от всех матчей. 0.08 = 8% минимум. Для сложных сцен: 0.05–0.10
Создаёт inlier_matches.png и detected_object.png для отладки

Справка

СценарийДетекторRANSACMin inliersRatio
Аэросъёмка (разные даты)SIFT5.040.82
Одинаковый масштабSIFT3.060.75
Быстрый поискORB5.040.85
Максимальная точностьSIFT2.0100.65
Сезонные различияAKAZE8.040.85
Автоматический fallback: если основной детектор даёт мало матчей, автоматически пробуются SIFT → AKAZE → ORB. При провале RANSAC пробуется LMEDS, затем rigid translation (медианный сдвиг). CLAHE нормализует освещение между снимками.

Алгоритм

  1. CLAHE — нормализация освещения
  2. Multi-detector: детекция ключевых точек (с автоматическим fallback)
  3. KNN-сопоставление + Lowe's ratio test → good_matches
  4. cv2.findHomography(RANSAC) → матрица H + инлаеры
  5. Fallback: LMEDS → rigid translation (если RANSAC не сработал)
  6. cv2.perspectiveTransform(corners, H) → контур объекта
  7. Геометрическая валидация (выпуклость, площадь, границы)

Параметры запроса

ПараметрТипПо умолчаниюОписание
query_imagefileИскомый объект (template)
train_imagefileСцена для поиска (scene)
detectorstringSIFTSIFT | ORB | AKAZE | BRISK
matcherstringFLANNFLANN | BFMatcher
ratio_thresholdfloat0.82Порог Lowe's ratio (0.1–1.0)
max_matchesint1000Макс. совпадений (1–5000)
ransac_reproj_thresholdfloat5.0Ошибка репроекции (px)
max_itersint5000Макс. итераций RANSAC
confidencefloat0.999Уверенность RANSAC
min_inliersint4Мин. инлаеров (≥4)
min_inlier_ratiofloat0.08Мин. доля инлаеров
return_debug_imagesbooltrueГенерировать отладочные изображения

Примеры запросов и ответов

# ── Запрос: локализация объекта через гомографию ──
curl -X POST http://localhost:8888/api/v1/match/feature-homography \
  -F "query_image=@template.png" \
  -F "train_image=@scene.png" \
  -F "detector=SIFT" \
  -F "matcher=FLANN" \
  -F "ratio_threshold=0.82" \
  -F "ransac_reproj_threshold=5.0" \
  -F "max_iters=5000" \
  -F "min_inliers=4"

# ── Ответ (201): задача создана ──
# {
#   "uid": "a52a88d9-8fb7-4c17-b08c-200bfb3d5fb8",
#   "status": "queued",
#   "tool": "feature_homography",
#   "params": { "detector":"SIFT", "ransac_reproj_threshold":5.0, ... }
# }

# ── Запрос: получить результат ──
curl http://localhost:8888/api/v1/tasks/a52a88d9-8fb7-4c17-b08c-200bfb3d5fb8

# ── Ответ (200): задача завершена ──
# {
#   "status": "done",
#   "result_data": {
#     "object_found": true,
#     "inliers_count": 72,
#     "inlier_ratio": 0.878,
#     "projected_corners": [
#       {"x": 439, "y": 239}, {"x": 575, "y": 239},
#       {"x": 575, "y": 374}, {"x": 439, "y": 374}
#     ],
#     "bbox": {"x": 439, "y": 239, "w": 136, "h": 135},
#     "homography": [[...], [...], [...]],
#     "metrics": {"mean_reprojection_error": 0.166}
#   },
#   "result_files": [
#     "results/a52a.../inlier_matches.png",
#     "results/a52a.../detected_object.png"
#   ]
# }
// ── Запрос: локализация через гомографию ──
const form = new FormData();
form.append("query_image", templateFile);
form.append("train_image", sceneFile);
form.append("detector", "SIFT");
form.append("ransac_reproj_threshold", "5.0");
form.append("min_inliers", "4");

const res = await fetch("/api/v1/match/feature-homography", {
  method: "POST", body: form,
});
const task = await res.json();

// ── Поллинг результата ──
const result = await fetch(`/api/v1/tasks/${task.uid}`)
  .then(r => r.json());

// result.result_data:
// {
//   object_found: true,
//   inliers_count: 72,
//   inlier_ratio: 0.878,
//   projected_corners: [{x:439,y:239}, ...],
//   bbox: {x:439, y:239, w:136, h:135},
//   metrics: {mean_reprojection_error: 0.166}
// }
import requests

# ── Запрос: локализация через гомографию ──
files = {
    "query_image": open("template.png", "rb"),
    "train_image": open("scene.png", "rb"),
}
data = {
    "detector": "SIFT",
    "ransac_reproj_threshold": "5.0",
    "max_iters": "5000",
    "min_inliers": "4",
}
resp = requests.post(
    "http://localhost:8888/api/v1/match/feature-homography",
    files=files, data=data,
)
task = resp.json()

# ── Поллинг результата ──
result = requests.get(
    f"http://localhost:8888/api/v1/tasks/{task['uid']}"
).json()

# result["result_data"]:
# {
#   "object_found": True,
#   "inliers_count": 72,
#   "inlier_ratio": 0.878,
#   "projected_corners": [{"x":439,"y":239}, ...],
#   "bbox": {"x":439, "y":239, "w":136, "h":135},
#   "homography": [[...], [...], [...]],
#   "metrics": {"mean_reprojection_error": 0.166}
# }

Документация OpenCV: Feature Matching + Homography →