Поиск ближайших соседей

Мне нужно найти "ближайших" соседей среди множества точек.

набор точек

На изображении выше 10 точек. Красные линии – это края триангуляции Делоне, черные звезды – середина. линии ребер, синие линии — это тесселяция Вороного. У точки 1 есть три «ближних» соседа, то есть 4, 6 и 7, но не 2 и 3, которые почти на одной линии с ребром 1-7, но намного дальше.

Каков хороший способ определить ближайших соседей (или «хорошие» края)? Глядя на рисунок, мне кажется, что хорошим решением могло бы быть либо выделение ребер, середина которых приходится на пересечение с линиями Вороного, либо рассмотрение в качестве «ближних» соседей тех, у которых соприкасаются клетки Вороного (классификация 3-5 можно пойти по любому пути). Есть ли эффективный способ реализации любого из решений в Matlab (кстати, я был бы рад получить хороший общий алгоритм, который затем мог бы перевести в Matlab)?


person Jonas    schedule 10.02.2011    source источник
comment
+1 за интересный вопрос. Чтобы лучше понять это, каковы ближайшие соседи 9?   -  person Jacob    schedule 10.02.2011
comment
@Jacob: Скорее всего, 3, 4, 5, 7, 8, 10.   -  person Jonas    schedule 10.02.2011
comment
Йонас, вы уверены, что возвращаемый объект DelaunayTri имеет соединение 1 и 3? Разве не существует леммы, утверждающей, что существует ребро Делоне между двумя точками тогда и только тогда, когда их области Вороного имеют общее ребро? Я новичок в этой области, так что скажите мне, если я что-то пропустил здесь.   -  person sundar - Remember Monica    schedule 23.11.2011
comment
@sundar: я построил вывод DelaunayTri, так что да, я уверен. Может быть лемма, как вы говорите, но я не знаю о ней.   -  person Jonas    schedule 23.11.2011
comment
@Jonas, спасибо за ответ, не могли бы вы сказать мне, являются ли они единственными точками ввода в DelaunayTri, или это увеличенная версия с некоторыми опущенными внешними точками?   -  person sundar - Remember Monica    schedule 24.11.2011
comment
@sundar: это были единственные точки.   -  person Jonas    schedule 24.11.2011
comment
@ Джонас Спасибо. Я проанализировал изображение и определил, что области 1 и 2 (а также 1 и 3) имеют общее ребро и становятся «ближайшими» соседями в крайней правой области этого изображения. Таким образом, возвращенные ребра Делоне технически правильны и сами по себе идентифицируют точки, находящиеся рядом с соседями.   -  person sundar - Remember Monica    schedule 25.11.2011
comment
@sundar: Спасибо, что посмотрели это. Однако для моих практических целей я бы не стал рассматривать их как близких соседей.   -  person Jonas    schedule 25.11.2011


Ответы (3)


Вы можете реализовать свою первую идею выбора рёбер, середины которых попадают на пересечение с линиями Вороного, используя DelaunayTri класс и его edges< /a> и nearestNeighbor. Вот пример с 10 случайными парами значений x и y:

x = rand(10,1);                     %# Random x data
y = rand(10,1);                     %# Random y data
dt = DelaunayTri(x,y);              %# Compute the Delaunay triangulation
edgeIndex = edges(dt);              %# Triangulation edge indices
midpts = [mean(x(edgeIndex),2) ...  %# Triangulation edge midpoints
          mean(y(edgeIndex),2)];
nearIndex = nearestNeighbor(dt,midpts);  %# Find the vertex nearest the midpoints
keepIndex = (nearIndex == edgeIndex(:,1)) | ...  %# Find the edges where the
            (nearIndex == edgeIndex(:,2));       %#   midpoint is not closer to
                                                 %#   another vertex than it is
                                                 %#   to one of its end vertices
edgeIndex = edgeIndex(keepIndex,:);      %# The "good" edges

И теперь edgeIndex представляет собой матрицу размером N на 2, где каждая строка содержит индексы x и y для одного ребра, определяющего «ближнее» соединение. Следующий график иллюстрирует триангуляцию Делоне (красные линии), диаграмму Вороного (синие линии), средние точки ребер триангуляции (черные звездочки) и «хорошие» ребра, оставшиеся в edgeIndex (толстые красные линии):

triplot(dt,'r');  %# Plot the Delaunay triangulation
hold on;          %# Add to the plot
plot(x(edgeIndex).',y(edgeIndex).','r-','LineWidth',3);  %# Plot the "good" edges
voronoi(dt,'b');  %# Plot the Voronoi diagram
plot(midpts(:,1),midpts(:,2),'k*');  %# Plot the triangulation edge midpoints

введите здесь описание изображения

Как это работает...

Диаграмма Вороного состоит из серии многоугольников Вороного или ячеек. На приведенном выше изображении каждая ячейка представляет собой область вокруг данной вершины триангуляции, которая охватывает все точки в пространстве, которые ближе к этой вершине, чем к любой другой вершине. В результате этого, когда у вас есть 2 вершины, которые не находятся рядом с другими вершинами (например, вершины 6 и 8 на вашем изображении), тогда средняя точка линии, соединяющей эти вершины, попадает на разделительную линию между ячейками Вороного для вершины.

Однако, когда есть третья вершина, близкая к линии, соединяющей 2 заданные вершины, то ячейка Вороного для третьей вершины может проходить между двумя заданными вершинами, пересекая линию, соединяющую их, и охватывая середину этой линии. Таким образом, эту третью вершину можно считать «более близким» соседом к двум заданным вершинам, чем эти две вершины друг к другу. На вашем изображении ячейка Вороного для вершины 7 простирается в область между вершинами 1 и 2 (и 1 и 3), поэтому вершина 7 считается более близким соседом к вершине 1, чем вершина 2 (или 3).

В некоторых случаях этот алгоритм может не рассматривать две вершины как «близких» соседей, даже если их ячейки Вороного соприкасаются. Вершины 3 и 5 на вашем изображении являются примером этого, где вершина 2 считается более близким соседом к вершинам 3 или 5, чем вершины 3 или 5 друг к другу.

person gnovice    schedule 10.02.2011
comment
Большое тебе спасибо! Я признаю, что не совсем понимаю, почему это работает (т.е. какое свойство тесселяции Вороного вы используете), но работает. - person Jonas; 10.02.2011
comment
@Jonas: я добавил объяснение того, как работает этот подход к классификации ближайших соседей. - person gnovice; 11.02.2011

Я согласен с тем, что общие края ячеек являются критерием хорошего соседства (на основе этого примера). Если бы вы использовали структуру данных, ориентированную на сетку (например, что-то из Gts), то идентификация общих ребер была бы тривиальной.

Matlab, с другой стороны, делает это более «интересным». Предполагая, что ячейки Вороного хранятся в виде патчей, вы можете попробовать получить свойство патча «Лица» (см. эту ссылку). Это должно вернуть что-то вроде матрицы смежности, которая идентифицирует связанные вершины. Исходя из этого (и немного магии), вы сможете определить общие вершины, а затем вывести общие ребра. По моему опыту, такая проблема «поиска» плохо подходит для Matlab — если возможно, я рекомендую перейти на систему, более подходящую для запросов связности сетки.

person Throwback1986    schedule 10.02.2011
comment
Спасибо за ссылку на другую систему. Я надеюсь, что мне сойдет с рук решение @gnovice, но полезно знать, что там есть, если я не могу. - person Jonas; 10.02.2011
comment
Немного поздно для вечеринки, но эта концепция (близость, основанная на парах Вороного) недавно использовалась для создания ограниченного списка смежности (список кандидатов) для эвристического решения задач маршрутизации транспортных средств. См. Fang, Zhixiang, et al. "A Voronoi neighborhood-based search heuristic for distance/capacity constrained very large vehicle routing problems." International Journal of Geographical Information Science 27.4 (2013): 741-764. - person Gaminic; 25.03.2014

Другая возможность, более простая, чем создание триангуляций или диаграмм Вороного, — это использование матрицы соседства.

Сначала поместите все свои точки в 2D квадратную матрицу. Затем вы можете запустить полную или частичную пространственную сортировку, чтобы точки упорядочились внутри матрицы.

Точки с маленьким Y могли перемещаться в верхние строки матрицы, и точно так же точки с большим Y попадали в нижние строки. То же самое произойдет с точками с маленькими координатами X, которые должны переместиться в столбцы слева. И симметрично, точки с большим значением X пойдут в правые столбцы.

После того, как вы выполнили пространственную сортировку (есть много способов добиться этого, как с помощью последовательных, так и параллельных алгоритмов), вы можете найти ближайшие точки к заданной точке P, просто посетив соседние ячейки, где точка P фактически хранится в матрице соседства.

Вы можете прочитать более подробную информацию об этой идее в следующей статье (вы найдете ее PDF-копии в Интернете): Моделирование сверхмассивной толпы на графическом процессоре на основе эмерджентного поведения.

Шаг сортировки дает вам интересные варианты. Вы можете использовать только четно-нечетную транспонированную сортировку, описанную в статье, которую очень просто реализовать (даже в CUDA). Если вы запустите только один проход, это даст вам частичную сортировку, которая уже может быть полезна, если ваша матрица почти отсортирована. То есть, если ваши точки движутся медленно, это сэкономит вам много вычислений.

Если вам нужна полная сортировка, вы можете запустить такой четно-нечетный проход несколько раз (как описано на следующей странице Википедии):

http://en.wikipedia.org/wiki/Odd%E2%80%93even_sort

person mgmalheiros    schedule 08.02.2014
comment
Если у вас есть скачок в ваших данных... скажем, два хорошо разделенных кластера рядом. и вы отсортировали свою матрицу, как предложили выше. Тогда не будет ли крайняя левая точка правого кластера и крайняя правая точка левого кластера ошибочно считаться соседями? - person codekitty; 13.02.2014
comment
@codekitty: Да, эти удаленные точки можно разместить рядом в матрице соседства. Но эта схема помогает быстро найти кандидатов в реальные соседи, поэтому, выбрав несколько из ближайших ячеек матрицы, вам все равно нужно будет протестировать те, которые находятся в вашем радиусе влияния (или выбрать ближайшего) . - person mgmalheiros; 14.02.2014
comment
Конечно, фактическая плотность и распределение ваших точек в пространстве напрямую влияет на то, как упакована матрица. Таким образом, это будет лучше работать для равномерного распределения, в идеале для регулярной сетки или расположения точек в виде сот. Для моего конкретного применения (плотно упакованные частицы) это было очень полезно... - person mgmalheiros; 14.02.2014
comment
Я поместил образец кода C++ здесь, который действительно прост. И два изображения точек на плоскости с цветовой кодировкой (X — красная составляющая, Y — зеленая): до и после. - person mgmalheiros; 14.02.2014