Чи розділений алгоритм стрибкового потопу?


10

JFA (алгоритм, описаний тут: http://www.comp.nus.edu.sg/~tants/jfa/i3d06.pdf ) може бути використаний для отримання апроксимації діаграми Вороного або перетворення відстані. Це робиться в логарифмічний час виходячи з розміру отриманого зображення, а не від кількості насіння.

Що ви робите, якщо ваше зображення не має однакового розміру на кожній осі?

Якби вони були подібних розмірів, я впевнений, що ви могли б просто дозволити коротшій осі мати додаткові кроки JFA розміром 1, тоді як більша вісь закінчила її роботу (як, наприклад, зображення розміром 512 x 256). Для дуже різних розмірів осей це може бути набагато неефективніше - скажімо, у вас об'ємна текстура, яка була 512 x 512 x 4.

Чи можливо запустити JFA на кожній осі окремо і все-таки отримати гідні результати?

Або в той момент чи інший алгоритм доцільніше використовувати? Якщо так, то який алгоритм це може бути?

В ідеалі в моїй ситуації я прагну підтримувати як насінини в одній точці, так і насіння довільної форми. Можливо, навіть зважене насіння, де відстань до насіння регулюється множником та / або суматором, щоб надати йому більш-менш вплив.

Відповіді:


7

Швидкі відповіді на ваші індивідуальні запитання

Що ви робите, якщо ваше зображення не має однакового розміру на кожній осі?

У роботі використовуються квадратні зображення із довжиною бічних сторін потужністю 2. Це для зручності пояснення, але алгоритм не потрібен. Див. Розділ 3.1:

Не втрачаючи загальності, можна вважати, що n - це сила 2.

Тобто це припущення не потрібно для того, щоб алгоритм працював.

Чи можливо запустити JFA на кожній осі окремо і все-таки отримати гідні результати?

Біг на кожній осі окремо, швидше за все, дасть більше неправильних результатів пікселів, а в більшості випадків потрібно тривати більше часу. У крайніх випадках, коли одна з довгих сторін зображення менша за 8 (кількість напрямків стрибка), це може бути швидше, оскільки алгоритм обробляє ці 8 напрямків послідовно, але для будь-якого більш широкого зображення, розділення осей втрачає перевагу їх обробки паралельно.

В ідеалі в моїй ситуації я прагну підтримувати як насінини в одній точці, так і насіння довільної форми

У статті зазначено насіння довільної форми у розділі 6 під підзаголовком "Узагальнена діаграма Вороного":

... наші алгоритми розглядають такі узагальнені насіння як колекції точкових насіння і, таким чином, розраховуємо успадкувати хороші показники, отримані для точкових насінин.

Отже, якщо це відповідає вашому призначенню для моделювання довільних фігур як колекцій пікселів, вам не потрібно вносити будь-які корективи в алгоритм. Просто подайте текстуру, що позначає всі пікселі насінням довільної форми з однаковим номером насіння, але в різних місцях.

Можливо, навіть зважене насіння, де відстань до насіння регулюється множником та / або суматором, щоб надати йому більш-менш вплив

Для "зважування на насіння, такого як мультиплікативний та добавка", у статті зазначено лише можливість проходження у розділі 8, як потенційна майбутня робота. Однак це слід легко здійснити за умови, що бажане зважування може бути включене до насіннєвих даних, що передаються від пікселя до пікселя.

Поточний алгоритм передається, <s, position(s)>щоб вказати насіння та його положення, і лише один насіння зберігається на піксель у будь-який час. Розширюючи це на зберігання, <s, position(s), weight(s)>надається вся інформація, необхідна для зважування функції відстані та обчислення того, чи буде нове насіння, яке передається пікселю, ближче до нього, ніж те, яке воно зберігає.

Ви навіть можете включити дві ваги, одну мультиплікативну та одну добавку, а також просто встановити мультиплікативний один на 1, а добавку - 0, коли цього не потрібно. Тоді ваш алгоритм буде включати можливість використання для мультиплікативно зважених насіння, адитивно зважених насіння або навіть комбінації одночасно або деяких з кожного. Це було б просто потрібно

<s, position(s), multiplicative(s), additive(s)>

і поточний алгоритм був би еквівалентний цьому новому алгоритму з використанням

<s, position(s), 1, 0>


Детальне пояснення чому

Як і в статті, всі використання стосуються логарифму основи 2.log()

Алгоритм не потрібно адаптувати для різних сторін

Якщо бічні довжини не рівні і не мають потужності 2, не потрібно адаптувати алгоритм. Він вже має справу з пікселями на краю зображення, для яких деякі напрямки стрибка ведуть поза зображенням. Оскільки алгоритм вже опускає насіннєву інформацію для напрямків, які ведуть за межами зображення, ширина або висота, що не є потужністю 2, не будуть проблемою. Для зображення ширини W і висоти H максимальний розмір стрибка буде потрібним

2log(max(W,H))1

У випадку однакової ширини та висоти N це зменшується до

2log(N)1

У разі довжини сторони N, яка є потужністю 2, це зменшується до

2log(N)1=N/2

як використовується в роботі.

Інтуїтивніше, округніть максимальну довжину сторони до наступної потужності 2, а потім вдвічі зменшіть її, щоб отримати максимальний розмір стрибка.

Цього завжди достатньо для покриття кожного пікселя на зображенні від кожного іншого пікселя на зображенні, оскільки зміщення до будь-якого пікселя буде в діапазоні від 0 до N-1, якщо найдовша бічна довжина становить N. Комбінації потужностей 2 від 0 до N / 2 буде охоплювати кожне ціле число до N-1, якщо N - потужність 2, а якщо N не є потужністю 2, обхват, що охоплюється, може бути тільки більшим, ніж потрібно, за рахунок прийняття стелі логарифму ( округлення до наступної сили 2).

Зображення зі сторонами, що не мають потужності 2, не будуть суттєво менш ефективними

Кількість стрибків залежить від найдовшої бічної довжини, скажімо L. Якщо L - потужність 2, то кількість стрибків дорівнює . Якщо L не є потужністю 2, то кількість стрибків дорівнює . Для досить великого зображення це не буде великою різницею.log(L)log(L)

Наприклад, для зображення 1024 на 1024 знадобиться 10 ітерацій стрибка. Для зображення 512 на 512 знадобиться 9 ітерацій стрибка. Що-небудь між двома розмірами також потребує 10 ітерацій. Навіть у гіршому випадку для зображення лише трохи більше 2-х, наприклад зображення 513 на 513, знадобиться лише 1 додаткова ітерація, що в цьому масштабі приблизно на 11% більше (10 замість 9).

Не квадратні зображення менш ефективні на площу

Оскільки кількість необхідних ітерацій визначається найдовшою стороною довжини, час для зображення 1024 на 1024 буде таким самим, як і для зображення 1024 на 16. Квадратне зображення дозволяє охопити більшу площу в однаковій кількості ітерацій.

Розділення осей, ймовірно, знизить якість

У розділі 5 статті описані можливі помилки. Кожен піксель доступний шляхом від кожного іншого пікселя, але деякі шляхи не приносять правильного найближчого насіння, оскільки це насіння не є найближчим до попереднього пікселя в шляху. Кажуть, що піксель, який не дозволяє насінню розмножуватися повз, "убив" це насіння. Якщо найближче насіння до пікселя буде вбито на всіх шляхах до цього пікселя, то піксель буде записувати якесь інше насіння, і в кінцевому зображенні з’явиться неправильний колір.

Потрібно існувати лише один шлях, який не вбиває насіння, щоб остаточний результат був правильним. Неправильні кольори виникають лише тоді, коли всі шляхи від правильного насіння до заданого пікселя заблоковані.

Якщо шлях передбачає чергування горизонтальних і вертикальних стрибків, розділення осей унеможливить цей шлях (всі горизонтальні стрибки будуть зроблені перед усіма вертикальними стрибками, що зробить чергування неможливим). Діагональні стрибки взагалі неможливі. Тож будь-який шлях, який чергується або містить діагональні стрибки, буде виключений. Кожен піксель все ще матиме шлях до кожного іншого пікселя, але оскільки в даний час існує менше шляхів, більше шансів заблокувати певний піксель від отримання правильного насіння, тож кінцевий результат буде більш схильним до помилок.

Розділення осей, ймовірно, змусить алгоритм зайняти більше часу

Ефективність, ймовірно, буде знижена шляхом розділення осей, оскільки затоплення більше не буде проводитися паралельно, а замість цього повториться для кожної осі. Для 2D це, швидше за все, займе приблизно вдвічі довше, а для 3D - приблизно в 3 рази довше.

Це може дещо пом'якшити відсутність діагональних стрибків, але я все одно очікую загального зниження ефективності.


1
Я вже почав експериментувати з цим. Я виявив, що вибірки в знаку + (5 читань) замість повних 9 не показали відмінностей у моєму тестуванні, але я впевнений, що у складніших ситуаціях існують відмінності. Виконання повного x jfa, а потім повного y jfa робить багато помилок. Мені буде цікаво дізнатись більше деталей / інформації, якщо у вас є, але приймаю вашу відповідь: P
Алан Вулф

1
Забув, ось посилання на один з моїх експериментів: shadertoy.com/view/Mdy3D3
Алан Вулф

Цікаво, що він працює так само добре з лише 5 читаннями - тим більше, що вони не можуть бути паралелізовані. Оскільки у статті перераховані випадки, що призводять до помилок, можливо, ви могли б навмисно їх встановити і побачити, чи 5 напрямків стрибка все-таки хороші.
трихоплакс

Здається, ви готові опублікувати власну відповідь ...
trichoplax

моя інформація доповнює вашу: P
Алан Вулф
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.