Загрузка данных


Раз на сервере нет дискретной видеокарты, упор нужно делать на **алгоритмические фильтры (отсечение мусора)** и **оптимизацию работы процессора (CPU)**. Когда нейросеть пытается распознать размытое, слишком маленькое, повернутое или плохо освещенное лицо на процессоре, она не только тратит много времени, но и генерирует те самые ложные срабатывания (False Positives), так как вектор («хэш») такого лица получается сильно искаженным.

Вот конкретные архитектурные и программные шаги, как доработать ваш проект `ccsc_legacy_backup.py` для CPU, чтобы свести ложные распознавания к минимуму.

---

### 1. Фильтрация лиц по качеству (Face Quality Blur Assessment)

Самый эффективный способ убрать ложные срабатывания — запретить нейросети распознавать смазанные кадры (когда человек идет, и камера не успевает сфокусироваться).
Перед тем как отправлять лицо на сравнение с базой данных, проверьте его на размытость с помощью простого и очень быстрого метода **Лапласиана** (он работает на CPU мгновенно):

```python
import cv2

def is_blur(face_img, threshold=100):
    """
    Возвращает True, если изображение размыто.
    threshold подбирается экспериментально (обычно от 70 до 150).
    Чем меньше значение, тем более размытые кадры будут пропускаться.
    """
    gray = cv2.cvtColor(face_img, cv2.COLOR_BGR2GRAY)
    variance = cv2.Laplacian(gray, cv2.CV_64F).var()
    return variance < threshold

```

**Куда вставить в ваш код:** В цикле обработки лиц (внутри `ai_worker`), как только детектор определил координаты лица (`bbox`), вырежьте этот кусочек из кадра: `face_crop = frame[y1:y2, x1:x2]`. Если `is_blur(face_crop)` возвращает `True` — просто делайте `continue` и пропускайте этот кадр.

---

### 2. Фильтрация по углам поворота головы (Pose Estimation)

InsightFace при детекции выдает не только рамку (`bbox`), но и ключевые точки лица (`landm` или `kps` — глаза, нос, уголки рта). Если человек повернулся к камере боком или сильно наклонил голову, модель `buffalo_l` всё равно попытается извлечь вектор, но он будет ошибочным, что приведет к ложному совпадению с кем-то из базы.

В объекте `face`, который возвращает `app.get()`, уже есть готовые углы поворота головы (аттрибут `pose`: *pitch* (наклон вверх/вниз), *yaw* (поворот влево/вправо), *roll* (наклон к плечу)).

* **Добавьте жесткий фильтр в `ai_worker`:**
```python
# Проверка, что человек смотрит относительно прямо в камеру
if hasattr(face, 'pose'):
    pitch, yaw, roll = face.pose
    if abs(yaw) > 30 or abs(pitch) > 25:
        continue  # Пропускаем профили и наклоненные головы

```



```

---

### 3. Метод «Голосования» по N кадрам (Важнейший шаг для видеопотока)
В вашей текущей архитектуре скрипт, скорее всего, принимает решение по одному единственному кадру: совпало расстояние — выдаем лог/уведомление. На CPU из-за шума матрицы камеры один кадр может «скакнуть» и показаться похожим на человека из базы.

**Решение:** Сделайте буфер распознавания внутри `ai_worker`. 
* Вместо мгновенного срабатывания, запоминайте ID распознанного человека для конкретного трека (или в течение последних 2-3 секунд).
* Отправляйте лог/уведомление только тогда, когда один и тот же ID определился, например, **3 раза за последние 5 кадров**. Если это была случайная ложная детекция — она проскочит на 1 кадре и исчезнет, не создав ложного лога.

---

### 4. Оптимизация ONNX Runtime под CPU
Чтобы процессор не захлебывался при увеличении разрешения, нужно правильно настроить параметры `providers` в ONNX. По умолчанию он может использовать только одно ядро или, наоборот, пытаться хаотично задействовать все потоки, вызывая микрофризы.

Измените инициализацию во всех местах (`api_upload_person`, `api_db_mass_upload` и главном потоке):
```python
import onnxruntime as ort

# Настройка опций для CPU
opts = ort.SessionOptions()
opts.intra_op_num_threads = 4  # Задайте жестко количество ядер (например, 4)
opts.inter_op_num_threads = 2
opts.execution_mode = ort.ExecutionMode.ORT_SEQUENTIAL

# Передаем опции в InsightFace
temp_app = FaceAnalysis(name='buffalo_l', allowed_modules=['detection', 'recognition'], providers=['CPUExecutionProvider'])
# В зависимости от версии insightface, опции сессии можно прокинуть через провайдеры:
# providers=[('CPUExecutionProvider', {'intra_op_num_threads': '4'})]

```

---

### 5. Использование каскадного изменения `det_size`

В первом ответе я советовал поднять размер до `1280x1280`, но на CPU это может сильно снизить FPS. Чтобы найти баланс между точностью детекции мелких (дальних) лиц и скоростью процессора:

* Установите компромиссный размер: `det_size=(960, 960)`. Это значительно точнее, чем `640x640`, но процессор справится с этим гораздо легче, чем с FullHD-картинкой.

---

### Резюме: Идеальный пайплайн для CPU внутри вашего `ai_worker`

Каждый кадр из RTSP-потока должен проходить следующий жесткий фильтр перед тем, как вы начнете вычислять косинусное расстояние (`np.linalg.norm`):

```
[Кадр из RTSP] 
      │
      ▼
[Детектор InsightFace (960x960)]
      │
      ▼
[Размер лица > 80x80px?] ──(Нет)──> Пропустить кадр
      │ (Да)
      ▼
[Поворот головы (Yaw/Pitch) < 30°?] ──(Нет)──> Пропустить кадр
      │ (Да)
      ▼
[Размытость (Лапласиан) < порога?] ──(Да)──> Пропустить кадр
      │ (Нет, кадр четкий)
      ▼
[Извлечение 512-мерного вектора (Embedding)]
      │
      ▼
[Сравнение с базой (Порог строгости 0.52)]
      │
      ▼
[Проверка через буфер: Повторилось 3 раза?] ──(Нет)──> Ждем еще кадры
      │ (Да)
      ▼
[ЗАПИСЬ В БАЗУ / СРАБАТЫВАНИЕ ТЕЛЕГРАМА]

```

Внедрение даже двух фильтров (по размеру лица и по размытости Лапласиана) уберет до 90% ложных срабатываний, так как нейросеть перестанет анализировать "кашу" на заднем плане кадра. Порог косинусного расстояния при этом держите в районе **0.50–0.53** (для ArcFace/Buffalo).