Створюємо комп’ютерний зір з графічним інтерфейсом у контейнері: OpenCV + PyQt5 + Docker

OpenCV PyQt5 Docker

Уявіть: ви хочете розробити додаток із комп’ютерним зором, який матиме гарний графічний інтерфейс. Звучить просто? Але коли ви починаєте налаштовувати середовище, встановлювати залежності та конфігурувати взаємодію OpenCV з графічним інтерфейсом, простота швидко зникає. А що, якщо ваш додаток повинен працювати на різних операційних системах?

Саме тут на допомогу приходить контейнеризація. У цій статті ми дослідимо, як створити потужний комбінований інструмент, що об’єднує:

  • OpenCV для завдань комп’ютерного зору
  • PyQt5 для створення професійних GUI-інтерфейсів
  • Qt Designer для візуального проєктування інтерфейсу
  • Docker для стабільної роботи в будь-якому середовищі

І все це з автоматичною компіляцією UI-файлів, підтримкою камери та готовністю до розширення.

Навіщо нам контейнеризація для GUI-додатків?

Багато розробників звикли використовувати Docker для веб-додатків або сервісів без графічного інтерфейсу. Але контейнеризація GUI-додатків має свої переваги:

  1. Однакове середовище — незалежно від того, чи ви працюєте на Windows, macOS або Linux
  2. Прості залежності — не потрібно турбуватися про конфлікти версій OpenCV та PyQt5
  3. Відтворюваність — ваш додаток працюватиме однаково на будь-якій машині
  4. Ізоляція — проблеми з додатком не вплинуть на вашу основну систему
  5. Зручність розповсюдження — упакуйте все необхідне в один контейнер
Переваги контейнеризації

Що отримуємо в результаті

Наш комбінований інструмент дозволяє:

  • Розробляти інтерфейс візуально через 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

Для запуску 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 Designerdocker-compose run --rm opencv-qt-tutorial designer
Перекомпілювати .uidocker 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
  • Перезапустіть контейнер

Перспективи розвитку

Що можна додати до цього проєкту в майбутньому:

  1. Розширені фільтри OpenCV — додавання більшої кількості фільтрів для обробки зображення
  2. Розпізнавання об’єктів — інтеграція моделей машинного навчання для виявлення об’єктів
  3. Підтримка декількох камер — можливість працювати з кількома камерами одночасно
  4. Збереження відео — функціональність запису та збереження відео з застосованими фільтрами
  5. Обробка відеофайлів — можливість обробляти не лише потік з камери, а й завантажені відеофайли
Перспективи розвитку

Висновки

Поєднання OpenCV, PyQt5 і Docker створює потужне середовище для розробки додатків комп’ютерного зору з професійним графічним інтерфейсом. Цей підхід має багато переваг:

  • Простота налаштування — не потрібно встановлювати все вручну
  • Переносимість — працює на будь-якій системі з Docker
  • Зручність розробки — візуальне проєктування інтерфейсу з Qt Designer
  • Автоматизація — автоматична компіляція UI-файлів
  • Ізоляція — проблеми з залежностями ізольовані в контейнері

Такий підхід особливо корисний для навчальних проєктів, швидкого прототипування та створення кросплатформених додатків комп’ютерного зору.

Спробуйте цей інструмент для своїх проєктів — і ви відкриєте новий рівень зручності та ефективності розробки!


Цей проєкт доступний під ліцензією MIT, що дозволяє вільно використовувати, модифікувати та розповсюджувати код за умови збереження зазначення авторства.

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *