Adattamento di linee attraverso grandi nuvole di punti


8

Ho una grande serie di punti (ordine di 10k punti) formati da tracce di particelle (movimento nel piano xy nel tempo filmato da una telecamera, quindi fotogrammi 3d - 256x256px e ca 3k nel mio set di esempio) e rumore. Queste particelle viaggiano approssimativamente su linee rette approssimativamente (ma solo approssimativamente) nella stessa direzione, e quindi per l'analisi delle loro traiettorie sto cercando di adattare le linee attraverso i punti. Ho provato a usare Sequential RANSAC, ma non riesco a trovare un criterio per individuare in modo affidabile falsi positivi, così come T-e J-Linkage, che erano troppo lenti e anche non abbastanza affidabili.

Ecco un'immagine di una parte del set di dati con adattamenti positivi e negativi che ho ottenuto con Ransac sequenziale: inserisci qui la descrizione dell'immagine sto usando i centroidi dei BLOB di particelle, le dimensioni dei BLOB variano tra 1 e circa 20 pixel.

Ho scoperto che anche i sottocampioni che utilizzano ad esempio solo ogni decimo frame hanno funzionato abbastanza bene, quindi la dimensione dei dati da elaborare può essere ridotta in questo modo.

Ho letto un post sul blog su tutto ciò che le reti neurali possono realizzare e vorrei chiederti se questa sarebbe un'applicazione fattibile per una prima di iniziare a leggere (vengo da un background non matematico, quindi dovrei fare abbastanza un po 'di lettura)?

O potresti suggerire un metodo diverso?

Grazie!

Addendum: ecco il codice per una funzione Matlab per generare una nuvola di punti campione contenente 30 linee rumorose parallele, che non riesco ancora a distinguere:

function coords = generateSampleData()
coords = [];
for i = 1:30
    randOffset = i*2;
    coords = vertcat(coords, makeLine([100+randOffset 100 100], [200+randOffset 200 200], 150, 0.2));
end

figure
scatter3(coords(:,1),coords(:,2),coords(:,3),'.')

function linepts = makeLine(startpt, endpt, numpts, noiseOffset)
    dirvec = endpt - startpt;
    linepts = bsxfun( @plus, startpt, rand(numpts,1)*dirvec); % random points on line
    linepts = linepts + noiseOffset*randn(numpts,3); % add random offsets to points
end

end

se ci fornisci un set di dati di esempio o un set di dati falso sufficientemente simile al tuo set di dati reale o un'immagine di un set di dati reale o falso, potresti ottenere una risposta migliore. Non devi dire se è 2d o 3d - o 4d ...
Spacedman il

Non pensavo che avrebbe dovuto essere così specifico. Aggiornato comunque
Lukas K.

Ooh, è molto più interessante di quanto pensassi. Hai un'intera nuvola di punti che appartengono a un gran numero di linee diverse e alcuni punti rumorosi che non lo fanno, e idealmente vuoi trovare tutte le linee, anche quelle piccole come le 3 o le 4 in basso a destra ...
Spacedman,

Sono contento che il problema sia interessante, ora spero che qualcuno possa aiutarmi con esso :)
Lukas K.

ah, ma non sono le coordinate continue dei punti x, y, T ma un gruppo di raster binari (0/1)? E se due tracce si incrociano potresti ottenere un pixel che appartiene a più di una traccia ...
Spacedman

Risposte:


3

Basandomi sul feedback e cercando di trovare un approccio più efficace, ho sviluppato il seguente algoritmo utilizzando una misura di distanza dedicata.

Vengono eseguiti i seguenti passaggi:

1) Definire una metrica di distanza che ritorna:

zero - se i punti non appartengono a una linea

Distanza euclidea dei punti - se i punti costituiscono una linea secondo i parametri definiti, ad es

  • la loro distanza è maggiore o uguale a min_line_length e

  • la loro distanza è inferiore o uguale a max_line_length e

  • la linea è composta da almeno min_line_points punti con una distanza inferiore a line_width / 2 dalla linea

2) Calcola la matrice della distanza usando questa misura della distanza (usa un campione di dati per grandi serie di dati; regola i parametri della linea di conseguenza)

3) Trova i punti A e B con la distanza massima - passa al punto 5) se la distanza è zero

Nota che se la distanza è maggiore di zero i punti A e B stanno costruendo una linea in base alla nostra definizione

4) Ottieni tutti i punti appartenenti alla linea AB e rimuovili dalla matrice della distanza. Ripetere il passaggio 3) per trovare un'altra riga

5) Controllare la copertura del punto con le linee selezionate, se rimane scoperto un numero considerevole di punti, ripetere l'intero algoritmo con i parametri della linea regolati.

6) Nel caso in cui sia stato utilizzato il campione di dati, riassegnare tutti i punti alle linee e ricalcolare i punti di confine.

Vengono utilizzati i seguenti parametri:

larghezza della linea - line_width / 2 è la distanza consentita del punto dalla linea ideale = r line_width

lunghezza minima della linea - i punti con distanza più breve non sono considerati appartenenti alla stessa linea = r min_line_length

lunghezza massima della linea : i punti con una distanza maggiore non sono considerati appartenenti alla stessa linea = r max_line_length

punti minimi su una linea - le linee con meno punti vengono ignorate =r min_line_points

Con i tuoi dati (dopo aver armeggiato con i parametri) ho ottenuto un buon risultato coprendo tutte e 30 le linee.

inserisci qui la descrizione dell'immagine

Maggiori dettagli sono disponibili nello script knitr


2

Ho risolto un compito simile, anche se più semplice, con un approccio a forza bruta. La semplificazione era nell'ipotesi che la linea fosse una funzione lineare (nel mio caso anche i coefficienti e l'intercetta erano in un intervallo noto).

Questo quindi non risolverà il tuo problema in generale, in cui una particella può spostarsi ortogonalmente all'asse x (cioè non traccia alcuna funzione), ma inserisco la soluzione come possibile ispirazione.

1) Prendi tutte le combinazioni di due punti A e B con A (x)> B (x) + costante (per evitare la simmetria e un errore elevato durante il calcolo del coefficiente)

2) Calcola il coefficiente c e intercetta i della linea AB

 A(y) = i + c * A(x)
 B(y) = i + c * B(x)
 A(y) - B(y) = c * (A(x) - B(x))
 c = (A(y) - B(y)) / (A(x) - B(x))
 i = A(y) - c * A(x)

3) Arrotondare il coefficiente e intercettare (questo dovrebbe eliminare / ridurre i problemi con errori causati dai punti in una griglia)

4) Per ogni intercetta e coefficiente calcolare il numero di punti su questa linea

5) Considera solo le linee con punti sopra una certa soglia.

Esempio semplice vedi qui


Questo è fondamentalmente quello che sto facendo con RANSAC (tranne per il fatto che utilizzo il campionamento casuale invece di provare tutte le combinazioni). Il problema per me non sta adattando alcune linee, il problema è che ho adattato troppe linee, perché solo con così tanti punti vicini, anche una linea obliqua troverà abbastanza inlier entro qualsiasi soglia ragionevole. Quindi sto cercando un criterio per distinguere le linee che si adattano alle linee "reali" dagli altri.
Lukas K.,

1
Non sono sicuro che sia davvero lo stesso approccio. Non faccio distinzione tra il punto su una linea e un valore anomalo . Sto valutando se due vettori possono appartenere o meno a una stessa linea. Penso che questo potrebbe essere molto più esatto. Additioanly Uso parametri spessore della linea , lunghezza minima linea e punti di linea minimi per il controllo della selezione.
Marmite Bomber,

ok capisco. Sebbene con 10k punti e (10E + 5 scegli 2) = 5E + 11 possibili coppie, dovrò fare un campionamento casuale. Anche questo è probabilmente molto sensibile alle deviazioni da una linea retta, che potrebbe cambiare l'intercetta. Ma ci proverò! Pensa come lunghezza minima e minimo n. di punti on line che ho già usato nei miei tentativi di ripulire i risultati.
Lukas K.,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.