Нахождение рядом с соседями - PullRequest
16 голосов
/ 10 февраля 2011

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

pointSet

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

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

Ответы [ 3 ]

8 голосов
/ 10 февраля 2011

Вы можете реализовать свою первую идею выбора ребер, средние точки которых находятся на пересечении с линиями Вороного, используя DelaunayTri класс и его edgesи 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

enter image description here

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

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

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

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

1 голос
/ 10 февраля 2011

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

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

0 голосов
/ 09 февраля 2014

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

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

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

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

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

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

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

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

...