Уявіть: ви хочете розробити додаток із комп’ютерним зором, який матиме гарний графічний інтерфейс. Звучить просто? Але коли ви починаєте налаштовувати середовище, встановлювати залежності та конфігурувати взаємодію OpenCV з графічним інтерфейсом, простота швидко зникає. А що, якщо ваш додаток повинен працювати на різних операційних системах?
Саме тут на допомогу приходить контейнеризація. У цій статті ми дослідимо, як створити потужний комбінований інструмент, що об’єднує:
- OpenCV для завдань комп’ютерного зору
- PyQt5 для створення професійних GUI-інтерфейсів
- Qt Designer для візуального проєктування інтерфейсу
- Docker для стабільної роботи в будь-якому середовищі
І все це з автоматичною компіляцією UI-файлів, підтримкою камери та готовністю до розширення.
Навіщо нам контейнеризація для GUI-додатків?
Багато розробників звикли використовувати Docker для веб-додатків або сервісів без графічного інтерфейсу. Але контейнеризація GUI-додатків має свої переваги:
- Однакове середовище — незалежно від того, чи ви працюєте на Windows, macOS або Linux
- Прості залежності — не потрібно турбуватися про конфлікти версій OpenCV та PyQt5
- Відтворюваність — ваш додаток працюватиме однаково на будь-якій машині
- Ізоляція — проблеми з додатком не вплинуть на вашу основну систему
- Зручність розповсюдження — упакуйте все необхідне в один контейнер
Що отримуємо в результаті
Наш комбінований інструмент дозволяє:
- Розробляти інтерфейс візуально через Qt Designer
- Працювати з відеопотоками та камерами через OpenCV
- Автоматично компілювати
.uiфайли у Python-код - Запускати все це в ізольованому середовищі через Docker
- Розгортати на будь-якій машині з мінімальними вимогами
Структура проєкту
Ось як виглядає структура нашого проєкту:
/app
├— Dockerfile # Інструкція створення контейнера
├— docker-compose.yml # Файл для зручного запуску через Docker Compose
├— entrypoint.sh # Скрипт запуску додатка або Qt Designer
├— compile_ui.sh # Скрипт компіляції усіх .ui файлів
├— mainwindow.ui # Графічний інтерфейс (Qt Designer)
├— ui_mainwindow.py # Згенерований Python-файл із UI
└— simple_app.py # Основний код додатка
Ця проста структура забезпечує гнучкість при розробці та розширенні вашого додатку.
Створення Docker-контейнера
Давайте розглянемо ключові частини нашого Dockerfile, який встановлює все необхідне:
FROM ubuntu:20.04
# Встановлення без запитів (non-interactive)
ENV DEBIAN_FRONTEND=noninteractive
# Встановлення необхідних пакетів
RUN apt-get update && apt-get install -y \
python3 \
python3-pip \
python3-pyqt5 \
qttools5-dev-tools \
x11-apps \
libx11-xcb1 \
libpulse0 \
libxcb-icccm4 \
libxcb-image0 \
libxcb-keysyms1 \
libxcb-randr0 \
libxcb-render-util0 \
libxcb-xinerama0 \
libxcb-xkb1 \
libxkbcommon-x11-0 \
&& apt-get clean
# Встановлення Python-залежностей
COPY requirements.txt /tmp/
RUN pip3 install --no-cache-dir -r /tmp/requirements.txt
# Додавання скриптів для запуску
COPY entrypoint.sh compile_ui.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/entrypoint.sh /usr/local/bin/compile_ui.sh
# Створення робочої директорії
WORKDIR /app
# Запуск додатку або Qt Designer при старті контейнера
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
Файл docker-compose.yml спрощує запуск і налаштування:
version: '3'
services:
opencv-qt-tutorial:
build: .
volumes:
- .:/app
- /tmp/.X11-unix:/tmp/.X11-unix
environment:
- DISPLAY=${DISPLAY}
devices:
- /dev/video0:/dev/video0
command: python3 simple_app.py
Зверніть увагу на монтування X11-сокету та передачу змінної DISPLAY — це ключові моменти для роботи графічного інтерфейсу з Docker.
Робота з Qt Designer всередині контейнера
Одна з найцікавіших можливостей нашого проєкту — це робота з Qt Designer безпосередньо з контейнера. Qt Designer — це потужний візуальний інструмент для створення UI, і ми можемо запустити його через Docker.
Для запуску Qt Designer виконайте:
docker compose exec opencv-qt-tutorial designer
або
docker compose run --rm opencv-qt-tutorial designer
Це запустить Qt Designer, де ви можете візуально створювати інтерфейс, додавати кнопки, поля введення, мітки та інші елементи. Після закінчення роботи просто збережіть .ui файл у директорії проєкту.
Автоматична компіляція UI-файлів
Традиційно після створення .ui файлу вам потрібно вручну конвертувати його у Python-код за допомогою pyuic5. Але ми автоматизували цей процес!
Ось як виглядає наш скрипт compile_ui.sh:
#!/bin/bash
set -e
echo "Компіляція UI файлів..."
# Шукаємо всі .ui файли в поточній директорії
for ui_file in *.ui; do
# Перевіряємо, чи файл існує (щоб уникнути обробки шаблону "*.ui" якщо немає .ui файлів)
if [ -f "$ui_file" ]; then
# Отримуємо ім'я файлу без розширення
filename=$(basename -- "$ui_file")
filename="${filename%.*}"
# Компілюємо .ui в .py файл
echo "Компіляція $ui_file в ui_$filename.py"
pyuic5 -x "$ui_file" -o "ui_$filename.py"
fi
done
echo "Компіляція завершена!"
Цей скрипт автоматично запускається при старті контейнера, знаходячи всі .ui файли та генеруючи відповідні Python-файли. Тепер вам не потрібно запам’ятовувати команду pyuic5 або турбуватися про те, які файли потребують оновлення!
Запуск додатку
Запустити додаток так само просто, як виконати:
# Дозвіл для X-сервера
xhost +local:docker
# Запуск з docker-compose
docker-compose up --build
Наш контейнер скомпілює всі .ui файли і запустить simple_app.py. Якщо ви внесли зміни в UI через Qt Designer, вони будуть автоматично враховані.
Після завершення роботи не забудьте відкликати дозволи:
docker compose down
xhost -local:docker
Розробка практичного додатку
Тепер давайте подивимося, як створити простий додаток, який використовує камеру та OpenCV для обробки зображення.
Ось приклад простого PyQt5-додатку з використанням OpenCV:
import sys
import cv2
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtCore import QTimer
from PyQt5.QtGui import QImage, QPixmap
from ui_mainwindow import Ui_MainWindow
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
# Ініціалізація камери
self.capture = cv2.VideoCapture(0)
# Створення таймера для оновлення кадрів
self.timer = QTimer()
self.timer.timeout.connect(self.update_frame)
self.timer.start(30) # 30ms -> ~33 кадри/с
# Підключення кнопок
self.ui.btnGrayscale.clicked.connect(self.toggle_grayscale)
self.ui.btnBlur.clicked.connect(self.toggle_blur)
# Прапорці для фільтрів
self.grayscale_enabled = False
self.blur_enabled = False
def update_frame(self):
ret, frame = self.capture.read()
if ret:
# Застосування фільтрів
if self.grayscale_enabled:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)
if self.blur_enabled:
frame = cv2.GaussianBlur(frame, (15, 15), 0)
# Конвертація у формат Qt
rgb_image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
h, w, ch = rgb_image.shape
bytes_per_line = ch * w
q_image = QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888)
self.ui.labelCamera.setPixmap(QPixmap.fromImage(q_image))
def toggle_grayscale(self):
self.grayscale_enabled = not self.grayscale_enabled
self.ui.btnGrayscale.setText(
"Вимк. ч/б" if self.grayscale_enabled else "Увімк. ч/б"
)
def toggle_blur(self):
self.blur_enabled = not self.blur_enabled
self.ui.btnBlur.setText(
"Вимк. розмиття" if self.blur_enabled else "Увімк. розмиття"
)
def closeEvent(self, event):
self.capture.release()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Цей приклад демонструє:
- Захоплення відео з камери
- Перетворення кадрів OpenCV у формат, сумісний з PyQt5
- Застосування простих фільтрів (чорно-білий, розмиття)
- Обробку подій інтерфейсу
Корисні команди
Ось зведена таблиця найбільш корисних команд для роботи з проєктом:
| Операція | Команда |
|---|---|
| Побудувати контейнер | docker-compose build |
| Запустити додаток | docker-compose up |
| Запустити Qt Designer | docker-compose run --rm opencv-qt-tutorial designer |
| Перекомпілювати .ui | docker compose exec opencv-qt-tutorial /usr/local/bin/compile_ui.sh |
| Зупинити і видалити контейнер | docker-compose down |
| Дозвіл для X-сервера | xhost +local:docker |
| Відкликати дозвіл X-сервера | xhost -local:docker |
Можливі проблеми та їх вирішення
Проблема: Графічний інтерфейс не відображається
Вирішення:
- Переконайтеся, що ви виконали
xhost +local:docker - Перевірте, чи правильно передано змінну середовища
DISPLAYуdocker-compose.yml - Перевірте, чи коректно змонтовано директорію
/tmp/.X11-unix
Проблема: Камера не працює в контейнері
Вирішення:
- Перевірте, чи правильно вказано пристрій у
docker-compose.yml:devices: - /dev/video0:/dev/video0 - Якщо у вас кілька камер, можливо, потрібно вказати інший пристрій (наприклад,
/dev/video1)
Проблема: Зміни в UI не відображаються в додатку
Вирішення:
- Перевірте, чи коректно скомпільовано
.uiфайли - Спробуйте вручну запустити
compile_ui.sh - Перезапустіть контейнер
Перспективи розвитку
Що можна додати до цього проєкту в майбутньому:
- Розширені фільтри OpenCV — додавання більшої кількості фільтрів для обробки зображення
- Розпізнавання об’єктів — інтеграція моделей машинного навчання для виявлення об’єктів
- Підтримка декількох камер — можливість працювати з кількома камерами одночасно
- Збереження відео — функціональність запису та збереження відео з застосованими фільтрами
- Обробка відеофайлів — можливість обробляти не лише потік з камери, а й завантажені відеофайли
Висновки
Поєднання OpenCV, PyQt5 і Docker створює потужне середовище для розробки додатків комп’ютерного зору з професійним графічним інтерфейсом. Цей підхід має багато переваг:
- Простота налаштування — не потрібно встановлювати все вручну
- Переносимість — працює на будь-якій системі з Docker
- Зручність розробки — візуальне проєктування інтерфейсу з Qt Designer
- Автоматизація — автоматична компіляція UI-файлів
- Ізоляція — проблеми з залежностями ізольовані в контейнері
Такий підхід особливо корисний для навчальних проєктів, швидкого прототипування та створення кросплатформених додатків комп’ютерного зору.
Спробуйте цей інструмент для своїх проєктів — і ви відкриєте новий рівень зручності та ефективності розробки!
Цей проєкт доступний під ліцензією MIT, що дозволяє вільно використовувати, модифікувати та розповсюджувати код за умови збереження зазначення авторства.