System Development детекции вторжения (Intrusion Detection) по видео
Детекция вторжения — автоматическое обнаружение появления человека или транспортного средства в запретной зоне. Задача кажется простой, но на практике генерирует массу ложных срабатываний: ветер, тени, свет фар, мелкие животные. Хорошая система должна иметь recall > 95% при ложных срабатываниях < 1 в час на камеру.
Двухуровневый детектор
import cv2
import numpy as np
from ultralytics import YOLO
class IntrusionDetector:
def __init__(self, model_path: str, zone_polygon: list,
sensitivity: str = 'medium'):
self.detector = YOLO(model_path)
self.zone = np.array(zone_polygon, dtype=np.int32)
# Background subtractor для motion pre-filtering
self.bg_subtractor = cv2.createBackgroundSubtractorMOG2(
history=500,
varThreshold=16,
detectShadows=True
)
# Параметры чувствительности
self.conf_thresholds = {
'low': 0.7,
'medium': 0.5,
'high': 0.3
}
self.conf = self.conf_thresholds[sensitivity]
# Фильтр ложных срабатываний
self.confirmed_tracks = {} # track_id -> frames_in_zone
self.confirmation_frames = 3 # N кадров подряд = подтверждённое вторжение
def detect(self, frame: np.ndarray) -> dict:
result = {
'intrusion_detected': False,
'intruders': [],
'motion_level': 0.0
}
# 1. Быстрая проверка: есть ли движение
fg_mask = self.bg_subtractor.apply(frame)
# Удаляем тени (серые пиксели)
fg_mask[fg_mask == 127] = 0
motion_level = float(fg_mask.sum()) / (frame.shape[0] * frame.shape[1])
result['motion_level'] = motion_level
# Если движения нет — пропускаем дорогой ML инференс
if motion_level < 0.001:
return result
# 2. ML детекция
detections = self.detector(frame,
conf=self.conf,
classes=[0, 2, 3, 5, 7]) # person + vehicles
for box in detections[0].boxes:
x1, y1, x2, y2 = map(int, box.xyxy[0])
cx, cy = (x1 + x2) // 2, (y1 + y2) // 2
# Центр объекта в запретной зоне?
in_zone = cv2.pointPolygonTest(
self.zone,
(float(cx), float(cy)),
False
) >= 0
if in_zone:
result['intruders'].append({
'class': self.detector.model.names[int(box.cls)],
'confidence': float(box.conf),
'bbox': [x1, y1, x2, y2],
'center': (cx, cy)
})
if result['intruders']:
result['intrusion_detected'] = True
return result
Фильтрация ложных срабатываний
class FalsePositiveFilter:
def __init__(self):
self.event_buffer = []
self.cooldown_seconds = 30 # минимум 30 сек между тревогами
def should_trigger_alarm(self, intrusion_event: dict,
current_time: float) -> bool:
# Минимальная площадь bounding box (фильтрует мелких животных)
for intruder in intrusion_event.get('intruders', []):
x1, y1, x2, y2 = intruder['bbox']
area = (x2 - x1) * (y2 - y1)
if area < 2000: # пикселей
return False
# Cooldown период
if self.event_buffer:
last_event_time = self.event_buffer[-1]
if current_time - last_event_time < self.cooldown_seconds:
return False
self.event_buffer.append(current_time)
# Хранить только последние 10 событий
self.event_buffer = self.event_buffer[-10:]
return True
Ночная работа: ИК и тепловые камеры
Стандартные RGB-модели плохо работают в темноте. Решения:
- ИК-подсветка камеры (850nm или 940nm): модель обучаем на ИК-изображениях
- Тепловая камера (FLIR, Axis): люди хорошо детектируются по тепловому излучению; требует отдельной модели или дообучения на тепловых данных
- Фьюжн RGB + тепло: наилучшая точность в любых условиях
Мультизонная конфигурация
zones_config = {
'perimeter': {
'polygon': [[0,300],[1920,300],[1920,1080],[0,1080]],
'alert_level': 'warning',
'schedule': 'always'
},
'server_room': {
'polygon': [[500,200],[900,200],[900,600],[500,600]],
'alert_level': 'critical',
'schedule': 'after_hours', # только в нерабочее время
'allowed_persons': ['id_001', 'id_002'] # whitelist
}
}
| Метрика | Типичное значение |
|---|---|
| Detection Rate (recall) | 95–98% |
| False Alarm Rate | < 2 в час (хорошие условия) |
| Latency до тревоги | < 2 секунды |
| Работа в темноте (ИК) | 90–94% DR |
| Масштаб | Срок |
|---|---|
| 1–4 камеры, простые зоны | 2–3 недели |
| 8–20 камер, сложные зоны + расписание | 4–7 недель |
| 50+ камер, интеграция с PSIM | 10–16 недель |







