Зазвичай виявлення країв зводиться до виявлення областей зображення з високим значенням градієнта.
У нашому випадку ми можемо грубо бачити градієнт як похідну від функції зображення, тому величина градієнта дає вам інформацію про те, наскільки ваше зображення змінюється локально (щодо сусідніх пікселів / текселів).
Тепер, край, як ви говорите, свідчить про переривання, тож тепер, коли ми визначили градієнт, зрозуміло, що ця інформація - це все, що нам потрібно. Як тільки ми знайдемо градієнт зображення, це лише питання застосування порогу до нього, щоб отримати бінарне значення край / не-край.
Як ти вважаєш цей градієнт - це справді те, про що ти питаєш, і я ще відповім :)
Багато способів! Ось пара :)
Вбудовані функції шейдера
І hlsl, і glsl пропонують похідні функції. У GLSL у вас є dFdx та dFdy, які дають відповідно інформацію про градієнт у напрямку x та y. Зазвичай ці функції оцінюються в блоці з 2x2 фрагментів.
Якщо ви не зацікавлені в одному напрямку, хороший спосіб отримати компактний результат, який вказує, наскільки сильним є градієнт у регіоні, є ширина, яка не дає нічого іншого, крім суми абсолютного значення dFdy та dFdy.
Вас, швидше за все, цікавить крає зображення в цілому, а не певний канал, тому ви можете перетворити функцію зображення на луму. Зважаючи на це, коли мова йде про виявлення краю, ваш шейдер може включати щось подібне:
float luminance = dot(yourFinalColour,vec3(0.2126, 0.7152, 0.0722));
float gradient = fwidth(luminance );
float isEdge = gradient > threshold;
З високим порогом ви знайдете більш грубі краї, і ви можете пропустити деякі, навпаки, з низьким порогом ви можете виявити помилкові ребра. Ви повинні експериментувати, щоб знайти поріг, який найкраще відповідає вашим потребам.
Причину, по якій ці функції працюють, варто зазначити, але я не маю часу на це зараз, я, ймовірно, оновлюю цю відповідь пізніше :)
Пост-процес на екрані
Ви могли бути фантастичнішим за це, зараз поле виявлення країв в обробці зображень величезне. Я можу навести вам десятки хороших способів виявлення виявлення меж у відповідності з вашими потребами, але давайте продовжимо це просто зараз, якщо ви зацікавлені, я можу запропонувати вам більше варіантів!
Тож ідея була б подібною до наведеної вище, з тією різницею, що ви можете подивитися на ширше околиці та використовувати набір ваг для сортування зразків, якщо хочете. Як правило, ви проводите згортку свого зображення з ядром, що дає в результаті хорошу інформацію про градієнт.
Дуже поширеним вибором є ядро Sobel
Які відповідно дають вам градієнти у напрямку x та y:
GradientMagnitude=(Gradientx)2+(Gradienty)2−−−−−−−−−−−−−−−−−−−−−−−√
Тоді ви можете порогувати так само, як я згадав вище.
Як бачите, це ядро надає більшої ваги центральному пікселю, тому ефективно обчислює градієнт + трохи згладжування, що традиційно допомагає (часто зображення гаусовим розмитим, щоб усунути невеликі краї).
Вищезазначене працює досить добре, але якщо ви не любите згладжування, ви можете використовувати ядра Prewitt:
(Зауважте, що я поспішаю, незабаром напишу належний відформатований текст замість зображень!)
Дійсно, є набагато більше ядер і методів пошуку виявлення країв у процесі зображення, а не в графіці в реальному часі, тому я виключив більш складні (каламбур не призначені) методи, напевно, вам би було добре з функціями dFdx / y .