Перейти к содержимому
OPENCV НА PYTHON | Часть 1 | БАЗОВЫЕ ЗНАНИЯ

OPENCV НА PYTHON | Часть 1 | БАЗОВЫЕ ЗНАНИЯ

УЧЕБНОЕ ПОСОБИЕ ПО OPEN CV НА PYTHON 3.13 (часть 1)

Содержание

Урок 1: Введение в компьютерное зрение и базовые понятия

1.1 Что такое изображение в цифровом виде?

Суть задачи: Понимание фундаментальной структуры изображений для работы с ними в OpenCV.

Теоретическая основа:

  • Изображение представляет собой матрицу (массив) пикселей
  • Каждый пиксель содержит информацию о цвете или яркости
  • Разрешение изображения определяется количеством пикселей по ширине и высоте:
    • VGA: 640×480 пикселей
    • HD: 1280×720 пикселей
    • Full HD: 1920×1080 пикселей

Типы изображений:

  1. Бинарное изображение - содержит только два значения:
    • 0 = черный цвет
    • 1 = белый цвет
    • Применяется для простых масок и базовой сегментации
  2. Изображение в градациях серого - использует 8-битное представление:
    • Диапазон значений: 0-255
    • 0 = абсолютный черный
    • 255 = абсолютный белый
    • 254 промежуточных оттенка серого
    • Формат: (высота × ширина)
  3. Цветное изображение (RGB/BGR) - состоит из трех каналов:
    • В OpenCV используется порядок BGR (Blue, Green, Red), а не RGB
    • Каждый канал содержит значения от 0 до 255
    • Формат: (высота × ширина × 3 канала)
Практическое значение: Понимание структуры изображений необходимо для выбора правильных методов обработки и преобразования данных.

1.2 Среда разработки

Суть задачи: Подготовка рабочего окружения для разработки приложений компьютерного зрения.

Необходимые инструменты:

  • Python 3.13
  • PyCharm Community Edition (бесплатная IDE)
  • Библиотеки: OpenCV, NumPy

Пошаговая инструкция:

  1. Скачиваем Python с официального сайта python.org
    • Важно отметить галочку "Add Python to PATH" во время установки
  2. Устанавливаем PyCharm Community Edition:
    • Скачиваем с jetbrains.com/pycharm
    • Ассоциируем .py файлы с PyCharm
    • Добавляем лаунчер в PATH
  3. Создаем виртуальное окружение:
    # В PyCharm: File → New Project → Python
    # Выбираем интерпретатор Python 3.13
  4. Устанавливаем необходимые библиотеки:
    pip install opencv-python numpy

Проверка установки:

import cv2
import numpy as np

print("OpenCV версия:", cv2.__version__)
print("NumPy версия:", np.__version__)
print("Пакеты успешно импортированы!")
Важные замечания:
  • OpenCV (cv2) - основная библиотека для компьютерного зрения
  • NumPy (np) - библиотека для работы с многомерными массивами, необходима для математических операций с изображениями
  • Версия Python влияет на совместимость некоторых функций OpenCV

Урок 2: Чтение и отображение изображений, видео и работа с веб-камерой

2.1 Чтение и отображение изображений

Суть задачи: Научиться загружать изображения из файлов и выводить их на экран для визуализации.

Используемые методы:

  • cv2.imread(path) - загружает изображение из файла
    • Параметр path - путь к файлу изображения
    • Возвращает объект изображения в формате BGR
    • Если файл не найден, возвращает None (не вызывает исключение!)
  • cv2.imshow(window_name, image) - отображает изображение в окне
    • window_name - название окна для отображения
    • image - объект изображения для отображения
    • Создает окно с заданным именем и показывает в нем изображение
  • cv2.waitKey(delay) - ожидает нажатия клавиши
    • delay - время ожидания в миллисекундах (0 = бесконечно)
    • Возвращает код нажатой клавиши
    • Обязательно вызывать после imshow для отображения изображения

Практический пример:

import cv2

# Чтение изображения из файла
img = cv2.imread('resources/lena.png')

# Проверка успешности загрузки
if img is None:
    print("Ошибка: изображение не найдено!")
else:
    # Отображение изображения
    cv2.imshow('Output', img)
    
    # Ожидание нажатия клавиши (0 - бесконечное ожидание)
    cv2.waitKey(0)
    
    # Закрытие всех окон OpenCV
    cv2.destroyAllWindows()
Важные особенности:
  • OpenCV использует цветовое пространство BGR вместо RGB
  • Путь к файлу может быть относительным или абсолютным
  • Функция destroyAllWindows() освобождает все ресурсы, связанные с окнами OpenCV

2.2 Работа с видео

Суть задачи: Научиться загружать и обрабатывать видеофайлы кадр за кадром.

Используемые методы:

  • cv2.VideoCapture(source) - создает объект для захвата видео
    • source - путь к видеофайлу или ID камеры
    • Возвращает объект VideoCapture
  • cap.read() - считывает следующий кадр из видео
    • Возвращает кортеж (success, image)
    • success - булево значение, указывающее на успешность чтения
    • image - объект изображения (кадр)
  • cap.isOpened() - проверяет, успешно ли открыт источник видео
  • cap.release() - освобождает ресурсы видеоисточника

Практический пример:

import cv2

# Захват видео из файла
cap = cv2.VideoCapture('resources/test_video.mp4')

# Проверка успешности открытия
if not cap.isOpened():
    print("Ошибка: не удалось открыть видеофайл")
    exit()

while True:
    # Чтение кадра
    success, img = cap.read()
    
    # Проверка успешности чтения кадра
    if not success:
        print("Видео закончилось или произошла ошибка")
        break
    
    # Отображение кадра
    cv2.imshow('Video', img)
    
    # Выход при нажатии клавиши 'q'
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# Очистка ресурсов
cap.release()
cv2.destroyAllWindows()
Важные особенности:
  • cv2.waitKey(1) с параметром 1 мс обеспечивает плавное воспроизведение
  • 0xFF == ord('q') гарантирует корректную работу на 64-битных системах
  • Видео обрабатывается в цикле while, что позволяет обрабатывать каждый кадр

2.3 Работа с веб-камерой

Суть задачи: Научиться получать изображения с веб-камеры в реальном времени.

Используемые методы:

  • cv2.VideoCapture(0) - подключение к веб-камере (ID 0 - камера по умолчанию)
  • cap.set(propId, value) - установка параметров камеры:
    • propId = 3 - ширина кадра
    • propId = 4 - высота кадра
    • propId = 10 - яркость
    • propId = 15 - контрастность

Практический пример:

import cv2

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

# Проверка подключения камеры
if not cap.isOpened():
    print("Ошибка: не удалось подключиться к веб-камере")
    exit()

# Установка параметров камеры
cap.set(3, 640)  # Ширина (ID параметра 3)
cap.set(4, 480)  # Высота (ID параметра 4)
cap.set(10, 100)  # Яркость (ID параметра 10)

print(f"Разрешение камеры: {cap.get(3)}x{cap.get(4)}")
print(f"Яркость: {cap.get(10)}")

while True:
    success, img = cap.read()
    
    if not success:
        print("Ошибка: не удалось получить кадр с камеры")
        break
    
    cv2.imshow('Webcam', img)
    
    # Выход при нажатии клавиши 'q'
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# Очистка ресурсов
cap.release()
cv2.destroyAllWindows()
Важные особенности:
  • ID камеры начинается с 0 (основная камера), 1 (вторая камера) и т.д.
  • Параметры камеры могут варьироваться в зависимости от модели и драйверов
  • Важно всегда вызывать cap.release() для корректного закрытия камеры
  • Разрешение камеры влияет на производительность и качество обработки

Урок 3: Базовые функции обработки изображений

3.1 Конвертация цветовых пространств

Суть задачи: Научиться преобразовывать изображения между различными цветовыми пространствами для решения конкретных задач.

Используемые методы:

  • cv2.cvtColor(src, code) - конвертация цветового пространства
    • src - исходное изображение
    • code - код преобразования:
      • cv2.COLOR_BGR2GRAY - BGR в градации серого
      • cv2.COLOR_BGR2HSV - BGR в HSV (Hue, Saturation, Value)
      • cv2.COLOR_GRAY2BGR - градации серого в BGR

Практический пример:

import cv2

# Чтение изображения
img = cv2.imread('resources/lena.png')

# Конвертация в градации серого
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Отображение результатов
cv2.imshow('Original', img)
cv2.imshow('Gray Image', imgGray)
cv2.waitKey(0)
cv2.destroyAllWindows()
Важные особенности:
  • Конвертация в градации серого уменьшает размер данных в 3 раза (1 канал вместо 3)
  • HSV цветовое пространство лучше подходит для детектирования цветов
  • Порядок каналов в OpenCV - BGR, а не RGB (важно при работе с другими библиотеками)

3.2 Размытие изображения (Gaussian Blur)

Суть задачи: Научиться применять размытие для уменьшения шума и деталей в изображении.

Используемые методы:

  • cv2.GaussianBlur(src, ksize, sigmaX) - гауссово размытие
    • src - исходное изображение
    • ksize - размер ядра (кортеж (width, height)), должен быть нечетным
    • sigmaX - стандартное отклонение по оси X (0 - автоматический расчет)

Практический пример:

import cv2
import numpy as np

# Чтение изображения
img = cv2.imread('resources/lena.png')
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Применение гауссова размытия
imgBlur = cv2.GaussianBlur(imgGray, (7, 7), 0)  # (7, 7) - размер ядра

# Отображение результатов
cv2.imshow('Gray Image', imgGray)
cv2.imshow('Blur Image', imgBlur)
cv2.waitKey(0)
cv2.destroyAllWindows()
Важные особенности:
  • Размер ядра (ksize) влияет на степень размытия: чем больше ядро, тем сильнее размытие
  • Размер ядра должен быть нечетным (3, 5, 7, 9...) для симметричного размытия
  • Размытие уменьшает шум и высокочастотные детали, что полезно перед детектированием границ
  • Ядро 3×3 дает легкое размытие, 7×7 - сильное размытие

3.3 Детектирование границ (Canny Edge Detection)

Суть задачи: Научиться выделять границы объектов на изображении для последующего анализа.

Используемые методы:

  • cv2.Canny(image, threshold1, threshold2) - детектирование границ методом Canny
    • image - исходное изображение (лучше использовать размытое изображение)
    • threshold1 - нижний порог градиента
    • threshold2 - верхний порог градиента
    • Соотношение threshold2/threshold1 обычно 2:1 или 3:1

Практический пример:

import cv2

# Чтение изображения
img = cv2.imread('resources/lena.png')

# Детектирование границ
imgCanny = cv2.Canny(img, 100, 100)  # Базовые пороги

# Улучшенная версия с размытием перед детектированием
imgBlur = cv2.GaussianBlur(img, (7, 7), 0)
imgCannyEnhanced = cv2.Canny(imgBlur, 50, 150)

# Отображение результатов
cv2.imshow('Original', img)
cv2.imshow('Canny Basic', imgCanny)
cv2.imshow('Canny Enhanced', imgCannyEnhanced)
cv2.waitKey(0)
cv2.destroyAllWindows()
Важные особенности:
  • Алгоритм Canny использует градиенты яркости для нахождения границ
  • Низкие пороги (50, 150) дают больше границ, высокие (200, 300) - меньше границ
  • Размытие перед детектированием уменьшает шум и ложные границы
  • Результат детектирования - бинарное изображение (0 и 255)

Урок 4: Морфологические операции

4.1 Дилатация (утолщение границ)

Суть задачи: Научиться увеличивать толщину объектов на бинарных изображениях для соединения разорванных частей.

Используемые методы:

  • cv2.dilate(src, kernel, iterations) - дилатация изображения
    • src - исходное изображение (обычно результат Canny)
    • kernel - структурирующий элемент (матрица из единиц)
    • iterations - количество итераций (степень дилатации)
  • np.ones(shape, dtype) - создание матрицы из единиц
    • shape - размер матрицы (высота, ширина)
    • dtype - тип данных (np.uint8 для изображений)

Практический пример:

import cv2
import numpy as np

# Чтение изображения
img = cv2.imread('resources/lena.png')
imgCanny = cv2.Canny(img, 100, 100)

# Создание ядра для дилатации
kernel = np.ones((5, 5), np.uint8)  # Матрица 5x5 из единиц

# Применение дилатации
imgDilation = cv2.dilate(imgCanny, kernel, iterations=1)

# Усиленная дилатация
imgDilationStrong = cv2.dilate(imgCanny, kernel, iterations=3)

# Отображение результатов
cv2.imshow('Canny Image', imgCanny)
cv2.imshow('Dilation (1 iteration)', imgDilation)
cv2.imshow('Dilation (3 iterations)', imgDilationStrong)
cv2.waitKey(0)
cv2.destroyAllWindows()
Важные особенности:
  • Дилатация "раздувает" белые области на бинарном изображении
  • Размер ядра влияет на радиус "раздувания" на каждой итерации
  • Количество итераций определяет степень дилатации
  • Полезно для соединения разорванных границ и заполнения маленьких дыр

4.2 Эрозия (утончение границ)

Суть задачи: Научиться уменьшать толщину объектов на бинарных изображениях для удаления мелких деталей и шума.

Используемые методы:

  • cv2.erode(src, kernel, iterations) - эрозия изображения
    • Параметры аналогичны функции дилатации
    • Эффект противоположен дилатации - "сжигает" края белых областей

Практический пример:

import cv2
import numpy as np

# Чтение изображения
img = cv2.imread('resources/lena.png')
imgCanny = cv2.Canny(img, 100, 100)
kernel = np.ones((5, 5), np.uint8)

# Применение дилатации
imgDilation = cv2.dilate(imgCanny, kernel, iterations=1)

# Применение эрозии к результату дилатации
imgEroded = cv2.erode(imgDilation, kernel, iterations=1)

# Отображение результатов
cv2.imshow('Canny Image', imgCanny)
cv2.imshow('Dilation Image', imgDilation)
cv2.imshow('Eroded Image', imgEroded)
cv2.waitKey(0)
cv2.destroyAllWindows()
Важные особенности:
  • Эрозия уменьшает белые области на бинарном изображении
  • Эффективна для удаления мелких шумов и изолированных пикселей
  • При последовательном применении дилатации и эрозии получается операция "открытия"
  • При последовательном применении эрозии и дилатации получается операция "закрытия"
  • Эти операции являются базовыми в математической морфологии

Урок 5: Изменение размера и обрезка изображений

5.1 Изменение размера изображения

Суть задачи: Научиться изменять размеры изображений для стандартизации входных данных или адаптации к требованиям задачи.

Используемые методы:

  • cv2.resize(src, dsize, fx, fy, interpolation) - изменение размера изображения
    • src - исходное изображение
    • dsize - целевой размер (ширина, высота)
    • fx, fy - коэффициенты масштабирования (альтернатива dsize)
    • interpolation - метод интерполяции (по умолчанию cv2.INTER_LINEAR)
  • img.shape - получение размеров изображения
    • Возвращает кортеж (высота, ширина, количество каналов)
    • Для градаций серого: (высота, ширина)

Практический пример:

import cv2

# Чтение изображения
img = cv2.imread('resources/lambo.png')

# Получение и вывод размеров изображения
print("Размер исходного изображения:", img.shape)  # (высота, ширина, каналы)

# Изменение размера (ширина, высота)
imgResize = cv2.resize(img, (300, 200))  # Новые размеры: ширина=300, высота=200

# Увеличение размера (может привести к потере качества)
# imgResize = cv2.resize(img, (1000, 500))

# Проверка нового размера
print("Размер измененного изображения:", imgResize.shape)

# Отображение результатов
cv2.imshow('Original Image', img)
cv2.imshow('Resized Image', imgResize)
cv2.waitKey(0)
cv2.destroyAllWindows()
Важные особенности:
  • В OpenCV порядок размеров: сначала ширина, потом высота (в отличие от shape)
  • Методы интерполяции:
    • cv2.INTER_LINEAR - билинейная (по умолчанию, хороша для уменьшения)
    • cv2.INTER_CUBIC - бикубическая (качественная для увеличения)
    • cv2.INTER_NEAREST - ближайший сосед (быстро, но низкое качество)
  • Увеличение размера не добавляет новой информации, только интерполирует существующую
  • Соотношение сторон может измениться, что приведет к искажению изображения

5.2 Обрезка изображения

Суть задачи: Научиться вырезать области интереса из изображений для фокусировки на конкретных объектах.

Используемые методы:

  • Индексирование массивов NumPy: img[y1:y2, x1:x2]
    • y1:y2 - диапазон по вертикали (высота)
    • x1:x2 - диапазон по горизонтали (ширина)
    • Важно: сначала идет координата y (строки), потом x (столбцы)

Практический пример:

import cv2

# Чтение изображения
img = cv2.imread('resources/lambo.png')

# Обрезка изображения [начало_высоты:конец_высоты, начало_ширины:конец_ширины]
imgCropped = img[0:200, 200:500]  # [y1:y2, x1:x2]

# Визуализация точек обрезки на исходном изображении
img_with_rect = img.copy()
cv2.rectangle(img_with_rect, (200, 0), (500, 200), (0, 255, 0), 2)
cv2.putText(img_with_rect, "Область обрезки", (220, 30), 
            cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)

# Отображение результатов
cv2.imshow('Original Image with Crop Area', img_with_rect)
cv2.imshow('Cropped Image', imgCropped)
cv2.waitKey(0)
cv2.destroyAllWindows()
Важные особенности:
  • В OpenCV начало координат (0,0) находится в левом верхнем углу
  • Ось X идет вправо, ось Y идет вниз
  • Индексирование использует систему координат NumPy: сначала строки (y), потом столбцы (x)
  • Обрезка не изменяет исходное изображение, создает новое
  • Размеры обрезанного изображения: (y2-y1, x2-x1, каналы)

Урок 6: Рисование фигур и текста на изображениях

6.1 Создание изображений и рисование базовых фигур

Суть задачи: Научиться создавать изображения и рисовать на них геометрические фигуры для аннотации и визуализации.

Используемые методы:

  • np.zeros(shape, dtype) - создание черного изображения
    • shape - размеры изображения (высота, ширина, каналы)
    • dtype - тип данных (np.uint8 для 8-битных изображений)
  • cv2.line(img, pt1, pt2, color, thickness) - рисование линии
    • pt1, pt2 - начальная и конечная точки (x, y)
    • color - цвет в формате BGR (255, 0, 0) для синего
    • thickness - толщина линии
  • cv2.rectangle(img, pt1, pt2, color, thickness) - рисование прямоугольника
    • pt1 - верхний левый угол (x1, y1)
    • pt2 - нижний правый угол (x2, y2)
    • thickness = cv2.FILLED для заполнения прямоугольника
  • cv2.circle(img, center, radius, color, thickness) - рисование круга
    • center - центр круга (x, y)
    • radius - радиус круга в пикселях

Практический пример:

import cv2
import numpy as np

# Создание черного изображения (512x512 пикселей, 3 канала)
img = np.zeros((512, 512, 3), np.uint8)

# Рисование линии (изображение, начальная точка, конечная точка, цвет, толщина)
cv2.line(img, (0, 0), (img.shape[1], img.shape[0]), (0, 255, 0), 3)  # Зеленая диагональ

# Рисование прямоугольника (изображение, верхний левый угол, нижний правый угол, цвет, толщина)
cv2.rectangle(img, (0, 0), (250, 350), (0, 0, 255), 2)  # Красный прямоугольник с контуром

# Заполненный прямоугольник
cv2.rectangle(img, (300, 0), (512, 150), (255, 0, 0), cv2.FILLED)  # Синий заполненный прямоугольник

# Рисование круга (изображение, центр, радиус, цвет, толщина)
cv2.circle(img, (450, 50), 30, (255, 255, 0), 5)  # Голубой круг с контуром

# Отображение результата
cv2.imshow('Drawing Shapes', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Важные особенности:
  • Цвета в OpenCV задаются в формате BGR, а не RGB
  • Толщина -1 или cv2.FILLED означает заполнение фигуры
  • Координаты точек задаются как (x, y), где (0,0) - левый верхний угол
  • img.shape[1] - ширина изображения, img.shape[0] - высота
  • Все функции рисования изменяют исходное изображение

6.2 Добавление текста на изображения

Суть задачи: Научиться добавлять текстовые аннотации на изображения для информативности и отладки.

Используемые методы:

  • cv2.putText(img, text, org, fontFace, fontScale, color, thickness) - добавление текста
    • text - текстовая строка для отображения
    • org - начальная точка текста (нижний левый угол первого символа)
    • fontFace - тип шрифта:
      • cv2.FONT_HERSHEY_SIMPLEX - простой пропорциональный шрифт
      • cv2.FONT_HERSHEY_PLAIN - компактный шрифт
      • cv2.FONT_HERSHEY_COMPLEX - более сложный шрифт
    • fontScale - масштаб шрифта (1.0 = нормальный размер)
    • thickness - толщина штрихов символов

Практический пример:

import cv2
import numpy as np

# Создание черного изображения
img = np.zeros((512, 512, 3), np.uint8)

# Добавление текста с разными параметрами
cv2.putText(img, "OpenCV", (100, 100), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (255, 255, 255), 3)
cv2.putText(img, "Font Scale 0.5", (100, 150), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
cv2.putText(img, "Font Scale 2.0", (100, 200), cv2.FONT_HERSHEY_SIMPLEX, 2.0, (0, 0, 255), 2)
cv2.putText(img, "FONT_HERSHEY_PLAIN", (100, 250), cv2.FONT_HERSHEY_PLAIN, 2, (255, 0, 255), 2)
cv2.putText(img, "Thickness Demo", (100, 300), cv2.FONT_HERSHEY_COMPLEX, 1, (255, 255, 0), 1)
cv2.putText(img, "Thickness 5", (100, 350), cv2.FONT_HERSHEY_COMPLEX, 1, (255, 0, 0), 5)

# Отображение результата
cv2.imshow('Text on Image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Важные особенности:
  • Начальная точка (org) определяет позицию нижнего левого угла первого символа
  • fontScale влияет на размер шрифта: 1.0 = стандартный размер
  • thickness влияет на жирность шрифта
  • Различные шрифты имеют разную читаемость и внешний вид
  • Текст добавляется поверх существующих элементов изображения
  • Для русских символов могут потребоваться дополнительные настройки или использование PIL

Урок 7: Перспективные преобразования и объединение изображений

7.1 Изменение перспективы (Bird Eye View)

Суть задачи: Научиться преобразовывать перспективу изображений для получения вида сверху (плана) искаженных объектов.

Используемые методы:

  • cv2.getPerspectiveTransform(src, dst) - вычисление матрицы перспективного преобразования
    • src - координаты четырех точек в исходном изображении (numpy массив)
    • dst - координаты четырех точек в целевом изображении (numpy массив)
    • Возвращает матрицу преобразования 3×3
  • cv2.warpPerspective(src, M, dsize) - применение перспективного преобразования
    • M - матрица преобразования от getPerspectiveTransform
    • dsize - размер выходного изображения (ширина, высота)

Практический пример:

import cv2
import numpy as np

# Чтение изображения с картой
img = cv2.imread('resources/cards.jpg')

# Определение четырех угловых точек карты на исходном изображении (координаты подбираются вручную)
# Порядок точек: верхний левый, верхний правый, нижний левый, нижний правый
pts1 = np.float32([[111, 219], [287, 188], [154, 482], [352, 440]])

# Определение целевых точек для результата (прямоугольник стандартных размеров)
width, height = 250, 350  # Стандартные размеры игральной карты
pts2 = np.float32([[0, 0], [width, 0], [0, height], [width, height]])

# Получение матрицы преобразования перспективы
matrix = cv2.getPerspectiveTransform(pts1, pts2)
print("Матрица преобразования:")
print(matrix)

# Применение преобразования перспективы
imgOutput = cv2.warpPerspective(img, matrix, (width, height))

# Визуализация исходных точек на оригинальном изображении
img_with_points = img.copy()
for i, point in enumerate(pts1):
    x, y = int(point[0]), int(point[1])
    cv2.circle(img_with_points, (x, y), 8, (0, 0, 255), cv2.FILLED)
    cv2.putText(img_with_points, f"Point {i+1}", (x+10, y), 
                cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)

# Отображение результатов
cv2.imshow('Original Image with Points', img_with_points)
cv2.imshow('Warped Image (Bird Eye View)', imgOutput)
cv2.waitKey(0)
cv2.destroyAllWindows()
Важные особенности:
  • Порядок точек в pts1 и pts2 должен соответствовать друг другу
  • Точки должны быть указаны в формате float32
  • Для подбора точек можно использовать программы вроде Paint или специальные инструменты OpenCV
  • Результат преобразования - прямоугольное изображение без перспективных искажений
  • Применяется в сканерах документов, системах распознавания номеров, AR-приложениях

7.2 Объединение изображений

Суть задачи: Научиться объединять несколько изображений в одно для удобства сравнения и анализа.

Простой метод (без масштабирования):

import cv2
import numpy as np

# Чтение изображений
img = cv2.imread('resources/lena.png')

# Горизонтальное объединение (требует одинаковой высоты)
imgHor = np.hstack((img, img))  # numpy.hstack для горизонтального стека

# Вертикальное объединение (требует одинаковой ширины)
imgVer = np.vstack((img, img))  # numpy.vstack для вертикального стека

# Отображение результатов
cv2.imshow('Horizontal Stack', imgHor)
cv2.imshow('Vertical Stack', imgVer)
cv2.waitKey(0)
cv2.destroyAllWindows()

Универсальный метод (с масштабированием и разными каналами):

import cv2
import numpy as np

def stackImages(scale, imgArray):
    """
    Функция для объединения изображений с возможностью масштабирования
    и обработки изображений с разным количеством каналов.
    
    Args:
        scale (float): Коэффициент масштабирования
        imgArray (list): Массив изображений (может быть 2D массивом для сетки)
    
    Returns:
        numpy.ndarray: Объединенное изображение
    """
    rows = len(imgArray)
    cols = len(imgArray[0])
    rowsAvailable = isinstance(imgArray[0], list)
    width = imgArray[0][0].shape[1]
    height = imgArray[0][0].shape[0]
    
    if rowsAvailable:
        for x in range(0, rows):
            for y in range(0, cols):
                if imgArray[x][y].shape[:2] == imgArray[0][0].shape[:2]:
                    imgArray[x][y] = cv2.resize(imgArray[x][y], (0, 0), None, scale, scale)
                else:
                    imgArray[x][y] = cv2.resize(imgArray[x][y], (imgArray[0][0].shape[1], imgArray[0][0].shape[0]), None, scale, scale)
                if len(imgArray[x][y].shape) == 2:
                    imgArray[x][y] = cv2.cvtColor(imgArray[x][y], cv2.COLOR_GRAY2BGR)
        
        imageBlank = np.zeros((height, width, 3), np.uint8)
        hor = [imageBlank] * rows
        
        for x in range(0, rows):
            hor[x] = np.hstack(imgArray[x])
        
        ver = np.vstack(hor)
    else:
        for x in range(0, rows):
            if imgArray[x].shape[:2] == imgArray[0].shape[:2]:
                imgArray[x] = cv2.resize(imgArray[x], (0, 0), None, scale, scale)
            else:
                imgArray[x] = cv2.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None, scale, scale)
            if len(imgArray[x].shape) == 2:
                imgArray[x] = cv2.cvtColor(imgArray[x], cv2.COLOR_GRAY2BGR)
        
        hor = np.hstack(imgArray)
        ver = hor
    
    return ver

# Использование функции
img = cv2.imread('resources/lena.png')
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
imgBlur = cv2.GaussianBlur(imgGray, (7, 7), 0)
imgCanny = cv2.Canny(img, 100, 100)

# Создание сетки изображений 2x2
imgStack = stackImages(0.5, (
    [img, imgGray],
    [imgBlur, imgCanny]
))

# Отображение результата
cv2.imshow('Stacked Images Grid', imgStack)
cv2.waitKey(0)
cv2.destroyAllWindows()
Важные особенности:
  • Простой метод (hstack/vstack) требует одинаковых размеров и количества каналов
  • Универсальная функция stackImages автоматически:
    • Масштабирует изображения
    • Конвертирует градации серого в BGR для совместимости
    • Поддерживает создание сеток изображений (2D массивы)
  • Параметр scale позволяет уменьшать изображения для размещения большего количества в одном окне
  • Функция обрабатывает изображения с разным количеством каналов (RGB и градации серого)
  • Пригодно для отладки и визуализации промежуточных результатов обработки

Заключение по базовому курсу:

В этом учебном пособии мы рассмотрели основные функции OpenCV для работы с изображениями и видео. Полученные знания позволяют:

  • Читать и отображать изображения и видео
  • Применять базовые операции обработки (конвертация цветов, размытие, детектирование границ)
  • Выполнять морфологические операции (дилатация, эрозия)
  • Изменять размеры и обрезать изображения
  • Рисовать геометрические фигуры и текст
  • Преобразовывать перспективу и объединять изображения

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

 

ЧЕК-ЛИСТ ПО 1 ЧАСТИ: ОСНОВЫ OPEN CV

Установка и настройка среды

Задача
Установлен Python
Установлен PyCharm Community Edition
Настроены пути (PATH) для Python и PyCharm
Создан виртуальный проект в PyCharm
Установлены необходимые библиотеки: opencv-python, numpy
Проведена проверка установки импортом библиотек и выводом версий

Понимание базовых концепций изображений

Задача
Понимаю, что такое пиксель и как он представлен в цифровом виде
Знаю разницу между типами изображений:
  • Бинарное изображение (0 и 1)
  • Изображение в градациях серого (0-255)
  • Цветное изображение BGR (3 канала)
Знаю стандартные разрешения: VGA (640×480), HD (1280×720), Full HD (1920×1080)
Понимаю, что в OpenCV используется цветовое пространство BGR, а не RGB

Работа с изображениями

Задача
Могу загружать изображение с помощью cv2.imread()
Могу отображать изображение с помощью cv2.imshow()
Использую cv2.waitKey(0) для задержки отображения
Знаю, как закрыть окна с помощью cv2.destroyAllWindows()
Проверяю успешность загрузки изображения (обработка случая, когда файл не найден)

Работа с видео

Задача
Могу создать объект для захвата видео с помощью cv2.VideoCapture()
Знаю, как считывать кадры с помощью cap.read()
Понимаю структуру возвращаемого значения (success, img)
Использую цикл while для обработки видео покадрово
Знаю, как добавить выход из цикла по нажатию клавиши 'q'
Освобождаю ресурсы с помощью cap.release() после окончания работы

Работа с веб-камерой

Задача
Могу подключиться к веб-камере с помощью cv2.VideoCapture(0)
Знаю, как установить параметры камеры:
Ширина кадра cap.set(3, width)
Высота кадра cap.set(4, height)
Яркость cap.set(10, brightness)
Проверяю успешность подключения камеры с помощью cap.isOpened()
Применяю зеркальное отображение при необходимости cv2.flip(img, 1)

Базовые функции обработки изображений

Задача
Конвертация цветовых пространств
Могу конвертировать BGR в градации серого cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
Понимаю преимущества работы с изображениями в градациях серого
Размытие изображений
Применяю гауссово размытие cv2.GaussianBlur(img, (ksize, ksize), sigmaX)
Знаю, что размер ядра должен быть нечетным (3, 5, 7...)
Понимаю влияние размытия на качество детектирования границ
Детектирование границ
Использую алгоритм Canny cv2.Canny(img, threshold1, threshold2)
Знаю, как подбирать оптимальные пороговые значения
Понимаю, что размытие перед детектированием улучшает результат
Морфологические операции
Создаю ядро для морфологических операций np.ones((5,5), np.uint8)
Применяю дилатацию cv2.dilate(img, kernel, iterations)
Применяю эрозию cv2.erode(img, kernel, iterations)
Понимаю практическое применение этих операций

Изменение размера и обрезка изображений

Задача
Знаю, как получить размеры изображения img.shape
Могу изменить размер изображения cv2.resize(img, (width, height))
Понимаю разницу в порядке параметров (resize: ширина→высота; shape: высота→ширина)
Могу обрезать изображение с помощью индексации img[y1:y2, x1:x2]
Знаю особенности системы координат в OpenCV (начало в левом верхнем углу)

Рисование на изображениях

Задача
Могу создать черное изображение np.zeros((height, width, 3), np.uint8)
Рисую линии cv2.line(img, pt1, pt2, color, thickness)
Рисую прямоугольники cv2.rectangle(img, pt1, pt2, color, thickness)
Рисую заполненные прямоугольники (thickness=cv2.FILLED или -1)
Рисую окружности cv2.circle(img, center, radius, color, thickness)
Добавляю текст cv2.putText(img, text, org, font, scale, color, thickness)
Знаю основные шрифты OpenCV:
  • cv2.FONT_HERSHEY_SIMPLEX
  • cv2.FONT_HERSHEY_PLAIN
  • cv2.FONT_HERSHEY_COMPLEX

Практические навыки

Задача
Создал проект с чтением изображения, применением базовых преобразований и отображением результатов
Реализовал программу для захвата видео с веб-камеры с возможностью выхода по клавише 'q'
Написал программу, которая рисует геометрические фигуры и текст на изображении
Создал функцию для объединения изображений в одну визуализацию
Реализовал базовую обработку изображения (серый → размытие → границы → дилатация)

Понимание ключевых концепций

Задача
Понимаю систему координат в OpenCV (ось Y направлена вниз)
Знаю, как работает цветовое пространство BGR в OpenCV
Понимаю, что изображение в OpenCV — это NumPy массив
Знаю, как правильно освобождать ресурсы после работы с видео и камерой
Понимаю важность предварительной обработки изображений перед детектированием объектов

Общие замечания для самопроверки

Задача
Все импорты библиотек выполнены корректно (import cv2, import numpy as np)
Все окна OpenCV закрываются после завершения программы
Проверяю существование файлов перед их чтением
Обрабатываю возможные ошибки при работе с камерой
Использую понятные имена переменных
Добавляю комментарии к коду для объяснения ключевых шагов
Протестировал все функции на разных изображениях
Понимаю, как работают параметры в каждой функции OpenCV

```

Понедельник, 22 декабря 2025
OPENCV НА PYTHON | Часть 1 | БАЗОВЫЕ ЗНАНИЯ