Современные технологии компьютерного зрения позволяют в реальном времени распознавать объекты через веб-камеру. В этой статье разберём создание собственного desktop-приложения на Python с использованием библиотеки OpenCV, нейросети YOLO и графического интерфейса на CustomTkinter.
Приложение умеет:
- получать видео с камеры;
- находить объекты в кадре;
- отображать рамки вокруг объектов;
- выводить список найденных предметов;
- автоматически переводить названия объектов на русский язык;
- работать как на CPU, так и на GPU через CUDA.
Основные библиотеки
Перед началом работы необходимо установить зависимости:
pip install customtkinter opencv-python pillow torch ultralytics
В проекте используются:
- OpenCV — работа с камерой и изображениями;
- PyTorch — запуск нейросети;
- YOLO — распознавание объектов;
- Pillow — обработка изображений;
- CustomTkinter — современный интерфейс приложения.
Инициализация приложения
Главное окно создаётся через класс CameraApp.
class CameraApp(ctk.CTk):
Внутри конструктора выполняется:
- запуск камеры;
- загрузка модели YOLO;
- определение устройства (CPU или GPU);
- запуск циклов обновления интерфейса.
self.cap = cv2.VideoCapture(0)
self.model = YOLO('yolo26n.pt')
self.device = 'cuda' if torch.cuda.is_available() else 'cpu'
self.model.to(self.device)
Создание интерфейса
Интерфейс разделён на две части:
Левая часть
Содержит видеопоток с камеры.
self.video_label = ctk.CTkLabel(
self.video_frame,
text="",
fg_color="black"
)
Правая часть
Отображает список найденных объектов.
self.objects_listbox = ctk.CTkFrame(self.right_frame)
Для каждого найденного объекта создаётся отдельная кнопка.
Обработка видео с камеры
Главная логика находится в методе update_frame().
Получение кадра
ret, frame = self.cap.read()
Конвертация цветов
OpenCV использует формат BGR, а для корректного отображения нужен RGB.
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
Распознавание объектов через YOLO
Модель анализирует кадр:
results = self.model(frame, device=self.device, verbose=False)
После этого перебираются найденные объекты:
for box in results[0].boxes:
Получаем:
- ID класса;
- название объекта;
- цвет рамки.
class_id = int(box.cls[0])
object_name = self.model.names[class_id]
Отображение рамок вокруг объектов
YOLO автоматически рисует bounding boxes:
img = Image.fromarray(results[0].plot())
В результате пользователь видит:
- объект;
- рамку;
- название класса;
- уровень уверенности модели.
Перевод объектов на русский язык
В проекте используется словарь:
from yolo_en_to_ru import yolo26_en_to_ru
Пример перевода:
object_name_ru = yolo26_en_to_ru.get(
object_name,
object_name
)
Например:
| Английский | Русский |
|---|---|
| person | человек |
| car | машина |
| dog | собака |
Динамический список объектов
Каждый обнаруженный объект выводится отдельной кнопкой.
btn_item = ctk.CTkButton(
self.objects_listbox,
text=display_text
)
При нажатии открывается модальное окно:
def click_btn(self, display_text):
Это можно использовать для:
- дополнительной информации;
- статистики;
- озвучивания объекта;
- сохранения данных.
Подсчёт объектов
Для группировки одинаковых объектов используется:
from collections import Counter
Пример:
object_counts = Counter(self.current_objects)
Если камера видит 3 человека и 2 телефона, приложение может корректно подсчитать количество каждого типа объектов.
Работа с GPU
Одно из главных преимуществ проекта — поддержка CUDA.
self.device = 'cuda' if torch.cuda.is_available() else 'cpu'
Это позволяет:
- увеличить FPS;
- ускорить распознавание;
- снизить нагрузку на процессор.
Преимущества проекта
Высокая скорость
YOLO обеспечивает распознавание объектов практически в реальном времени.
Современный интерфейс
CustomTkinter делает интерфейс более современным по сравнению с обычным Tkinter.
Простота расширения
Проект легко доработать:
- добавить запись видео;
- сохранять скриншоты;
- подключить Telegram-бота;
- добавить голосовое озвучивание;
- интегрировать базу данных;
- обучить собственную модель.
Возможные улучшения
Добавление трекинга объектов
Можно отслеживать движение объектов между кадрами.
Распознавание лиц
Интеграция с face recognition позволит определять конкретных людей.
Работа с IP-камерами
Вместо веб-камеры можно подключить RTSP-поток.
Экспорт статистики
Сохранять данные в:
- CSV;
- SQLite;
- PostgreSQL;
- Excel.
Данный проект — отличный пример использования современных технологий компьютерного зрения на Python. Сочетание YOLO, OpenCV и CustomTkinter позволяет создать мощное приложение для распознавания объектов в реальном времени.
Такое решение можно использовать для:
- систем видеонаблюдения;
- умного дома;
- автоматизации;
- анализа видео;
- образовательных проектов;
- AI-приложений.
Полный код
import customtkinter as ctk
import cv2
from PIL import Image
import torch
from collections import Counter
from yolo_en_to_ru import yolo26_en_to_ru
from ultralytics import YOLO
from ultralytics.utils.plotting import colors
class CameraApp(ctk.CTk):
def __init__(self):
super().__init__()
self.title('')
self.geometry('800x600')
self.resizable(False, False)
self.cap = cv2.VideoCapture(0)
self.model = YOLO('yolo26n.pt')
self.device = 'cuda' if torch.cuda.is_available() else 'cpu'
self.model.to(self.device)
self.current_objects = []
print(f"Модель загружена на устройство: {self.model.device}")
if not self.cap.isOpened():
print('Ошибка: Камера не найдена')
#return
self.create_widgets()
self.update_frame()
self.objects_loop()
def create_widgets(self):
self.grid_columnconfigure(0, weight=3)
self.grid_rowconfigure(1, weight=1)
self.grid_rowconfigure(0, weight=1)
self.video_frame = ctk.CTkFrame(self)
self.video_frame.grid(row=0, column=0, padx=(20, 10), pady=20, sticky="nsew")
self.video_frame.rowconfigure(0, weight=1)
self.video_frame.grid_columnconfigure(0, weight=1)
self.video_label = ctk.CTkLabel(self.video_frame, text="", fg_color="black")
self.video_label.grid(row=0, column=0, padx=20, pady=20, sticky="nsew")
self.right_frame = ctk.CTkFrame(self)
self.right_frame.grid(row=0, column=1, padx=(10, 20), pady=20, sticky="nsew")
self.right_frame.grid_rowconfigure(1, weight=1)
self.right_frame.grid_columnconfigure(0, weight=1)
self.objects_listbox = ctk.CTkFrame(self.right_frame)
self.objects_listbox.grid(row=1, column=0, padx=10, pady=10, sticky="nsew")
#self.objects_listbox = ctk.CTkTextbox(self.right_frame)
#self.objects_listbox.grid(row=1, column=0, padx=10, pady=10, sticky="nsew")
def clear_frame(self, frame):
for widget in frame.winfo_children():
widget.destroy()
def click_btn(self, display_text):
modal_add_note = ctk.CTkToplevel()
ctk.CTkLabel(modal_add_note, text=display_text, font=(None, '33px')).pack()
def update_objects_list(self):
#self.objects_listbox.configure(state='normal')
#self.objects_listbox.delete('1.0', 'end')
self.clear_frame(self.objects_listbox)
if self.current_objects:
object_counts = Counter(self.current_objects)
for object_tuple, count in object_counts.items():
object_name = object_tuple[0]
color = object_tuple[1]
object_name_ru = yolo26_en_to_ru.get(object_name, object_name)
display_text = f'{object_name_ru}'
btn_item = ctk.CTkButton(self.objects_listbox, bg_color=color, command=lambda m=display_text: self.click_btn(m), text=display_text, anchor="center", height=5)
btn_item.pack(pady=10, padx=10)
#self.objects_listbox.insert('end', display_text)
#self.objects_listbox.configure(state='disabled')
def objects_loop(self):
self.update_objects_list()
self.after(3000, self.objects_loop)
def update_frame(self):
ret, frame = self.cap.read()
if ret:
# Конвертируем BGR в RGB
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = self.model(frame, device=self.device, verbose=False)
detected_objects = []
if results[0].boxes is not None:
for box in results[0].boxes:
class_id = int(box.cls[0])
object_name = self.model.names[class_id]
box_color_rgb = colors(class_id, bgr=False)
hex_color_hex = f"#{box_color_rgb[0]:02x}{box_color_rgb[1]:02x}{box_color_rgb[2]:02x}"
detected_objects.append((object_name, hex_color_hex))
self.current_objects = detected_objects
self.after(3000, lambda: self.update_objects_list)
img = Image.fromarray(results[0].plot())
w, h = self.video_label.winfo_width(), self.video_label.winfo_height()
if w < 10: w, h = 640, 480
ctk_img = ctk.CTkImage(light_image=img, dark_image=img, size=(w, h))
self.video_label.configure(image=ctk_img)
self.video_label._image = ctk_img
self.after(20, self.update_frame)
ctk.set_appearance_mode('dark')
ctk.set_default_color_theme('blue')
app = CameraApp()
app.mainloop()
Автор: Евгений Морковин




0 комментариев
Оставьте комментарий
Комментарии