Размытие, резкость и шумоподавление
Меняя ядро свёртки, мы получаем целое семейство эффектов: сгладить, подчеркнуть, очистить от шума.
Шум — случайные отклонения яркости пикселей, не относящиеся к самому объекту (зернистость при слабом свете, артефакты сенсора).
Резкость: усилить отличие от соседей
Резкость — почти противоположность размытию. Ядро резкости даёт большой положительный вес центру и отрицательные соседям: пиксель усиливается там, где он сильно отличается от окружения (на границах). Применим ядро резкости к картинке с яркой точкой по центру (используем 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 — настоящее значение фона. Поэтому против «соли и перца» берут медиану, а не усреднение.
Итог
- Резкость — ядро с большим центром и отрицательными краями; подчёркивает перепады.
- Гауссово размытие взвешивает соседей по расстоянию — мягче простого усреднения.
- Импульсный шум («соль и перец») лучше всего убирает медианный фильтр.
- Медиана устойчива к выбросам, среднее — нет.