Компьютерное зрение
Фильтрация и свёртка
Цели урока
- Понимать операцию свёртки: kernel, padding, stride - формула размера выхода
- Выбирать правильный тип blur для конкретного типа шума
- Применять Canny edge detection с правильными параметрами порогов
- Строить pipeline морфологических операций для очистки бинарных масок
Предварительные знания
Yann LeCun и первая практическая CNN
1989 год. Yann LeCun в Bell Labs обучает LeNet-5 - свёрточную нейросеть для распознавания рукописных цифр для почтовой службы США (USPS). Революционное решение: вместо полносвязных слоёв - ядра свёртки 5x5 с общими весами. Это дало не просто меньше параметров - это дало инвариантность к позиции. Та же цифра в разных позициях изображения - одно и то же ядро. К 1998 году LeNet обрабатывал 10-20% чеков в США. В 2012 году его идеи лежали в основе AlexNet, который переломил историю ImageNet.
2015 год. ResNet-152: 3.57% ошибка на ImageNet - лучше человека (5.1%). 152 слоя. Один trick: residual connections. Сегодня DALL-E 3, Stable Diffusion, Tesla Autopilot - всё стоит на свёрточных архитектурах. А в основе - матрица 3x3, скользящая по изображению. Та же идея, что Yann LeCun применил в 1989 году.
- **Portrait Mode в смартфонах** - Gaussian blur по маске, вычисленной нейросетью. Каждый раз когда фото делается - свёртка 30-40 раз подряд
- **Tesla Autopilot** - Canny edge detection + Hough transform для разметки дороги, 30 кадров в секунду на 8 камерах
- **OCR (Google Lens, Apple Live Text)** - морфологические операции соединяют рваные буквы, убирают пятна со сканов перед нейросетью
- **DALL-E 3 и Stable Diffusion** - свёрточный энкодер сжимает изображение в latent space перед diffusion process
Операция свёртки (Convolution)
1989 год. Yann LeCun в Bell Labs обучает LeNet на рукописных цифрах для почтовой службы США. Ключевое решение: вместо полносвязного слоя - **ядро свёртки**, матрица 5x5, которая скользит по изображению. Те же числа, те же веса - на каждой позиции. Это дало в 10 раз меньше параметров и первую в мире практическую нейросеть для CV. Сегодня ядра свёртки внутри iPhone Portrait Mode, Tesla Autopilot и DALL-E 3.
**Padding** решает проблему краёв: при скольжении ядра 3x3 крайние пиксели не имеют соседей. **Same padding** (zero padding) - дополнение нулями, выход того же размера. **Valid** - без дополнения, выход уменьшается. **Stride** - шаг сдвига ядра (обычно 1). В CNN: stride=2 заменяет pooling для уменьшения разрешения.
Реализация с циклами на Python - **катастрофически медленная** (секунды на одно изображение). OpenCV вызывает оптимизированный C++ код: `cv2.filter2D(img, -1, kernel)` - в тысячи раз быстрее. Писать свёртку руками только для понимания механики.
Ядро определяет **что именно** делает свёртка. Все единицы - усреднение (blur). Центр положительный, окружение отрицательное - обнаружение границ. Гауссиана - размытие без артефактов. Одна операция, бесконечное множество эффектов. CNN учит ядра автоматически из данных - это и есть главное достижение глубокого обучения в CV.
К изображению 100x100 применяется свёртка ядром 5x5 без padding (valid). Каков размер выхода?
Размытие и шумоподавление
Парадокс: размытие - одна из самых полезных операций CV. Оно убирает шум (случайные колебания яркости), сглаживает текстуры перед обнаружением границ, уменьшает количество деталей. Без blur: Canny edge detector на зашумлённом изображении находит тысячи ложных границ. С blur: только реальные контуры. Harris, SIFT, Canny - все начинают с Gaussian blur.
**Averaging blur** - самый простой: ядро из одинаковых значений. Каждый пиксель заменяется средним соседей. Размывает всё одинаково, включая границы - поэтому на практике используется редко. **Gaussian blur** - золотой стандарт: веса распределены по колоколообразной кривой Гаусса, центральный пиксель вносит наибольший вклад.
| Фильтр | Ядро | Лучше всего для | Сохраняет границы? |
|---|---|---|---|
| Averaging | Все значения = 1/N2 | Быстрое предпросмотрование | Нет |
| Gaussian | Веса по Гауссиане | Общее шумоподавление | Частично |
| Median | Медиана соседей | Salt-and-pepper noise | Да! |
| Bilateral | Gaussian + учёт яркости | Шумоподавление с сохранением границ | Да |
В pipeline CV **Gaussian blur почти всегда идёт первым шагом**. Canny edge detector, Harris corner detector, SIFT - все начинают с размытия. Параметр **sigma** контролирует силу размытия: sigma=1 - лёгкое, sigma=10 - агрессивное.
На фото с камеры видеонаблюдения много шума типа salt-and-pepper (случайные чёрные и белые точки). Какой фильтр справится лучше?
Обнаружение границ: Sobel и Canny
Tesla Autopilot обрабатывает 8 видеопотоков в реальном времени. Первая задача - найти разметку, бордюры, силуэты объектов. Это **границы**: места резкого перепада яркости. Для алгоритма граница = место, где **градиент** (скорость изменения яркости) максимален. Два ядра свёртки 3x3 - это всё, что нужно для первичного детектирования.
**Sobel** - простейший детектор: два ядра 3x3, одно находит горизонтальные градиенты (Gx), другое - вертикальные (Gy). Полный градиент: G = sqrt(Gx^2 + Gy^2).
**Canny** - gold standard edge detection, John Canny, 1986. Не просто один фильтр, а **pipeline из 4 шагов**, каждый из которых решает конкретную проблему Sobel: Gaussian blur (убрать шум) - Sobel (найти градиент) - Non-maximum suppression (истончить до 1 пикселя) - Hysteresis thresholding (убрать слабые изолированные края).
**Hysteresis thresholding** - главная фишка Canny. Два порога вместо одного: низкий порог - много шума, высокий - рваные контуры. Canny берёт лучшее из обоих: сильные границы находит высоким порогом, затем дотягивает слабые участки вдоль контура. Практическое правило: high:low = 2:1 или 3:1.
В Canny edge detection non-maximum suppression нужна для того, чтобы:
Морфологические операции
OCR-системы (Google Lens, Tesseract, Apple Live Text) работают с бинарными масками. После порогового сегментирования текста - дырки внутри букв, мелкий шум, рваные контуры. **Морфологические операции** - инструменты для чистки. Они работают со **структурным элементом** (small kernel), который определяет форму окрестности.
Две базовые операции: **erosion** (эрозия) - если хотя бы один пиксель под ядром = 0, результат = 0. Объекты сжимаются, мелкие точки исчезают. **Dilation** (расширение) - если хотя бы один пиксель = 1, результат = 1. Объекты расширяются, дырки заполняются.
**Opening** = erosion -> dilation. Убирает мелкий шум (erosion удаляет точки), затем восстанавливает размер объектов (dilation). **Closing** = dilation -> erosion. Заполняет дырки и щели (dilation расширяет), затем возвращает контур (erosion сжимает). Стандартный pipeline для очистки масок OCR: сначала opening, потом closing.
| Операция | Формула | Эффект | Применение |
|---|---|---|---|
| Erosion | Сжатие | Объекты уменьшаются | Удаление тонких связей, шума |
| Dilation | Расширение | Объекты увеличиваются | Заполнение дырок, объединение |
| Opening | Erode -> Dilate | Удаление мелких объектов | Очистка от шума |
| Closing | Dilate -> Erode | Заполнение дырок | Замыкание контуров |
| Gradient | Dilate - Erode | Контур объекта | Обводка, outline |
**Морфологический градиент** (`MORPH_GRADIENT`) = dilation - erosion. Результат - контур объекта толщиной, пропорциональной размеру ядра. Быстрая альтернатива Canny для бинарных масок.
Свёртка (convolution) и корреляция (correlation) - одно и то же
Математически свёртка переворачивает ядро на 180° перед применением (отражение по обеим осям). Корреляция применяет ядро как есть. Для симметричных ядер (Gaussian, averaging) разницы нет. Для несимметричных (Sobel) - разница существенна.
OpenCV и большинство deep learning фреймворков реализуют корреляцию, но называют её convolution. Настоящая математическая свёртка используется в signal processing. При конструировании ядра для конкретного направления - помнить, что cv2.filter2D() выполняет корреляцию.
Есть бинарная маска: внутри объекта - мелкие чёрные дырки, вокруг - мелкие белые точки-шум. Какой pipeline применить?
Ключевые идеи
- **Свёртка** - одна операция (kernel x область), но разные ядра дают разные эффекты: blur, edge detection, резкость. Yann LeCun применил эту идею в 1989 - она лежит в основе всего modern CV
- **Blur** убирает шум и готовит к анализу. Gaussian - универсальный, Median - для salt-and-pepper, Bilateral - когда нужно сохранить границы
- **Canny** = 4-шаговый pipeline (blur - gradient - NMS - hysteresis). Два порога решают дилемму шум vs рваные контуры. Правило 2:1 или 3:1
- **Морфология** чистит бинарные маски: opening убирает шум, closing заполняет дырки. OCR, медицинские сканеры, детекция объектов - везде этот pipeline
- **CNN в 2024** учит ядра автоматически - но понимание Sobel, Gaussian, Canny помогает интерпретировать, что нейросеть выучила
Связанные темы
Свёртка - мост между пикселями и высокоуровневым пониманием изображений:
- Цифровое изображение: пиксели и цвет — Свёртка работает с массивами пикселей - без понимания координат и типов данных невозможно правильно сконструировать ядро
- Признаки: SIFT, SURF, ORB — Feature detectors используют Gaussian blur для scale-space и Sobel для градиентов
Вопросы для размышления
- Почему Canny edge detector начинается с размытия, хотя размытие уничтожает детали? Не противоречит ли это цели - найти границы?
- Если CNN учат ядра свёртки автоматически - зачем знать Sobel и Canny? В каких ситуациях классические фильтры надёжнее?
- Морфологические операции работают с бинарными масками. Но что если объект имеет полупрозрачные края (alpha gradient)? Как адаптировать pipeline?
Связанные уроки
- cv-01 — Пиксели, координаты и типы данных - фундамент для свёртки
- cv-03 — Feature detectors SIFT и ORB используют Gaussian blur и градиенты внутри
- dl-05 — CNN изучают ядра свёртки автоматически - это развитие ручных фильтров
- aie-25-multimodal — DALL-E 3 и Stable Diffusion используют свёрточные энкодеры внутри
- cv-04 — Обнаружение и отслеживание объектов строится на edge detection и морфологии
- la-06-transformations