Конволюція: одна операція, сотні фільтрів
Ядро конволюції – це невеликий сітка чисел – часто 3x3 або 5x5 – яка ковзає по кожному пікселю зображення. На кожній позиції воно множить кожне значення ядра на відповідне значення пікселя, сумує ці добутки та записує цю суму як нове значення центрального пікселя. Розмиття, покращення різкості, вигравіювання та виявлення країв – це всі одна й та сама ковзна операція вікна; лише числа в ядрі змінюються.
output(x,y) = Σ Σ kernel(i,j) · input(x+i, y+j) for i,j in the kernel's footprint 3x3 box blur kernel (each weight = 1/9): 3x3 sharpen kernel: 1/9 1/9 1/9 0 -1 0 1/9 1/9 1/9 -1 5 -1 1/9 1/9 1/9 0 -1 0
Розмиття Гауса: зважування сусідніх пікселів за відстанню
Розмиття коробкою (з рівними вагами) згладжує зображення, але створює видимі квадратні артефакти. Розмиття Гаусса замість цього зважує сусідні пікселі за функцією 2D Гауssівського (нормального розподілу), тому пікселі, близькі до центру, мають більшу вагу, ніж віддалені, що забезпечує природне розмиття без напрямлених артефактів:
G(x, y) = (1 / (2πσ²)) · exp( -(x² + y²) / (2σ²) σ (сигма) контролює радіус розмиву – більша σ = ширший ядро = сильніше розмиття. Оскільки 2D Гауssівська функція є роздільною – вона точно розкладається на горизонтальну 1D Гауssівську функцію, помножену на вертикальну 1D Гауssівську функцію – реалізація ніколи не обчислює повний 2D ядро. Вона згладжує кожен рядок за допомогою 1D проходу, а потім згладжує кожен стовпець результату таким самим 1D проходом, перетворюючи вартість O(k²) на піксель у O(2k), тому розмиття Гаусса залишається швидким навіть при великих радіусах.
G(x, y) = (1 / (2πσ²)) · exp( -(x² + y²) / (2σ²) ) σ (sigma) controls the blur radius — larger σ = wider kernel = stronger blur
Sobel: перетворення зміни інтенсивності на карту країв
Край, за визначенням, є місце, де швидка змінюється інтенсивність пікселів. Оператор Собеля (1968) приблизно оцінює градієнт зображення за допомогою двох невеликих ядер, одне чутливе до горизонтальних змін, а інше – до вертикальних:
Gx (горизонтальний градієнт): Gy (вертикальний градієнт): -1 0 +1 -1 -2 -1 -2 0 +2 0 0 0 -1 0 +1 +1 +2 +1 масштаб краю = sqrt(Gx² + Gy²) напрямок краю = atan2(Gy, Gx) Застосовуючи обидва ядра до кожного пікселя та об'єднуючи їх, отримують карту міцності країв, яка світиться там, де інтенсивність різко змінюється в будь-якому напрямку – основа для більш складного детектора країв Канні, який спочатку додає розмиття Гаусса (щоб приглушити шум, оскільки шум виглядає як невеликі штучні краї для Собеля), потім застосовує не максимальне придушення, щоб звузити краї до ліній з одним пікселем, а також використовує гістотезу з двома пороговими значеннями, щоб підтримувати лише справжні ланцюги пов'язаних країв.
Gx (horizontal gradient): Gy (vertical gradient): -1 0 +1 -1 -2 -1 -2 0 +2 0 0 0 -1 0 +1 +1 +2 +1 edge magnitude = sqrt(Gx² + Gy²) edge direction = atan2(Gy, Gx)
Коли швидше фільтрувати в частотному діапазоні
Пряме згортвання n-піксельної зображення з ядром розміром k x k коштує O(n · k²) – кожен вихідний піксель потребує k² множень і додавання. Теорема згортання стверджує, що згортка в просторовому діапазоні еквівалентна простий елемент-відмінній операції в частотному діапазоні, тому зображення можна трансформувати за допомогою 2D Швидкого Перетворення Фур'є (O(n log n)), помножити його на власну трансформацію ядра та повернути назад. Для невеликого ядра Sobel розміром 3x3 це не вигідно – постійний надлишок трьох FFT домінує – але для великих ядер, приблизно шириною 20-30 пікселів, фільтрація на основі FFT стає значно швидшою, оскільки її вартість не зростає разом із розміром ядра, як це відбувається у випадку з прямим згортванням.
Frequently asked questions
Чому оператор Соболя використовує дві ядрові функції замість однієї?
Оскільки край може проходити в будь-якому напрямку, а одна ядрова функція реагує сильніше лише на градієнти, вирівняні з нею. Собол використовує одну ядрову функцію, оптимізовану для горизонтальних змін інтенсивності (Gx), та іншу – для вертикальних змін (Gy), а потім об’єднує їх, щоб отримати незалежну від напрямку міцність краю: величина = sqrt(Gx^2 + Gy^2), та atan2(Gy, Gx) для відновлення орієнтації краю, якщо це необхідно.
Чому використовують розмиття Гаусса для зменшення шуму перед виявленням країв?
Виявники країв працюють шляхом посилення швидких змін інтенсивності, а випадковий шум пікселів також є швидкою, високочастотною зміною. Тому безпосереднє застосування оператора Соболя або подібної функції до шуканого зображення призводить до поля хибних, невеликих ‘країв’, спричинених шумом, що маскує справжні. Розмиття Гаусса – це фільтр низьких частот: воно згладжує високочастотний шум, зберігаючи при цьому справжні, більші за розміром краї, тому майже кожен практичний виявник країв, включаючи алгоритм Канні, спочатку розмиває зображення.
Коли швидше фільтрувати зображення за допомогою FFT замість прямої конволюції?
Пряма конволюція коштує O(n·k^2) для зображення розміром n пікселів та ядра розміру k×k, тоді як фільтрація на основі FFT коштує O(n log n), незалежно від розміру ядра, оскільки конволюція в просторовій області стає простим множенням у частотній області. Для невеликих ядер, таких як оператор Соболя 3×3, пряма конволюція виграє, оскільки постійні витрати на дві FFT та зворотну FFT не варті плати; для великих ядер, приблизно понад 20-30 пікселів у ширину, підхід на основі FFT стає швидшим.
Спробуйте наживо
Усе, що вище, працює прямо у вашому браузері — відкрийте Image Filters і змінюйте параметри під час роботи. Нічого не встановлюється, нічого не завантажується на сервер, уся модель живе в одній вкладці.
▶ Відкрити симуляцію Image Filters