Размытие, резкость и шумоподавление

Меняя ядро свёртки, мы получаем целое семейство эффектов: сгладить, подчеркнуть, очистить от шума.

Шум — случайные отклонения яркости пикселей, не относящиеся к самому объекту (зернистость при слабом свете, артефакты сенсора).

Резкость: усилить отличие от соседей

Резкость — почти противоположность размытию. Ядро резкости даёт большой положительный вес центру и отрицательные соседям: пиксель усиливается там, где он сильно отличается от окружения (на границах). Применим ядро резкости к картинке с яркой точкой по центру (используем clamp, чтобы остаться в 0..255).

def clamp(v):
    return max(0, min(255, v))

def conv2d(image, kernel, divisor=1):
    H, W = len(image), len(image[0])
    pad = len(kernel) // 2
    out = []
    for y in range(pad, H - pad):
        row = []
        for x in range(pad, W - pad):
            acc = 0
            for ky in range(len(kernel)):
                for kx in range(len(kernel)):
                    acc += image[y - pad + ky][x - pad + kx] * kernel[ky][kx]
            row.append(clamp(round(acc / divisor)))
        out.append(row)
    return out

image = [
    [50, 50, 50, 50, 50],
    [50, 50, 50, 50, 50],
    [50, 50, 200, 50, 50],
    [50, 50, 50, 50, 50],
    [50, 50, 50, 50, 50],
]
sharpen = [
    [ 0, -1,  0],
    [-1,  5, -1],
    [ 0, -1,  0],
]

print("Резкость:")
for r in conv2d(image, sharpen):
    print(r)

Вывод:

Резкость:
[50, 0, 50]
[0, 255, 0]
[50, 0, 50]

Яркая точка (200) стала ещё ярче (255 после обрезки), а соседи вокруг провалились в 0 — контраст на границе подчёркнут. Так работает усиление резкости: оно акцентирует перепады.

Гауссово размытие против простого

Простое усреднение даёт всем соседям равный вес — картинка размывается, но появляются грубые «прямоугольные» артефакты. Гауссово размытие взвешивает соседей по расстоянию: ближние важнее дальних. Ядро напоминает «колокол». Результат мягче и естественнее, поэтому в OpenCV почти всегда используют именно его.

# Идея: ядро Гаусса 3x3 (веса больше к центру)
[1, 2, 1]
[2, 4, 2]   делитель = 16
[1, 2, 1]

Шум и медианный фильтр

Особый враг — импульсный шум («соль и перец»): отдельные пиксели стали чисто белыми или чёрными. Усреднение тут плохо: оно размазывает белую точку по соседям, оставляя серое пятно. Лучше работает медианный фильтр: он берёт окрестность, сортирует значения и выбирает среднее по порядку (медиану). Одиночный выброс просто отбрасывается.

import statistics

# окрестность 3x3 вокруг пикселя, в центре — «соль» (255)
neighborhood = [48, 52, 50, 51, 255, 49, 50, 47, 53]

avg = round(statistics.mean(neighborhood))
med = statistics.median(neighborhood)
print("Среднее (размывает выброс):", avg)
print("Медиана (убирает выброс):  ", med)

Вывод:

Среднее (размывает выброс): 73
Медиана (убирает выброс):   50

Среднее «заразилось» выбросом 255 и подскочило до 73, исказив пиксель. Медиана же дала 50 — настоящее значение фона. Поэтому против «соли и перца» берут медиану, а не усреднение.

Итог

  • Резкость — ядро с большим центром и отрицательными краями; подчёркивает перепады.
  • Гауссово размытие взвешивает соседей по расстоянию — мягче простого усреднения.
  • Импульсный шум («соль и перец») лучше всего убирает медианный фильтр.
  • Медиана устойчива к выбросам, среднее — нет.
Проверьте себя
1. Почему медианный фильтр лучше усреднения против шума «соль и перец»?
AОн работает быстрее
BОн выбирает медиану окрестности и просто отбрасывает одиночный выброс, а не размазывает его
CОн повышает разрешение
DОн добавляет цвет
2. Чем гауссово размытие отличается от простого усреднения?
AОно делает картинку резче
BОно взвешивает соседей по расстоянию (ближние важнее), давая более мягкий результат
CОно не использует ядро
DОно работает только с цветом
3. Что характерно для ядра повышения резкости?
AВсе веса равны
BБольшой положительный вес в центре и отрицательные у соседей
CВсе веса нулевые
DТолько один вес по углу
Поддержать проект