eToro -panostus

Kuinka automatisoida 3D -pistepilven segmentointi ja klusterointi Pythonin avulla

Lähdesolmu: 1861015

Jos olet aiemmin työskennellyt pistepilvien kanssa (tai tässä tapauksessa datan kanssa), tiedät kuinka tärkeää on löytää kuvioita havaintojen välillä 📈. Meidän on todellakin usein hankittava ylemmän tason tietoa, joka perustuu vahvasti "objektien" määrittämiseen, jotka muodostavat tietopisteet, joilla on yhteinen kuvio.

Visuaaliset kuviot pisteissä vasemmalta oikealle: Ei ryhmitelty; Läheisyyskriteeri; Samankaltaisuuskriteeri; Yhteinen klusterialue; Lineaarinen kriteeri; Rinnakkaiskriteeri: Symmetriakriteeri. Lähde: (Poux ym., 2019)

Tämä on tehtävä, jonka visuaalinen kognitiivinen järjestelmämme suorittaa melko mukavasti. Tämän ihmisen kyvyn matkiminen laskennallisin menetelmin on kuitenkin erittäin haastava ongelma 🤯. Pohjimmiltaan haluamme hyödyntää ihmisen näköjärjestelmän taipumusta ryhmä elementtejä.

Se, mitä "anturi näkee" VS mahdollinen "objektien ryhmittely", joka jäljittelee ihmisen näköjärjestelmää (tuolit keltaisina, pohja sininen, sotkua ilmentyneinä). © F. Poux

Mutta miksi se on hyödyllistä?

Loistava kysymys! Itse asiassa pistepilven segmentoinnin pääasialliset syyt ovat kolme:

  • Ensinnäkin se tarjoaa loppukäyttäjille joustavuuden päästä tehokkaasti käsiksi yksittäiseen sisältöön ja muokata sitä korkeamman tason yleistyksellä: segmenteillä.
  • Toiseksi se luo tiedoista kompaktin esityksen, jossa kaikki myöhemmät käsittelyt voidaan tehdä alueellisella tasolla yksittäisen pistetason sijaan, mikä johtaa mahdollisesti merkittäviin laskennallisiin hyötyihin.
  • Lopuksi se antaa mahdollisuuden poimia naapurustojen, kaavioiden ja topologian välisiä suhteita, joita ei ole olemassa raakapistepohjaisissa tietosarjoissa.

Näistä syistä segmentointia käytetään pääasiassa esikäsittelyvaiheena pistepilvitietojen merkitsemiseen, parantamiseen, analysointiin, luokitteluun, luokitteluun, poimimiseen ja abstraktiin informaatioon. Mutta oikea kysymys nyt. Miten se tehdään?

Aaand… avataan laatikko 👐!

3D-pistepilven segmentointi
Tässä käytännön python-oppaassa opitut 3D-pistepilven segmentoinnin vaiheet. Ensin etsimme tasomaisia ​​muotoja (RANSAC), sitten tarkennamme automaattisesti euklidisen klusterin (DBSCAN) avulla. © F. Poux

Jos tästä perusteellisesta opetussisällöstä on hyötyä sinulle, tilaa AI-tutkimuksen postituslista hälytys, kun julkaisemme uutta materiaalia.

Nopea 3D-segmentointiteoria, jossa on kaksi avainkäsitettä

Tässä opetusohjelmassa olen jo valinnut sinulle kahdesta parhaasta ja vahvemmasta lähestymistavasta, jotka opit lopuksi. Luotamme kahteen keskeiseen ja tehokkaaseen lähestymistapaan: ransac ja Euklidisen klusterin kautta DBSCAN. Mutta ennen niiden käyttöä on kai 😀 Tärkeää ymmärtää yksinkertaisesti sanottuna pääidea.

ransac

RANSAC on siis lyhenne sanoista RANdom Sample Consensus, ja se on melko yksinkertainen mutta erittäin tehokas algoritmi, jota voit käyttää, jos tietoihisi vaikuttavat poikkeamat, kuten meidän tapauksessamme 😊. Todellakin, aina kun työskentelet todellisten antureiden kanssa, tietosi eivät koskaan ole täydellisiä. Ja melko usein poikkeamat vaikuttavat anturitietoihisi. Ja RANSAC on eräänlainen yritys ja erehdys -lähestymistapa, joka ryhmittelee tietopisteesi kahteen segmenttiin: inlier-joukko ja outlier-joukko. Sitten voit unohtaa poikkeamat ja työskennellä inliersin kanssa.

Käytän siis pientä mutta yksinkertaista esimerkkiä havainnollistamaan RANSACin toimintaa. Sanotaan, että haluamme sovittaa koneen alla olevan pistepilven läpi. Kuinka voimme tehdä sen?

RANSAC-tason tunnistussimulaatio satunnaisessa pistepilvessä. © F. Poux

Ensin luodaan tiedoista tason ja tätä varten valitsemme satunnaisesti pistepilvestä tason muodostamiseen tarvittavat 3 pistettä. Ja sitten yksinkertaisesti tarkistamme kuinka monta jäljellä olevista pisteistä putoaa koneeseen (tietylle kynnysarvolle), mikä antaa pisteytyksen ehdotukselle.

RANSAC-pisteytysjärjestelmä kuvassa. Voit nähdä, että jokainen iteraatio ottaa näytteitä 3 satunnaisesta pisteestä, joista se luo suunnitelman ja valitsee sitten pisteet, jotka kuuluisivat siihen. Tässä iteraatio 159 olisi paras ehdokas. © F. Poux

Sitten toistamme prosessin 3 uudella satunnaisella pisteellä ja katsomme, kuinka meillä menee. Onko se parempi? Onko se huonompi? Ja jälleen, toistamme tämän prosessin uudestaan ​​​​ja uudestaan, sanotaan 10 kertaa, 100 kertaa, 1000 kertaa, ja sitten valitsemme tasomallin, jolla on korkein pistemäärä (eli jolla on paras "tuki" jäljellä olevista datapisteistä). . Ja se on ratkaisumme: tukipisteet sekä kolme otokseemme pistettä muodostavat meidän sisäpiste asetettu, ja loput on meidän outlier point asetettu. Tarpeeksi helppoa, hun 😁?

Haha, mutta epäilijöille, eikö sinulla ole nousevaa kysymystä? Kuinka todella määritämme, kuinka monta kertaa meidän pitäisi toistaa prosessi? Kuinka usein meidän pitäisi kokeilla sitä? No, se on itse asiassa jotain, mitä voimme laskea, mutta jätetään se nyt sivuun keskittyäksesi käsillä olevaan asiaan: pistepilvien segmentointiin 😉.

Euklidinen klusteri (DBSCAN)

Pistepilvitietojoukoissa meidän on usein ryhmitettävä pistejoukot spatiaalisesti vierekkäin, kuten alla on kuvattu. Mutta kuinka voimme tehdä tämän tehokkaasti?

Tässä kuvassa näyttää ilmeiseltä, että haluamme ryhmitellä toisistaan ​​suljetut pisteet ja löytää 5 pistettä. © F. Poux

DBSCAN (Density-Based Spatial Clustering of Applications with Noise) -algoritmi otettiin käyttöön vuonna 1996 tätä tarkoitusta varten. Tämä algoritmi on laajalti käytetty, minkä vuoksi se palkittiin vuonna 2014 tieteellisellä panospalkinnolla, joka on kestänyt ajan kokeen.

DBSCAN iteroi tietojoukon pisteiden yli. Jokaiselle analysoitavalle pisteelle se muodostaa joukon pisteitä, jotka saavutetaan tiheydellä tästä pisteestä: se laskee tämän pisteen lähialueen, ja jos tämä naapurusto sisältää enemmän kuin tietyn määrän pisteitä, se sisällytetään alueeseen. Jokainen vierekkäinen piste käy läpi saman prosessin, kunnes se ei voi enää laajentaa klusteria. Jos kyseessä oleva piste ei ole sisäpiste, eli sillä ei ole tarpeeksi naapureita, se merkitään meluksi. Tämä mahdollistaa DBSCANin kestävän poikkeaville arvoille, koska tämä mekanismi eristää ne. Kuinka siistiä se on 😆?

Kuva DBSCAN-algoritmiprosessista ja kahden parametrin ϵ ja min_points vaikutuksesta tuloksiin. Voit nähdä, että mitä suurempi arvo, sitä vähemmän klustereita muodostuu. © F. Poux

Ah, melkein unohdin. Parametrien valinta (ϵ lähistölle ja n_min minimipistemäärälle) voi myös olla hankala: Parametreja asetettaessa on oltava tarkkana, jotta saadaan tarpeeksi sisäpisteitä (mitä ei tapahdu, jos n_min on liian suuri tai ϵ liian pieni ). Tämä tarkoittaa erityisesti sitä, että DBSCANilla on vaikeuksia löytää eri tiheyksillä olevia klustereita. MUTTA DBSCANilla on se suuri etu, että se on laskennallisesti tehokas ilman, että klusterien lukumäärää edellytetään, toisin kuin esimerkiksi Kmeans. Lopuksi se mahdollistaa mielivaltaisen muotoisten klustereiden löytämisen.

Ja nyt, laitetaan kaikki tämä hölynpöly superhyödylliseen "ohjelmistoon" 5-vaiheisen prosessin kautta 💻!

Vaihe 1: (pistepilvi) data, aina data 😁

Aiemmissa tutoriaaleissa havainnollistin pistepilvikäsittelyä ja verkostoitumista käyttämällä saadun 3D-aineiston yli fotogrammetriaa ja antenni LiDAR alkaen Avaa topografia. Tällä kertaa käytämme tietojoukkoa, jonka keräsin käyttämällä Terrestrial Laser Scanneria!

Ohitan I/O-toimintojen ja tiedostomuotojen yksityiskohdat, mutta tiedän, että niitä käsitellään nämä artikkelit jos haluat selventää tai rakentaa täysimittaista asiantuntemusta. Tänään siirrymme käyttämään tunnettua .ply-tiedostomuotoa.

🤓 HuomautuksiaTässä ohjeessa voit käyttää pistepilveä tämän arkiston, jonka olen jo suodattanut ja kääntänyt, jotta olet optimaalisissa olosuhteissa. Jos haluat visualisoida ja leikkiä sen kanssa etukäteen asentamatta mitään, voit tarkistaa webGL-versio.

Vaihe 2: Määritä Python-ympäristösi.

In edellinen artikkeli, näimme kuinka luoda ympäristö Anacondan avulla helposti ja kuinka voit käyttää IDE Spyderiä koodin hallintaan. Suosittelen jatkamaan tällä tavalla, jos olet valmis ryhtymään täysivaltaiseksi python-sovelluskehittäjäksi 😆.

Mutta hei, jos haluat tehdä kaiken tyhjästä seuraavien 5 minuutin aikana, annan sinulle myös pääsyn Google Colab -muistikirjaan, jonka löydät artikkelin lopusta. Ei ole mitään asennettavaa; voit vain tallentaa sen Google Driveen ja aloittaa työskentelyn sen kanssa, myös käyttämällä vaiheen 1 ilmaisia ​​tietojoukkoja☝️.

Google Colab -tiedostossa voit suorittaa komentosarjan solu kerrallaan ja hyötyä suorasta koodauskokemuksesta verkossa. Loistava tapa aloittaa Python-kokeilu. (Kyllä, kissat kävelevät ikkunasta 😺). © F. Poux

HuomautuksiaSuosittelen käyttämään työpöydän IDE:tä, kuten Spyderiä, ja välttämään Google Colabia tai Jupyteria, JOS sinun on visualisoitava 3D-pistepilvet käyttämällä toimitettuja kirjastoja, koska ne ovat parhaimmillaan epävakaita tai eivät toimi huonommin (valitettavasti…).

Vaihe 3: Ensimmäinen segmentointikierros

No, saadakseni tuloksia nopeasti, otan "parti-prisin". Todellakin, saamme aikaan mukavan segmentoinnin noudattamalla minimalistista lähestymistapaa koodaukseen 💻. Tämä tarkoittaa, että olet erittäin nirso taustalla olevien kirjastojen suhteen! Käytämme kolmea erittäin kestävää, nimittäin numpymatplotlibja open3d.

Okei, jos haluat asentaa yllä olevan kirjastopaketin ympäristöösi, suosittelen, että suoritat seuraavan komennon päätteestä (huomaa myös open3d-admin kanava):

conda install numpy
conda install matplotlib
conda install -c open3d-admin open3d

Vastuuvapauslauseke: Valitsemme Pythonin, emme C++:n tai Julian, joten esitykset ovat mitä ovat 😄. Toivottavasti se riittää hakemuksellesi 😉, niin sanottuihin "offline"-prosesseihin (ei reaaliaikaisiin).

Ja nyt on kauan odotettu aika nähdä ensimmäiset tulokset!

Kuinka ottaa RNSAC käyttöön 3D-pistepilvien yli?

Tuodaan ensin tiedot tiedostoon pcd muuttuja seuraavalla rivillä:

pcd = o3d.io.read_point_cloud("your_path/kitchen.ply")

Haluatko tehdä ihmeitä nopeasti? No, minulla on loistavia uutisia, open3d on varustettu RANSAC-toteutuksella tasomaisen muodon havaitsemiseen pistepilvissä. Ainoa kirjoitettava rivi on seuraava:

plane_model, inliers = pcd.segment_plane(distance_threshold=0.01, ransac_n=3, num_iterations=1000)

🤓 HuomautuksiaKuten näette, segment_plane() menetelmä sisältää 3 parametria. Nämä ovat etäisyyden kynnys (distance_threshold) tasosta ottaaksesi huomioon pisteen, joka on sisä- tai ulkopuolinen, piirrettyjen näytepisteiden määrä (3 tässä, koska haluamme tason) kunkin tasoehdokkaan arvioimiseksi (ransac_n) ja iteraatioiden lukumäärä (num_iterations). Nämä ovat vakioarvoja, mutta ota huomioon, että käytettävissä olevasta tietojoukosta riippuen distance_threshold tulee tarkistaa uudelleen.

Yllä olevan rivin tulos on parhaat tason ehdokasparametrit a,b,c ja d plane_model, ja indeksi pisteistä, joita pidetään inliersinä, on tallennettu inliers.

Katsokaamme nyt tuloksia, eikö niin? Tätä varten meidän on itse asiassa valittava pisteet tallennettujen indeksien perusteella inliersja valitse valinnaisesti kaikki muut poikkeavuuksiksi. Miten tämä tehdään? No näin:

inlier_cloud = pcd.select_by_index(inliers)
outlier_cloud = pcd.select_by_index(inliers, invert=True)

🤓 HuomautuksiaArgumentti invert=True sallii valita ensimmäisen argumentin vastakohdan, mikä tarkoittaa, että kaikki indeksit eivät ole mukana inliers.

Okei, nyt muuttujat pitävät pisteet, mutta ennen tulosten visualisointia ehdotan, että maalaamme sisäosat punaisiksi ja loput harmaiksi. Tätä varten voit vain välittää luettelon R-, G-, B-arvoista kelluvina seuraavasti:

inlier_cloud.paint_uniform_color([1, 0, 0])
outlier_cloud.paint_uniform_color([0.6, 0.6, 0.6])

Ja nyt visualisoidaan tulokset seuraavalla rivillä:

o3d.visualization.draw_geometries([inlier_cloud, outlier_cloud])

🤓 HuomautuksiaJos haluat ymmärtää paremmin värin peittämän geometrian, voit laskea normaalit etukäteen seuraavalla komennolla: pcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=16), fast_normal_computation=True). Näin saat paljon hienomman renderöinnin, kuten alla😉.

Tämä näyttää yllä kuvatun RNSAC-komentosarjan tuloksen. Punaisena ovat inliers ja harmaan ovat outliers. © F. Poux

Loistava! Osaat segmentoida pistepilvisi sisäpistejoukossa ja outlier point -joukossa 🥳! Tutkikaamme nyt, kuinka löytää joitakin klustereita lähellä toisiaan. Joten kuvitellaan, että kun olemme havainneet suuret tasomaiset osat, meillä on joitain "kelluvia" esineitä, jotka haluamme rajata. Miten tämä tehdään? (kyllä, se on väärä kysymys, minulla on vastaus sinulle 😀)

Kuinka käyttää DBSCANia pistepilvien yli?

Ensin valitsemme näytteen, jossa oletamme pääsevämme eroon kaikista tasomaisista alueista (tämä näyte löytyy täältä: Pääsy datanäyte), kuten alla.

Loput elementit, jotka haluamme segmentoida euklidisen klusterin kautta. Tietojoukko on käytettävissä yllä olevan linkin kautta. © F. Poux

Okei, kirjoitetaan nyt vähän DBSCAN-klusterointia. Jälleen, kaiken yksinkertaistamiseksi käytämme DBSCAN-menetelmän osaa open3d pakettia, mutta tiedä, että jos tarvitset lisää joustavuutta, käyttöönotto scikit-learn voi olla pidemmän aikavälin valinta. Ajan suhteen se on melko sama. Menetelmä cluster_dbscan toimii pcd pistepilvikokonaisuus suoraan ja palauttaa luettelon otsikoista pistepilven alkuperäisen indeksoinnin jälkeen.

labels = np.array(pcd.cluster_dbscan(eps=0.05, min_points=10))

🤓 HuomautuksiaTarrat vaihtelevat -1 ja n, Jossa -1 osoittavat, että se on "kohina" piste ja arvot 0 että n ovat sitten vastaavalle pisteelle annetut klusteritunnisteet. Huomaa, että haluamme saada tarrat NumPy-taulukkona ja että käytämme 5 cm:n sädettä klustereiden "kasvamiseen" ja harkitsemme yhtä vain, jos tämän vaiheen jälkeen meillä on vähintään 10 pistettä. Kokeile rohkeasti 😀.

Hienoa, nyt kun meillä on pisteryhmiä määritetty tunnisteella pistettä kohden, väritetään tulokset. Tämä on valinnainen, mutta se on kätevä iteratiivisille prosesseille oikeiden parametrien arvojen etsimiseksi. Tätä varten ehdotan Matplotlib-kirjaston käyttöä tarkkuuden saamiseksi värialueita, kuten tab20:

max_label = labels.max()
colors = plt.get_cmap("tab20")(labels / (max_label if max_label > 0 else 1)) colors[labels < 0] = 0
pcd.colors = o3d.utility.Vector3dVector(colors[:, :3]) o3d.visualization.draw_geometries([pcd])

🤓 Huomautuksiamax_label tulee olla intuitiivinen: se tallentaa enimmäisarvon tarraluetteloon. Tämä sallii sen käytön nimittäjänä väritysmallille, kun sitä käsitellään "if” kertoo erikoistapauksen, jossa klusterointi on vinossa ja tuottaa vain kohinaa + yksi klusteri. Tämän jälkeen varmistamme, että asetamme nämä meluisat kohdat etiketillä -1 mustaksi (0). Sitten annamme attribuutille colors pistepilvestä pcd 2D NumPy -taulukko, jossa on 3 "saraketta", jotka edustavat R, G, B.

Et voilà! Alla klusterointimme tulos.

Pistepilven DBSCAN-klusterointimallin tulokset parametreilla eps=0.05 ja min_points=10. Pystymme erottelemaan selkeästi yläkaapit alemmista, samoin kuin lämmityksen säätimet (vihreä) ja lampun (violetti). © F. Poux

Hienoa, se toimii hienosti, ja nyt, kuinka voimme todella laittaa kaiken tämän mittakaavaan ja automatisoidusti?

Vaihe 4: Skaalaus ja automaatio

Filosofiamme tulee olemaan hyvin yksinkertainen. Suoritamme ensin RANSACin useita kertoja (sanotaan n kertaa) poimimaan eri tasoalueet, jotka muodostavat kohtauksen. Sitten käsittelemme "kelluvia elementtejä" euklidisen klusterin (DBSCAN) avulla. Se tarkoittaa, että meidän on varmistettava, että meillä on tapa tallentaa tulokset iteraatioiden aikana. Valmis?

RANSAC-silmukan luominen useiden tasomaisten muotojen havaitsemiseen

Okei, luodaan tyhjä sanakirja, joka sisältää iteraatioiden tulokset (tasoparametrit segment_models, ja tasomaiset alueet pistepilven sisään segments):

segment_models={}
segments={}

Sitten haluamme varmistaa, että voimme myöhemmin vaikuttaa siihen, kuinka monta kertaa haluamme iteroida tasojen havaitsemiseksi. Tätä varten luodaan muuttuja max_plane_idx joka sisältää iteraatioiden määrän:

max_plane_idx=20

🤓 HuomautuksiaTässä sanomme, että haluamme iteroida 20 kertaa löytääksemme 20 tasoa, mutta on olemassa älykkäämpiä tapoja määrittää tällainen parametri. Se itse asiassa laajentaa artikkelin soveltamisalaa, mutta jos haluat oppia lisää, voit tarkistaa 3D Geodata Academy.

Mennään nyt toimivaan silmukkaan 😁, jonka havainnollistan ensin nopeasti. Ensimmäisessä ajossa (silmukka i=0), erottelemme inliers ja outliers. Säilytämme sisäosat sisällä segments, ja sitten haluamme jatkaa vain jäljellä olevilla pisteillä rest, josta tulee silmukan n+1 (silmukka i=1). Tämä tarkoittaa, että haluamme pitää edellisen vaiheen poikkeavuuksia peruspistepilvenä, kunnes saavutamme iteraatioiden ylärajan (ei pidä sekoittaa RANSAC-iteraatioihin). Tämä tarkoittaa seuraavaa:

rest=pcd
for i in range(max_plane_idx): colors = plt.get_cmap("tab20")(i) segment_models[i], inliers = rest.segment_plane( distance_threshold=0.01,ransac_n=3,num_iterations=1000) segments[i]=rest.select_by_index(inliers) segments[i].paint_uniform_color(list(colors[:3])) rest = rest.select_by_index(inliers, invert=True) print("pass",i,"/",max_plane_idx,"done.")

Ja siinä se on pitkälti! Nyt kokonaisuuden visualisoimiseksi, kun maalaamme jokaisen havaitun segmentin värillä tab20 silmukan ensimmäisen rivin kautta (colors = plt.get_cmap(“tab20”)(i)), sinun tarvitsee vain kirjoittaa:

o3d.visualization.draw_geometries([segments[i] for i in range(max_plane_idx)]+[rest])

🤓 HuomautuksiaLista [segments[i] for i in range(max_plane_idx)] että siirrymme funktioon o3d.visualization.draw_geometries() on itse asiassa "luettelon ymmärtäminen" 🤔. Se vastaa kirjoittamista a for silmukka, joka liittää ensimmäisen elementin segments[i] luetteloon. Kätevästi voimme sitten lisätä [rest] tähän luetteloon ja draw.geometries() menetelmä ymmärtää, että haluamme harkita yhden pistepilven piirtämistä. Kuinka siistiä?

RANSAC-pistepilvesegmentoinnin moniiteratiivisen prosessin tulos. © F. Poux

Hah! Luulemme, että olemme valmiita… Mutta olemmeko? Huomaatko tässä jotain outoa? Jos katsot tarkasti, siellä on outoja esineitä, kuten "viivoja", jotka todella leikkaavat joitain tasomaisia ​​elementtejä. Miksi? 🧐

Itse asiassa, koska sovitamme kaikki pisteet RANSAC-tasoehdokkaisiin (joilla ei ole raja-laajuutta euklidisessa avaruudessa) pistetiheyden jatkuvuudesta riippumatta, meillä on nämä "viivat" artefaktit riippuen siitä, missä järjestyksessä tasot havaitaan. Joten seuraava askel on estää tällainen käytös! Tätä varten ehdotan, että iteratiiviseen prosessiin sisällytetään euklidiseen klusterointiin perustuva ehto, joka tarkentaa vierekkäisten klustereiden sisäpistejoukkoja. Valmis?

Monipuolisen RANSAC-silmukan viisas jalostus DBSCANilla

Tätä varten luotamme DBSCAN-algoritmiin. Haluan yksityiskohtaisesti loogista prosessia, mutta ei niin suoraviivaista (Aktivoi petotila👹). Aiemmin määritellyssä for-silmukassa ajetaan DBSCAN juuri sen jälkeen, kun inliers (segments[i]=rest.select_by_index(inliers)), lisäämällä seuraava rivi heti perään:

labels = np.array(segments[i].cluster_dbscan(eps=d_threshold*10, min_points=10))

🤓 HuomautuksiaItse asiassa asetin epsilonin RANSAC-tasohaun alkukynnyksen funktiona, magnitudin ollessa 10 kertaa suurempi. Tämä ei ole syvätiedettä, tämä on puhtaasti empiirinen valinta, mutta toimii yleensä hyvin ja helpottaa parametrien kanssa 😀.

Sitten silmukan sisällä laskemme, kuinka monta pistettä kukin löytämämme klusteri sisältää, käyttämällä outoa merkintää, joka käyttää luettelon ymmärtämistä. Tulos tallennetaan sitten muuttujaan candidates:

candidates=[len(np.where(labels==j)[0]) for j in np.unique(labels)]

Ja nyt? Meidän on löydettävä "paras ehdokas", joka on yleensä se klusteri, jolla on enemmän pisteitä! Ja tätä varten tässä on rivi:

best_candidate=int(np.unique(labels)[np.where(candidates== np.max(candidates))[0]])

Okei, monia temppuja tapahtuu täällä konepellin alla, mutta pohjimmiltaan käytämme Numpy-taitoa etsiäksemme ja palauttaaksemme pisteiden indeksin, jotka kuuluvat suurimpaan klusteriin. Tästä eteenpäin se on laskettelua, ja meidän on vain lisättävä mahdolliset jäljellä olevat klusterit iteraatiota kohti seuraavissa RANSAC-iteraatioissa (🔥 lause luettava 5 kertaa sulattaaksesi):

rest = rest.select_by_index(inliers, invert=True) + segments[i].select_by_index(list(np.where(labels!=best_candidate)[0]))
segments[i]=segments[i].select_by_index(list(np.where(labels== best_candidate)[0]))

🤓 HuomautuksiaIshayoiden opettaman rest muuttuja varmistaa nyt, että sekä RNSAC:n että DBSCANin jäljellä olevat kohdat säilyvät. Ja tietysti, lisäkkeet suodatetaan nyt raaka-RANSAC-inlier-sarjan suurimpaan klusteriin.

Kun silmukka on ohi, saat puhtaan joukon segmenttejä, jotka sisältävät spatiaalisesti vierekkäisiä pistejoukkoja, jotka seuraavat tasomaisia ​​muotoja, kuten alla on esitetty.

Huomaa, että ratkaisimme "viiva"-ongelman, mutta meillä on edelleen joitakin harmaina elementtejä, jotka ovat vielä osoittamattomia pisteitä. © F. Poux

Mutta onko tämä loppu? Noooo, ei koskaan 😄! Viimeinen viimeinen askel!

Jäljellä olevien 3D-pisteiden klusterointi DBSCANilla

Lopuksi menemme silmukan ulkopuolelle ja käsittelemme jäljellä olevia lepotilaan tallennettuja elementtejä, joita ei vielä ole liitetty mihinkään segmenttiin. Tätä varten yksinkertaisen euklidisen klusteroinnin (DBSCAN) läpimenon pitäisi tehdä temppu:

labels = np.array(rest.cluster_dbscan(eps=0.05, min_points=5))
max_label = labels.max()
print(f"point cloud has {max_label + 1} clusters") colors = plt.get_cmap("tab10")(labels / (max_label if max_label > 0 else 1))
colors[labels < 0] = 0
rest.colors = o3d.utility.Vector3dVector(colors[:, :3])

Käytän samaa menetelmää kuin ennenkin, ei noituutta! Varmistan vain, että käytän yhtenäisiä parametreja saadakseni hienostuneen klusteroinnin saadaksesi kauniin sateenkaarikeittiön, josta olet aina haaveillut 🥳!

Tässä on lopullinen klusterointitulos nykyisellä lähestymistavalla! Onnittelut huipputason tasopohjaisen elementtien havaitsemisen saavuttamisesta, joita voit nyt käsitellä korkeampien näköprosessien perustana! © F. Poux

Jos haluat saada sen toimimaan suoraan, luon myös Google Colab -skriptin, johon pääset täältä: Python Google Colab -skriptiin.

Yhteenveto

Suuret onnittelut 🎉! Opit juuri tuomaan ja kehittämään automaattisen segmentointi- ja visualisointiohjelman miljoonista pisteistä koostuville 3D-pistepilville eri strategioilla! Vilpittömästi, hyvin tehty! Mutta polku ei todellakaan pääty tähän, koska avasit juuri valtavan potentiaalin älykkäille prosesseille, jotka syyttelevät segmenttitasolla!

Tulevat postaukset sukeltavat syvemmälle pistepilvien tilaanalyysiin, tiedostomuotoihin, tietorakenteisiin, objektien havaitsemiseen, segmentointiin, luokitteluun, visualisointiin, animaatioon ja verkostoitumiseen. Tarkastelemme erityisesti kuinka hallita Big Point -pilvitietoja kohdassa määritellyllä tavalla Tämä artikkeli.

Avustusteni tarkoituksena on tiivistää käyttökelpoista tietoa, jotta voit aloittaa 3D-automaatiojärjestelmien rakentamisen projekteillesi tyhjästä. Voit aloittaa tänään ottamalla muodostelman osoitteessa Geodata Akatemia.

Mennä kauemmas

Pistepilveä varten on olemassa muita kehittyneitä segmentointimenetelmiä. Se on itse asiassa tutkimusala, jossa olen syvästi mukana, ja artikkeleista löytyy jo hyvin suunniteltuja metodologioita [1–6]. Edistyneemmille 3D-syväoppimisarkkitehtuureille kattavia opetusohjelmia on tulossa pian!

  1. Poux, F., & Billen, R. (2019). Voxel-pohjainen 3D-pistepilven semanttinen segmentointi: valvomaton geometria ja suhde, jossa vs syväoppimismenetelmätISPRS International Journal of Geo-Information. 8(5), 213; - Jack Dangermond -palkinto (Linkki lehdistötiedotteeseen)
  2. Poux, F., Neuville, R., Nys, G.-A., & Billen, R. (2018). 3D-pistepilven semanttinen mallinnus: integroitu kehys sisätiloihin ja huonekaluihinKaukokartoitus10(9), 1412. 
  3. Poux, F., Neuville, R., Van Wersch, L., Nys, G.-A., & Billen, R. (2017). 3D-pistepilvet arkeologiassa: edistysaskeleet hankinnassa, prosessoinnissa ja tiedon integroinnissa sovellettaessa lähes tasomaisiin objekteihinGeosciences7(4), 96. 
  4. Poux, F., Mattes, C., Kobbelt, L., 2020. Sisätilojen 3D-pistepilven valvomaton segmentointi: sovellus oliopohjaiseen luokitukseen, ISPRS — International Archives of the Photogrammetria, Remote Sensing and Spatial Information Sciences. s. 111–118.
  5. Poux, F., Ponciano, JJ, 2020. Itseoppiva ontologia esimerkiksi 3D-sisäpistepilven segmentointiin, ISPRS — International Archives of Photogrammetry, Remote Sensing and Spatial Information Sciences. s. 309–316.
  6. Bassier, M., Vergauwen, M., Poux, F., (2020). Pistepilvi vs. verkkoominaisuudet rakennuksen sisätilojen luokittelussaKaukokartoitus. 12, 2224.

Tämä artikkeli julkaistiin alunperin Kohti datatieteitä ja julkaistu uudelleen TOPBOTS: lle tekijän luvalla.

Nauti tästä artikkelista? Tilaa lisää AI-päivityksiä.

Ilmoitamme sinulle, kun julkaisemme lisää teknistä koulutusta.

Lähde: https://www.topbots.com/automate-3d-point-cloud-segmentation/

Aikaleima:

Lisää aiheesta TOPBOTIT