Всем добра.
Введение
В наше время технологии распознавания лиц становятся все более популярными и востребованными в различных областях, начиная от безопасности и заканчивая маркетингом. В этой статье мы рассмотрим, как с помощью 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)
DezmontDeXa
19.06.2024 04:41Важно заметить, что для работы системы требуется база эталонов(с разных ракурсов и прочего). Т.е. система применима только в местах куда доступ предоставлен строго определенному кругу лиц.
Не получится запускать людей, сразу присваивая им id в системе и узнавать при следующей встрече.
Vyacheslav_Olegovich Автор
19.06.2024 04:41спасибо за комментарий, но идея была в другом. Для функционала который описали Вы, использовался бы другой подход.
Dominux
19.06.2024 04:41global
не должен использоваться так, как это делаете вы (хотя его использование в целом не особо приветствуется)Использование асинхронности для CPU/GPU-bound задач, которые как раз и являются явным боттлнеком функции в вашем случае - бесполезная идея
os, datetime и asyncio - стандартные встроенные модули Python, а представлены как сторонние библиотеки
Весьма ужасный стиль форматирования а-ля тяп-ляп и так сойдёт. Можно было перечитать хотя бы раз статью и убедиться самому?
Использование магических чисел - определенно бэд практис
По итогу мы имеем статью в стиле туториалов ХаудиХо или Гоши Дударя, где базовые вещи представляются как что-то сверхкрутое, а стиль кода и используемые практики оставляют желать лучшего. Стоит отметить, что у них своя ниша - популяризация разработки среди совсем начинающих. А Хабр - всё-таки больше для людей попродвинутее, им не стоит популяризировать плохие практики, а стоит приучать к тому, как правильно
Newcss
Помню эту оригинальную статью face_recognition, жаль что ссылки на нее нет в посте. Взяли пример из оригинальной статьи и даже не доработали. Из недостатков подхода - лицо есть файл без привязки кто. Добавить новое лицо без перезагрузки - невозможно. Чем больше база лиц - тем сильнее будет тупить. Каждый раз при запуске программы - считывается каталог фоток, считаются их расстояния, но тут даже об этом речи нет - входное изображение одно). Удачи.
Vyacheslav_Olegovich Автор
Для написания функционала изучал много статей на хабре, но не плагиатил и не копировал не одну. Поэтому не надо писать "Взяли пример из оригинальной статьи и даже не доработали " - это 100% не так.
" ... лицо есть файл без привязки кто..." - есть привязка к одному лицу, для реализации мне достаточно было распознавать 1 лицо. Для реализации более сложного функционала использовал бы БД с лицами - в этом не было необходимости.