Разработка системы распознавания нежелательного поведения (Behavior Detection)
Дежурный оператор смотрит на 16 мониторов по 4 камеры — это классика. Через 20 минут внимание рассеивается, а через час он пропустит реальную драку. Автоматическая детекция нежелательного поведения решает эту проблему. Мы разрабатываем системы, которые видят не только 'что', но и 'как': позы, траектории, контекст. Сложность в том, что граница между нормой и нарушением размыта, а высокий recall требует работы с ложными срабатываниями. Система строится по модульному принципу: rule-based детекторы для простых сценариев, скелетный анализ для падений и бега, глубокие нейросети для агрессии и вандализма. Каждый модуль каскадно фильтруется, чтобы precision оставалась на уровне 82% и выше. Оцените возможность автоматизации на вашем объекте — свяжитесь с нами для предварительного анализа.
Какие типы поведения распознает система?
Уровень 1 (rule-based): простые события — пересечение линии, скопление точек. Не требует ML, низкое CPU. Настраивается за день.
Уровень 2 (pose-based): события на основе скелета человека (MediaPipe / RTMPose). Анализ углов суставов и скорости движения. Даёт 90% точности на падениях без GPU.
Уровень 3 (video-based): глубокое видео-понимание через 3D CNN или Video Transformer. Высокая точность, требует GPU. Используем датасет KINETICS-400 для предобучения.
Как работает детекция агрессии?
Драка — это не просто два объекта в кадре, это характерная динамика: резкие движения рук, внезапные падения, повышенная скорость перемещений. Мы используем 3D CNN, обученный на наборе из 400 классов KINETICS. Модель «смотрит» 16 кадров (0.5 с) и выдаёт вероятность агрессии. На практике precision=82%, recall=88% — лучше, чем у 90% операторов.
import torch import torch.nn as nn from torchvision.models.video import r3d_18, R3D_18_Weights class FightDetector: def __init__(self, model_path: str, threshold: float = 0.7): base = r3d_18(weights=R3D_18_Weights.KINETICS400_V1) base.fc = nn.Sequential( nn.Linear(512, 128), nn.GELU(), nn.Dropout(0.4), nn.Linear(128, 2) # fight / no_fight ) base.load_state_dict(torch.load(model_path)) base.eval() self.model = base self.threshold = threshold # Скользящее окно видео self.frame_buffer = [] self.window_size = 16 # 16 кадров = ~0.5 сек при 30fps def update(self, frame: np.ndarray) -> dict | None: """Обновление буфера и получение результата""" self.frame_buffer.append(frame) if len(self.frame_buffer) > self.window_size: self.frame_buffer.pop(0) if len(self.frame_buffer) == self.window_size: return self._classify_window() return None @torch.no_grad() def _classify_window(self) -> dict: # [T, H, W, C] → [1, C, T, H, W] clip = np.stack(self.frame_buffer) clip = torch.from_numpy(clip).float().permute(3, 0, 1, 2) clip = self._normalize(clip).unsqueeze(0) logits = self.model(clip) probs = torch.softmax(logits, dim=1).squeeze() fight_prob = float(probs[1]) return { 'fight_detected': fight_prob > self.threshold, 'confidence': fight_prob } Что делать с ложными срабатываниями?
Главная боль агрессивных детекторов — false positives. Решение: temporal confirmation (N кадров подряд) — отсекает 70% случайных ложных срабатываний; multi-evidence fusion (скелет + видео + контекст) — снижает ошибки в помещениях с бликами; human-in-the-loop — отправляет сомнительные случаи охраннику, а подтверждённые — в дообучение. В итоге мы добиваемся precision=82% при recall=88% на драках. Это позволяет сэкономить до 30% бюджета на охране за счёт сокращения ложных вызовов.
Техническая деталь: каскадная фильтрация
Первый уровень — rule-based (триггер по motion), второй — pose-анализ (проверка позы), третий — 3D CNN (верификация события). Каждый уровень отсеивает false positives, оставляя только подтверждённые инциденты.Skeleton-based Behavior Analysis
Скелетный анализ позволяет детектировать падения, бег, подозрительное нахождение без затратного 3D CNN. Достаточно 5–15 FPS и лёгкой нейросети. Код ниже обрабатывает трекеры за 30 кадров и возвращает доминирующее поведение.
import numpy as np from collections import deque class BehaviorAnalyzer: def __init__(self, window_size: int = 30): self.track_history = {} # track_id -> deque of (frame, keypoints) self.window = window_size def update(self, track_id: int, frame_num: int, keypoints: dict) -> dict: if track_id not in self.track_history: self.track_history[track_id] = deque(maxlen=self.window) self.track_history[track_id].append((frame_num, keypoints)) if len(self.track_history[track_id]) < 10: return {'behavior': 'unknown'} return self._analyze(track_id) def _analyze(self, track_id: int) -> dict: history = list(self.track_history[track_id]) keypoints_seq = [kp for _, kp in history] behaviors = { 'fall': self._detect_fall(keypoints_seq), 'running': self._detect_running(keypoints_seq), 'crouching': self._detect_crouching(keypoints_seq[-1]), 'loitering': self._detect_loitering(keypoints_seq) } dominant = max(behaviors, key=lambda k: behaviors[k]) return { 'behavior': dominant if behaviors[dominant] > 0.5 else 'normal', 'scores': behaviors } def _detect_fall(self, seq: list) -> float: """Детекция падения: резкое снижение центра масс""" hip_ys = [] for kp in seq: if kp.get('left_hip') and kp.get('right_hip'): avg_hip_y = (kp['left_hip']['y'] + kp['right_hip']['y']) / 2 hip_ys.append(avg_hip_y) if len(hip_ys) < 10: return 0.0 # Нормализованные координаты: y растёт вниз max_drop = max(hip_ys[-5:]) - min(hip_ys[-15:-5]) if len(hip_ys) >= 15 else 0 return min(1.0, max_drop / 0.3) # 0.3 = 30% высоты кадра def _detect_loitering(self, seq: list) -> float: """Детекция задержки: человек долго на одном месте""" if len(seq) < 20: return 0.0 positions = [(kp.get('nose', {}).get('x', 0.5), kp.get('nose', {}).get('y', 0.5)) for kp in seq] positions = np.array(positions) spread = np.std(positions, axis=0).mean() return min(1.0, (0.05 - spread) / 0.05) # < 5% spread = loitering rule-based vs deep learning: когда что выбирать
Для счётчиков и пересечения линий rule-based быстрее и дешевле. Для драк и вандализма — только deep learning. Скелетный анализ (pose) — золотая середина: даёт 90% точности на падениях без тяжёлого GPU. В нашей практике комбинация rule-based + pose экономит до 50% бюджета на вычислительных мощностях.
Что входит в работу
- Документация: спецификация сценариев, архитектурная схема, описание API алертов.
- Доступы: Docker-образы с моделями, репозиторий конфигов, инструкция по развёртыванию.
- Интеграция: адаптация под VMS (Milestone, Genetec, TRASSIR) или RTSP-потоки.
- Обучение: сессия для операторов и администраторов (до 4 часов).
- Поддержка: 3 месяца гарантийного сопровождения, обновление моделей при ретрайне.
Процесс внедрения под ключ
- Анализ сценариев и зон на объекте (1–2 дня).
- Сбор и разметка данных (если требуется дообучение).
- Выбор архитектуры: rule-based, pose, 3D CNN или гибрид.
- Интеграция с существующей системой видеонаблюдения.
- Каскадная фильтрация и настройка чувствительности.
- Тестирование на исторических записях и запуск в 24/7.
Сроки — от 4 недель для базового решения. Закажите пилотное внедрение на двух камерах — увидите результат за две недели.
| Тип поведения | Precision | Recall |
|---|---|---|
| Падение | 91% | 94% |
| Бег/спешка | 88% | 92% |
| Агрессия/драка | 82% | 88% |
| Вандализм | 79% | 83% |
| Кража в кармане | 74% | 79% |
| Масштаб | Срок |
|---|---|
| 2–3 типа событий, rule-based + pose | 4–6 недель |
| Полная аналитика поведения | 9–14 недель |
| Высокоточная система с обучением | 14–22 недели |
Более 50 внедрений в ритейле, логистике и офисах — наша команда имеет 5+ лет опыта в Computer Vision. Оценим проект бесплатно, напишите нам.







