Всем добра.

Введение

В наше время технологии распознавания лиц становятся все более популярными и востребованными в различных областях, начиная от безопасности и заканчивая маркетингом. В этой статье мы рассмотрим, как с помощью Python и библиотек face_recognition и OpenCV создать систему, которая будет распознавать лица, делать скриншоты при обнаружении лица в кадре и отправлять эти скриншоты в Telegram.

Проект «Кто приходил»

Проект "Кто приходил" представляет собой систему, которая использует технологии распознавания лиц для автоматического определения лиц в кадре, их идентификации и отправки уведомлений с изображениями в Telegram. Это может быть полезно для обеспечения безопасности, мониторинга доступа в определенные зоны или просто для наблюдения.

Необходимые библиотеки

Для реализации проекта нам понадобятся следующие библиотеки:

  • OpenCV для захвата видеопотока с веб-камеры и обработки изображений.

  • face_recognition для обнаружения и распознавания лиц.

  • os для работы с файловой системой (создание и проверка директорий).

  • datetime для работы с датой и временем (отслеживание времени обнаружения лиц).

  • asyncio для асинхронного выполнения задач (отправка сообщений в Telegram).

  • telegram для взаимодействия с API Telegram (отправка скриншотов пользователю).

Установить их можно с помощью pip (pip install face_recognition opencv-python python-telegram-bot).

Настройка Telegram бота

Для начала работы с Telegram ботом, необходимо создать его через BotFather и получить токен. Этот токен будет использоваться для аутентификации нашего бота. Далее, мы должны узнать ID пользователя, которому будут отправляться уведомления. Это можно сделать с помощью различных методов, например, через специальные боты, которые показывают ваш User ID.

Основной код

Загрузка и подготовка изображения

Первым шагом будет загрузка изображения, с которым мы будем сравнивать лица, и его кодирование. Для этого используем библиотеку face_recognition:

import face_recognition

import cv2

# Загрузка фотографии, с которой будем сравнивать лица

imgmain = face_recognition.load_image_file('photo.jpg')

imgmain = cv2.cvtColor(imgmain, cv2.COLOR_BGR2RGB)  # Конвертация изображения из BGR (формат OpenCV) в RGB (формат face_recognition)

# Нахождение лиц и кодирование

encodeElon = face_recognition.face_encodings(imgmain)[0]  # Кодирование лица на изображении

Инициализация видеозахвата

Следующим шагом будет инициализация видеозахвата с помощью OpenCV:

# Инициализация видеозахвата

cap = cv2.VideoCapture(0)  # Запуск видеозахвата с веб-камеры

if not cap.isOpened():

    print("Ошибка при открытии веб-камеры.")

    exit(1)

Определение пути для сохранения скриншотов

Для сохранения скриншотов создаем отдельную директорию:

import os

# Определение пути для сохранения скриншотов

current_directory = os.getcwd()  # Получение текущего рабочего каталога

screenshots_directory = os.path.join(current_directory, "screenshots")  # Определение пути к каталогу для скриншотов

if not os.path.exists(screenshots_directory):

    os.makedirs(screenshots_directory)  # Создание каталога, если он не существует

Отправка изображений в Telegram

Создадим асинхронную функцию для отправки изображений в Telegram:

from telegram import Bot

from telegram.error import TelegramError

import asyncio

# Установка токена бота Telegram

TOKEN = "ВАШ_ТЕЛЕГРАМ_ТОКЕН"

# ID пользователя, которому будет отправлено сообщение

USER_ID = ВАШ_USER_ID

# Создание объекта бота

bot = Bot(token=TOKEN)

async def send_photo_to_telegram(photo_path):

    # Отправка изображения в Telegram

    with open(photo_path, 'rb') as photo_file:

        try:

            await bot.send_photo(chat_id=USER_ID, photo=photo_file)

            print(f"Labeled screenshot sent to Telegram user {USER_ID}")

        except TelegramError as e:

            print(f"Failed to send photo: {e}")

Обработка видеопотока

Создадим асинхронную функцию для обработки видеопотока, поиска лиц и отправки скриншотов:

from datetime import datetime

face_present_start_time = None  # Время начала обнаружения лица

screenshot_taken = False  # Флаг, указывающий, был ли сделан скриншот

async def process_video():

global face_present_start_time, screenshot_taken

    while True:

        ret, frame = cap.read()  # Чтение кадра с веб-камеры

        if not ret:

            print("Ошибка при захвате кадра.")

            break

        # Конвертация изображения из BGR в RGB

        rgb_frame = frame[:, :, ::-1]  # Конвертация кадра из BGR (формат OpenCV) в RGB (формат face_recognition)

        # Поиск всех лиц в текущем кадре видео

        face_locations = face_recognition.face_locations(rgb_frame)  # Нахождение всех лиц в кадре

        if face_locations:  # Если лица найдены

            if face_present_start_time is None:

                face_present_start_time = datetime.now()  # Установка времени начала обнаружения лица

            else:

                elapsed_time = (datetime.now() - face_present_start_time).total_seconds()  # Вычисление времени, прошедшего с начала обнаружения

                if elapsed_time >= 3 and not screenshot_taken:  # Если прошло 3 секунды и скриншот еще не был сделан

                    screenshot_path = os.path.join(screenshots_directory, f"face_{len(os.listdir(screenshots_directory)) + 1}.png")

                    cv2.imwrite(screenshot_path, frame)  # Сохранение скриншота

                    saved_screenshot = cv2.imread(screenshot_path)  # Загрузка сохраненного скриншота

                    # Поиск всех лиц на скриншоте

                    face_locations_test = face_recognition.face_locations(saved_screenshot)  # Нахождение всех лиц на скриншоте

                    encodings_test = face_recognition.face_encodings(saved_screenshot)  # Кодирование всех лиц на скриншоте

                    for (top, right, bottom, left), encodeTest in zip(face_locations_test, encodings_test):

                        results = face_recognition.compare_faces([encodeElon], encodeTest)  # Сравнение каждого лица на скриншоте с эталонным лицом

                        label = "Slava" if True in results else "Unknown"  # Определение метки для лица

                        cv2.rectangle(saved_screenshot, (left, top), (right, bottom), (255, 0, 255), 2)  # Отрисовка прямоугольника вокруг лица

                        cv2.putText(saved_screenshot, label, (left, top - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (255, 0, 255), 2)  # Добавление метки

                    print(f"Screenshot saved as {screenshot_path}")

                    screenshot_taken = True  # Установка флага, что скриншот был сделан

                    cv2.imshow('Test Image', saved_screenshot)  # Отображение скриншота с помеченными лицами

                    # Сохранение изображения с помеченными лицами

                    labeled_screenshot_path = os.path.join(screenshots_directory, f"labeled_face_{len(os.listdir(screenshots_directory)) + 1}.png")

                    cv2.imwrite(labeled_screenshot_path, saved_screenshot)  # Сохранение скриншота с метками

                    print(f"Labeled screenshot saved as {labeled_screenshot_path}")

                    # Отправка изображения в Telegram

                    await send_photo_to_telegram(labeled_screenshot_path)

            for top, right, bottom, left in face_locations:

                cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)  # Отрисовка прямоугольника вокруг лиц в текущем кадре

        else:

            face_present_start_time = None  # Сброс времени начала обнаружения лица

            screenshot_taken = False  # Сброс флага скриншота

        cv2.imshow('Video', frame)  # Отображение текущего кадра

        if cv2.waitKey(25) == 13:  # Нажатие Enter для выхода из цикла

            break

    cap.release()  # Освобождение видеозахвата

    cv2.destroyAllWindows()  # Закрытие всех окон OpenCV

asyncio.run(process_video())  # Запуск асинхронной функции обработки видео

Заключение

Мы рассмотрели, как создать простую систему распознавания лиц с использованием Python и популярных библиотек. Эта система не только распознает лица, но и делает скриншоты, отправляет их в Telegram, что может быть полезно для различных целей, таких как обеспечение безопасности или просто наблюдение. Надеюсь, что этот пример будет полезен для вас и поможет в создании собственных проектов на основе распознавания лиц.

Комментарии (5)


  1. Newcss
    19.06.2024 04:41

    Помню эту оригинальную статью face_recognition, жаль что ссылки на нее нет в посте. Взяли пример из оригинальной статьи и даже не доработали. Из недостатков подхода - лицо есть файл без привязки кто. Добавить новое лицо без перезагрузки - невозможно. Чем больше база лиц - тем сильнее будет тупить. Каждый раз при запуске программы - считывается каталог фоток, считаются их расстояния, но тут даже об этом речи нет - входное изображение одно). Удачи.


    1. Vyacheslav_Olegovich Автор
      19.06.2024 04:41

      1. Для написания функционала изучал много статей на хабре, но не плагиатил и не копировал не одну. Поэтому не надо писать "Взяли пример из оригинальной статьи и даже не доработали " - это 100% не так.

      2. " ... лицо есть файл без привязки кто..." - есть привязка к одному лицу, для реализации мне достаточно было распознавать 1 лицо. Для реализации более сложного функционала использовал бы БД с лицами - в этом не было необходимости.


  1. DezmontDeXa
    19.06.2024 04:41

    Важно заметить, что для работы системы требуется база эталонов(с разных ракурсов и прочего). Т.е. система применима только в местах куда доступ предоставлен строго определенному кругу лиц.

    Не получится запускать людей, сразу присваивая им id в системе и узнавать при следующей встрече.


    1. Vyacheslav_Olegovich Автор
      19.06.2024 04:41

      спасибо за комментарий, но идея была в другом. Для функционала который описали Вы, использовался бы другой подход.


  1. Dominux
    19.06.2024 04:41

    1. global не должен использоваться так, как это делаете вы (хотя его использование в целом не особо приветствуется)

    2. Использование асинхронности для CPU/GPU-bound задач, которые как раз и являются явным боттлнеком функции в вашем случае - бесполезная идея

    3. os, datetime и asyncio - стандартные встроенные модули Python, а представлены как сторонние библиотеки

    4. Весьма ужасный стиль форматирования а-ля тяп-ляп и так сойдёт. Можно было перечитать хотя бы раз статью и убедиться самому?

    5. Использование магических чисел - определенно бэд практис

    По итогу мы имеем статью в стиле туториалов ХаудиХо или Гоши Дударя, где базовые вещи представляются как что-то сверхкрутое, а стиль кода и используемые практики оставляют желать лучшего. Стоит отметить, что у них своя ниша - популяризация разработки среди совсем начинающих. А Хабр - всё-таки больше для людей попродвинутее, им не стоит популяризировать плохие практики, а стоит приучать к тому, как правильно