Menemukan tetangga dekat

Saya perlu menemukan tetangga "dekat" di antara serangkaian titik.

pointSet

Ada 10 poin pada gambar di atas. Garis merah adalah tepi dari Triangulasi Delaunay, bintang hitam menandai titik tengah garis tepinya, garis biru adalah tesselasi Voronoi. Titik 1 mempunyai tiga tetangga “dekat”, yaitu 4, 6, dan 7, namun bukan 2 dan 3, yang hampir sejajar dengan tepi 1-7, namun jauh lebih jauh.

Apa cara yang baik untuk mengidentifikasi tetangga dekat (atau tepian yang "baik")? Melihat gambar tersebut, menurut saya memilih tepi yang titik tengahnya jatuh pada perpotongan dengan garis Voronoi, atau mempertimbangkan tepi yang bersentuhan dengan sel Voronoi sebagai tetangga "dekat" bisa menjadi solusi yang baik (klasifikasi 3-5 bisa pergi ke arah mana pun). Apakah ada cara yang efisien untuk mengimplementasikan salah satu solusi di Matlab (saya akan senang mendapatkan algoritma umum yang bagus yang kemudian bisa saya terjemahkan ke Matlab, btw)?


person Jonas    schedule 10.02.2011    source sumber
comment
+1 untuk pertanyaan menarik. Untuk lebih memahami hal ini, apa saja tetangga dekat 9?   -  person Jacob    schedule 10.02.2011
comment
@Jacob: Kemungkinan besar 3, 4, 5, 7, 8, 10.   -  person Jonas    schedule 10.02.2011
comment
Jonas, apakah Anda yakin objek pengembalian DelaunayTri memiliki 1 dan 3 yang terhubung? Bukankah ada lemma yang menyatakan bahwa terdapat delaunay edge antara dua titik jika wilayah voronoinya berbagi keunggulan? Saya seorang pemula di bidang ini, jadi beri tahu saya jika saya melewatkan sesuatu di sini.   -  person sundar - Remember Monica    schedule 23.11.2011
comment
@sundar: Saya merencanakan keluaran DelaunayTri, jadi ya, saya yakin. Mungkin ada lemma seperti yang Anda katakan, tapi saya tidak menyadarinya.   -  person Jonas    schedule 23.11.2011
comment
@Jonas, terima kasih atas balasannya, dapatkah Anda memberi tahu saya apakah ini adalah satu-satunya titik masukan ke DelaunayTri, atau apakah ini adalah versi yang diperbesar dengan beberapa titik luar tertinggal?   -  person sundar - Remember Monica    schedule 24.11.2011
comment
@sundar: ini adalah satu-satunya poin.   -  person Jonas    schedule 24.11.2011
comment
@Jonas Terima kasih. Saya menganalisis gambar tersebut dan menentukan bahwa wilayah 1 dan 2 (dan juga 1 dan 3) memang berbagi tepi dan menjadi tetangga 'dekat' di wilayah paling kanan dari gambar ini. Jadi, tepi delaunay yang dikembalikan secara teknis benar dan dengan sendirinya mengidentifikasi titik-titik yang dekat dengan tetangganya.   -  person sundar - Remember Monica    schedule 25.11.2011
comment
@sundar: Terima kasih telah melihat ini. Namun, untuk tujuan praktis saya, saya tidak akan menganggap mereka sebagai tetangga dekat.   -  person Jonas    schedule 25.11.2011


Jawaban (3)


Anda dapat menerapkan ide pertama Anda dalam memilih tepi yang titik tengahnya berada pada perpotongan dengan garis Voronoi dengan memanfaatkan DelaunayTri kelas dan edges< /a> dan metode nearestNeighbor. Berikut ini contoh dengan 10 pasangan acak nilai x dan 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

Dan sekarang edgeIndex adalah matriks N-kali-2 di mana setiap baris berisi indeks menjadi x dan y untuk satu sisi yang mendefinisikan koneksi "dekat". Plot berikut mengilustrasikan triangulasi Delaunay (garis merah), diagram Voronoi (garis biru), titik tengah tepi triangulasi (tanda bintang hitam), dan tepi "baik" yang tersisa di edgeIndex (garis merah tebal):

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

masukkan deskripsi gambar di sini

Bagaimana itu bekerja...

Diagram Voronoi terdiri dari serangkaian poligon atau sel Voronoi. Pada gambar di atas, setiap sel mewakili wilayah di sekitar titik triangulasi tertentu yang melingkupi semua titik dalam ruang yang lebih dekat ke titik tersebut dibandingkan titik lainnya. Akibatnya, jika Anda memiliki 2 simpul yang tidak berdekatan dengan simpul lainnya (seperti simpul 6 dan 8 pada gambar Anda), maka titik tengah garis yang menghubungkan simpul-simpul tersebut berada pada garis pemisah antara sel Voronoi untuk sudut.

Akan tetapi, jika ada simpul ketiga yang dekat dengan garis yang menghubungkan 2 simpul tertentu, maka sel Voronoi untuk simpul ketiga dapat memanjang di antara 2 simpul tersebut, melintasi garis yang menghubungkan keduanya dan menutup titik tengah garis tersebut. Oleh karena itu, simpul ketiga ini dapat dianggap sebagai tetangga yang "lebih dekat" dengan 2 simpul tertentu dibandingkan dengan 2 simpul satu sama lain. Pada gambar Anda, sel Voronoi untuk simpul 7 meluas ke daerah antara simpul 1 dan 2 (dan 1 dan 3), sehingga simpul 7 dianggap sebagai tetangga yang lebih dekat dengan simpul 1 daripada simpul 2 (atau 3).

Dalam beberapa kasus, algoritme ini mungkin tidak menganggap dua simpul sebagai tetangga "dekat" meskipun sel Voronoinya bersentuhan. Simpul 3 dan 5 pada gambar Anda adalah contohnya, di mana simpul 2 dianggap sebagai tetangga yang lebih dekat dengan simpul 3 atau 5 dibandingkan simpul 3 atau 5 satu sama lain.

person gnovice    schedule 10.02.2011
comment
Terima kasih banyak! Saya akui saya tidak sepenuhnya yakin mengapa ini berhasil (yaitu properti tesselasi Voronoi apa yang Anda gunakan), tetapi berhasil. - person Jonas; 10.02.2011
comment
@Jonas: Saya menambahkan penjelasan tentang cara kerja pendekatan klasifikasi tetangga terdekat ini. - person gnovice; 11.02.2011

Saya setuju bahwa tepi sel bersama adalah kriteria tetangga yang baik (berdasarkan contoh ini). Jika Anda menggunakan struktur data berorientasi mesh (seperti sesuatu dari Gts), maka mengidentifikasi tepi bersama akan menjadi hal yang sepele.

Matlab, di sisi lain, membuat ini lebih "menarik". Dengan asumsi sel voronoi disimpan sebagai tambalan, Anda dapat mencoba mendapatkan properti tambalan 'Wajah' (lihat referensi ini). Itu akan menghasilkan sesuatu seperti matriks ketetanggaan yang mengidentifikasi simpul-simpul yang terhubung. Dari situ (dan sedikit keajaiban), Anda seharusnya bisa menentukan simpul bersama, dan kemudian menyimpulkan sisi bersama. Menurut pengalaman saya, masalah "pencarian" semacam ini tidak cocok untuk Matlab - jika memungkinkan, saya sarankan untuk pindah ke sistem yang lebih cocok untuk kueri konektivitas mesh.

person Throwback1986    schedule 10.02.2011
comment
Terima kasih atas referensi ke sistem lain. Saya harap saya bisa lolos dengan solusi @ gnovice, tapi ada baiknya mengetahui apa yang ada di luar sana kalau-kalau saya tidak bisa. - person Jonas; 10.02.2011
comment
Agak terlambat, tetapi konsep ini (Kedekatan berdasarkan pasangan Voronoi) baru-baru ini digunakan untuk menghasilkan daftar kedekatan terbatas (Daftar Kandidat) untuk menyelesaikan Masalah Perutean Kendaraan secara heuristik. Lihat 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

Kemungkinan lain, yang lebih sederhana daripada membuat triangulasi atau diagram voronoi, adalah menggunakan matriks lingkungan.

Pertama-tama tempatkan semua poin Anda ke dalam matriks persegi 2D. Kemudian Anda dapat menjalankan pengurutan spasial penuh atau sebagian, sehingga titik-titik akan terurut di dalam matriks.

Titik-titik yang mempunyai Y kecil dapat berpindah ke baris atas matriks, demikian pula titik-titik yang mempunyai Y besar akan berpindah ke baris terbawah. Hal yang sama akan terjadi pada titik-titik dengan koordinat X kecil, yang seharusnya berpindah ke kolom di sebelah kiri. Dan secara simetris, titik-titik dengan nilai X besar akan menuju ke kolom kanan.

Setelah Anda melakukan pengurutan spasial (ada banyak cara untuk mencapai hal ini, baik dengan algoritma serial atau paralel) Anda dapat mencari titik terdekat dari titik P tertentu hanya dengan mengunjungi sel yang berdekatan di mana titik P sebenarnya disimpan dalam matriks lingkungan.

Anda dapat membaca lebih detail ide ini di makalah berikut (Anda dapat menemukan salinan PDF-nya secara online): Simulasi Kerumunan Supermasif pada GPU berdasarkan Perilaku yang Muncul.

Langkah penyortiran memberi Anda pilihan menarik. Anda hanya dapat menggunakan pengurutan transposisi genap-ganjil yang dijelaskan di makalah, yang sangat mudah diterapkan (bahkan di CUDA). Jika Anda menjalankan hanya satu pass saja, ini akan memberi Anda pengurutan sebagian, yang sudah berguna jika matriks Anda hampir diurutkan. Artinya, jika poin Anda bergerak lambat, maka akan menghemat banyak perhitungan.

Jika Anda memerlukan pengurutan lengkap, Anda dapat menjalankan transposisi ganjil genap beberapa kali (seperti dijelaskan di halaman Wikipedia berikut):

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

person mgmalheiros    schedule 08.02.2014
comment
Jika Anda mengalami lonjakan data... katakanlah dua cluster yang terpisah secara berdampingan. dan Anda mengurutkan matriks seperti yang Anda sarankan di atas. Lalu bukankah titik paling kiri pada cluster kanan dan titik paling kanan pada cluster kiri akan dianggap bertetangga? - person codekitty; 13.02.2014
comment
@codekitty: Ya, titik-titik jauh tersebut dapat ditempatkan berdampingan dalam matriks lingkungan. Namun skema ini membantu Anda dengan cepat menemukan kandidat untuk tetangga sebenarnya, jadi setelah memilih beberapa dari sel matriks terdekat, Anda masih perlu menguji sel-sel yang berada dalam radius pengaruh Anda (atau memilih yang terdekat) . - person mgmalheiros; 14.02.2014
comment
Tentu saja kepadatan aktual dan distribusi titik-titik Anda dalam ruang secara langsung mempengaruhi cara matriks dikemas. Jadi, ini akan bekerja lebih baik untuk distribusi yang seragam, idealnya untuk pengaturan titik grid atau sarang lebah yang teratur. Untuk aplikasi khusus saya (partikel yang dikemas rapat) ini sangat berguna... - person mgmalheiros; 14.02.2014
comment
Saya telah menempatkan beberapa contoh kode C++ di sini, yang sangat sederhana. Dan dua gambar, titik berkode warna pada bidang (X komponen merah, Y hijau): sebelum dan setelah. - person mgmalheiros; 14.02.2014