Выделение границ: градиент яркости и оператор Собеля

Границы объектов — это места, где яркость резко меняется. Найти их — значит найти «контур» картинки.

Граница (edge) — линия в изображении, вдоль которой яркость резко меняется. Математически это место большого градиента яркости.

Почему границы — это градиент

Идём по строке пикселей: 10, 10, 10, 200, 200, 200. Там, где значение скачком меняется с 10 на 200, проходит граница тёмного и светлого. Скорость изменения — это градиент: на ровном участке он близок к нулю, на перепаде — большой. Значит, чтобы найти границы, нужно измерить, насколько резко меняется яркость в каждой точке.

Оператор Собеля

Собель — это пара свёрточных ядер. Одно (Gx) оценивает перепад по горизонтали, другое (Gy) — по вертикали. В каждой точке считаем оба и комбинируем в магнитуду градиента sqrt(Gx**2 + Gy**2): чем она больше, тем «сильнее» граница.

image = [
    [10, 10, 10, 200, 200, 200],
    [10, 10, 10, 200, 200, 200],
    [10, 10, 10, 200, 200, 200],
    [10, 10, 10, 200, 200, 200],
]
Gx = [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]
Gy = [[-1, -2, -1], [0, 0, 0], [1, 2, 1]]

def apply3(img, k, y, x):
    acc = 0
    for ky in range(3):
        for kx in range(3):
            acc += img[y - 1 + ky][x - 1 + kx] * k[ky][kx]
    return acc

H, W = len(image), len(image[0])
print("Магнитуда градиента (Собель):")
for y in range(1, H - 1):
    row = []
    for x in range(1, W - 1):
        gx = apply3(image, Gx, y, x)
        gy = apply3(image, Gy, y, x)
        mag = round((gx * gx + gy * gy) ** 0.5)
        row.append(mag)
    print(row)

Вывод:

Магнитуда градиента (Собель):
[0, 760, 760, 0]
[0, 760, 760, 0]

Смотрите: на ровных участках (тёмная зона слева, светлая справа) магнитуда — 0, а ровно на стыке тёмного и светлого — всплеск 760. Вертикальная граница «загорелась». Если нарисовать магнитуду как картинку, мы увидим контур — линию там, где был перепад.

Почему два ядра

Gx реагирует на вертикальные границы (перепад слева-направо), Gy — на горизонтальные. Объединяя их через магнитуду, детектор находит границы любого направления. Дополнительно по Gx и Gy можно вычислить направление границы — это пригодится продвинутым методам (Canny, HOG).

От Собеля к Canny

Чистый Собель даёт «толстые» и зашумлённые границы. Классический детектор Canny улучшает результат: сначала сглаживает картинку Гауссом (убирает шум), считает градиент, потом утончает границы до линии в один пиксель и отсекает слабые перепады двойным порогом. Результат — аккуратный контур. Но в основе всё та же идея: граница = большой градиент яркости.

Итог

  • Граница — место резкого изменения яркости, то есть большого градиента.
  • Собель — два ядра (Gx, Gy) для горизонтального и вертикального перепадов.
  • Магнитуда sqrt(Gx**2+Gy**2) «загорается» на границах.
  • Canny добавляет сглаживание, утончение и двойной порог поверх той же идеи.
Проверьте себя
1. Что такое граница (edge) с точки зрения математики?
AСамый яркий пиксель
BМесто, где яркость резко меняется, то есть большой градиент
CЦентр изображения
DГраница кадра
2. Зачем оператору Собеля два ядра, Gx и Gy?
AДля ускорения вычислений
BGx ловит перепады по горизонтали, Gy по вертикали — вместе они находят границы любого направления
CОдно для цвета, другое для яркости
DВторое ядро — запасное
3. Что добавляет детектор Canny поверх простого градиента Собеля?
AЦвет
BСглаживание от шума, утончение границ до 1 пикселя и двойной порог
CПоворот изображения
DУвеличение разрешения
Поддержать проект