Алгоритм генерации высот?
Я искал в интернете и не мог найти идеальный алгоритм для этой конкретной проблемы:
наш клиент имеет набор пунктов и данных по веса вместе с каждым пунктом как смогите быть продемонстрировано этим изображением:
взвешенные точки http://chakrit.net/files/stackoverflow/so_heightmap_points.png
из которых у нас есть ГИС-программа, которая может генерировать "карту высоты" или своего рода данные местности из этих точек и их веса но поскольку у нас есть около тысячи точек данных, и они будут меняться со временем, мы хотели бы создать наши собственные инструменты для автоматической генерации этих карт.
до сих пор я пытался рассчитать вес для каждого пикселя с его расстояния до ближайшей точки данных с Sqrt((x1 - x2) ^ 2 + (y1 - y2) ^ 2)
и применение коэффициента веса и расстояния к цвету точки данных для получения результирующего цвета градиента для этого конкретного пикселя:
результат heightmap http://chakrit.net/files/stackoverflow/so_heightmap_result.png
вы можете видеть, что все еще существуют проблемы с определенной конфигурацией точек данных, и алгоритм иногда создает довольно полигональное изображение, когда есть много точек данных. Идеальный результат должен выглядеть больше как многоточие и меньше как многоугольник.
вот один пример изображения из статьи Википедии о градиентном восхождении, который демонстрирует результат I хочу:
горы http://chakrit.net/files/stackoverflow/so_gradient_descent.png
алгоритм градиентного восхождения меня не интересует. Что меня интересует; это алгоритм вычисления исходной функции на этой картинке в первую очередь, при условии данных точек с весами.
Я не брал никакого класса по топологической математике, но я могу сделать некоторые исчисления. Я думаю, что я, возможно, что-то упускаю и довольно потерян в том, что я должен напечатать в этом поле поиска Google.
Мне нужны некоторые указатели.
спасибо!
9 ответов
то, что вы ищете интерполяции поверхности.
некоторые продукты существуют для этого (вот один)
результирующая функция / сплайн / другая математическая конструкция может быть опрошена с требуемым разрешением для предоставления карты высоты.
функции интерполяции
Sqrt((x1 - x2) ^ 2 + (y1 - y2) ^ 2)
похож на Обратное Взвешенное Расстояние методы разве вы претендуете произвольный фильтр и отбрасывая многие другие точки данных.
большинство этих методов опираются на разумное количество образцов и "ландшафтное" поведение, лежащее в основе значений.
Я предлагаю использовать вес в качестве образца высоты и попробовать простой метод Шепарда во второй ссылке (не фильтровать пиксели для начала), взяв долю вклада точек выборки в общее значение высоты в точке интерполяции, вы можете смешать цвета образцов в этих соотношениях, чтобы также цвет точки. Используйте интенсивность (грубо говоря, оттенки серого в простом пространстве RGB) для отображения высоты или добавления контурных линий черным цветом, как это делает пример изображения.
эта проблема не так проста, как кажется на первый взгляд. Ваша проблема в том, что обе стороны границы двух областей должны иметь одинаковую высоту, то есть высота в данном пикселе определяется более чем одним ближайшим соседом.
Если я правильно понимаю, вам нужно как минимум два алгоритма (и третий кусок жаргона).
чтобы сделать это правильно, вам нужно разбить самолет на Вороного тесселяции.
вы вероятно, вы захотите использовать KD-дерево, чтобы помочь вам найти ближайшего соседа. Вместо того, чтобы принимать O(n^2), это приведет его к O(N log(n)) (дополнительное преимущество заключается в том, что ваш этап генерации региона Вороного будет достаточно быстрым в разработке, чтобы работать на этапе расчета высоты).
теперь, когда у вас есть 2-D карта индексирования каждой точки к ближайшему соседу i,вам нужно пройти через каждую точку x, y на карте и рассчитать ее высоту.
сделать что для заданной точки x, y сначала схватите ближайшего соседа i и вставьте его в список, а затем соберите все смежные области на диаграмме Вороного. Простой способ-использовать заливка чтобы найти все точки в регионе, а затем посмотреть вокруг границы и собрать другие идентичности.
используя этот список всех ближайших соседей, теперь у вас есть шанс правильно интерполяции! (См. другие ответы для схем интерполяции).
вы запросили информацию об алгоритмах для 2-D интерполяции нерегулярных данных, что является довольно сложной областью. Поскольку вы говорите, что у вас есть ArcGIS, я советую вы интерполировать автоматически в ArcGIS с помощью встроенного особенности для автоматических расчетов. Я уверен, что это будет легче, чем писать свой собственный алгоритм интерполяции. Я сделал некоторую автоматизацию ArcGIS, это справедливо простой.
Если вы пишете свой собственный код интерполяции-я советую вам не делать этого-первое, что нужно выбрать соответствующий алгоритм, так как есть несколько каждый со своими плюсами и минусами. Вот несколько советов, взятых из справки для отличного инструмента интерполяции серфингист (который BTW можно также автоматизировать довольно легко). Есть больше алгоритмов, это только те, которые я пробовал.
- Кригинга один из более гибкие методы и полезны для gridding почти любой тип набора данных. В большинстве наборов данных Кригинг с линейной вариограммой по умолчанию довольно эффективен. В общем, мы бы чаще всего рекомендовали этот метод. Кригинг является методом сетки по умолчанию, поскольку он создает хорошую карту для большинства наборов данных. Для больших наборов данных, Кригинг может быть довольно медленным. Кригинг может экстраполировать значения сетки за пределами диапазона Z ваших данных.
- обратных взвешенных расстояний быстро, но тенденция генерировать" в яблочко " узоры концентрических контуров вокруг точек данных. Обратное расстояние до мощности не экстраполирует значения Z за пределами диапазона данных. Простой алгоритм взвешивания обратного расстояния прост в реализации, но будет медленным.
- триангуляция с линейной интерполяцией быстро. При использовании небольших наборов данных триангуляция с линейной интерполяцией создает различные треугольные грани между точками данных. Триангуляция с Линейная интерполяция не экстраполирует значения Z за пределы диапазона данных.
- метод Шепарда похоже на обратное расстояние до мощности, но не имеет тенденцию генерировать" бычий глаз", особенно когда используется коэффициент сглаживания. Шепард может экстраполировать значения за пределами диапазона Z ваших данных.
для реализации алгоритмов: вы можете попробовать гуглить или следовать ссылкам в некоторых других ответах. Есть некоторые ГИС-пакеты с открытым исходным кодом, которые включают интерполяцию, поэтому, возможно, вы можете извлечь из них алгоритмы, если вам нравится выбивать через c++. Или книги Дэвид Уотсон, по-видимому, считается классикой, хотя это сложное чтение, и пример кода является спагетти Basic!! Но, судя по тому, что я слышал, это лучшее, что есть. Если кто-то еще в Stack Overflow знает лучше, пожалуйста, исправьте меня, поскольку я тоже не могу в это поверить.
Кригинга является одним из тяжеловесных методов для этого, особенно в области ГИС. Он имеет несколько приятных математических свойств-недостатком является то, что он может быть медленным в зависимости от вашего вариограмм.
Если вы хотите что-то проще, есть много процедур интерполяции, которые обрабатывают это довольно хорошо. Если вы можете получить копию Численные Рецепты Глава 3 посвящена объяснению многих вариантов интерполяция, а также включает примеры кода и описания их функциональных свойств.
- это алгоритм вычисления первоначальная функция в этом изображении в первое место, предоставленные данные баллы с грузами.
это возможно. Если вы начинаете с отдельных точек, вы всегда будете заканчивать кругами, но если вы весите точки данных и учитываете это, вы можете сжать круги в овалы, как на изображении..
причина, по которой вы заканчиваете полигоны, заключается в том, что вы используете дискретную функцию в своем расчете - сначала вы находите ближайший цвет, затем вы определяете цвет.
вместо этого вы должны изучить алгоритмы градиента, которые назначают цвет для точки на основе расстояния и веса от трех точек данных, которые заключают эту точку в треугольник.
градиентЭто зависит от того, что вы пытаетесь отобразить. Упрощенный алгоритм будет:
для каждого пикселя:
- найти три точки, которые образуют наименьший треугольник, который окружает этот пиксель
-
установите эту точку в цвет (цветовая система HSV), который зависит от веса и расстояния до каждой точки данных:
pixel.color = datapoint[1].weight * distance(pixel, datapoint[1]) * datapoint[1].color + datapoint[2].weight * distance(pixel, datapoint[2]) * datapoint[2].color + datapoint[3].weight * distance(pixel, datapoint[3]) * datapoint[3].color
Я использую + здесь, но вам нужно определить алгоритм "усреднения", подходящий для вашего приложения.
Адам
поверхностная интерполяция кажется сложной и математической проблемой. Другой, более дешевый способ сделать это:
For each pixel:
For each point:
pixel.addWeight(weight(point, pixel))
def addWeight(w):
totalweight += w
numberofweights += 1
weight = totalweight / numberofweights
пример весовой функции:
def weight(point, pixel):
return point.weight * 1/(1 + sqrt((point.x - pixel.x)^2 + (point.y - pixel.y)^2))
это довольно грубый подход, но это просто.
я реализовал что-то подобное в Winamp AVS некоторое время назад. Он использует подход типа "metaballs" для вычисления обратного квадратного расстояния (чтобы избежать sqrt для скорости) от каждой точки данных, закрывая ее (например, до 1.0) и принимая сумму этих расстояний для каждой точки на 2D-сетке. Это даст плавно меняющуюся карту цвета/высоты.
Если вы хотите посмотреть код, его в предустановке "Glowy" от my J10 AVS pack.
EDIT: просто глядя на нем я добавил какой-то другой джаз, чтобы он выглядел красивее, самая важная часть:
d1=s/(sqr(px1-rx)+sqr(py1-ry));
d2=s/(sqr(px2-rx)+sqr(py2-ry));
d3=s/(sqr(px3-rx)+sqr(py3-ry));
d4=s/(sqr(px4-rx)+sqr(py4-ry));
d5=s/(sqr(px5-rx)+sqr(py5-ry));
d6=s/(sqr(px6-rx)+sqr(py6-ry));
d=d1+d2+d3+d4+d5+d6;
который принимает сумму за 6 очков. Все остальное, что делается для красных, зеленых и синих выходных значений, - это сделать его красивее. 6 очков не так много, но имейте в виду, что я пытался сделать этот запуск в режиме реального времени на сетке 320x200 на машине 400MHz, когда она была Новой (что она делает в ~20fps). :)
заменить красный = зеленый = синий и = ... линии с красным = д; и т. д... чтобы понять, что я имею в виду. Вся прелесть уходит, и вы остаетесь с изображением оттенков серого плавно меняющихся капель вокруг точек данных.
другое редактирование: я забыл сказать, что " s " - это общий вес для всех точек, изменение его для каждого дает весы, индивидуальные для каждой точки, например, d1 = 2/(...) и d2 = 1 / (...) даст d1 в два раза больше высоты в его центре, чем d2. Вы также можете закрыть выражение внизу чем-то вроде d1 = 2/max(..., 1.0), чтобы сгладить с вершин точек, чтобы они не достигали пика в бесконечности посередине. :)
извините за беспорядок ответа... Я думал, что публикация примера кода будет достаточно хорошей, но при проверке мой код запутан и труден для чтения. :(
Я знаю, это довольно старый вопрос, но я наткнулся на него, пытаясь решить подобную проблему.
есть проект с открытым исходным кодом под названием Surfit, который реализует такую функциональность.
вы ищете что-то, что блендер называет "шары" (статья в Википедии со ссылками, пример). Подумайте об этом так:--9-->
ваши объекты-это конусы, которые торчат из земли. Они все параболы, и вес говорит о том, как далеко они торчат из земли. Альтернативно, сделайте их все такую же высоту и отрегулируйте "плоскостность" параболы соответственно, поэтому большой вес делает конус очень широким пока а низкий вес делает его острым. Может быть, даже и то и другое в определенной степени.
Я предлагаю вам выполнить это и посмотреть, как это выглядит.
Далее, вам нужно повесить ткань или резиновый лист над результатом. Ткань растянется на определенное количество, и она обычно будет висеть из-за силы тяжести. Конусы поддерживают его.
пока вы близки к центру конуса, координата Z-это только положение на поверхности конуса. Как вы выходите из центра конуса, гравитация начинает тянуть вниз, и влияние других конусов растет.