Ajustar líneas a través de grandes nubes de puntos

8

Tengo un gran conjunto de puntos (orden de 10k puntos) formados por pistas de partículas (movimiento en el plano xy en el tiempo filmado por una cámara, por lo que 3D - 256x256px y ca 3k fotogramas en mi conjunto de ejemplo) y ruido. Estas partículas viajan aproximadamente en líneas rectas aproximadamente (pero solo aproximadamente) en la misma dirección, por lo que para el análisis de sus trayectorias estoy tratando de ajustar las líneas a través de los puntos. Traté de usar RANSAC secuencial, pero no puedo encontrar un criterio para identificar con seguridad los falsos positivos, así como el enlace T y J, que eran demasiado lentos y tampoco lo suficientemente confiables.

Aquí hay una imagen de una parte del conjunto de datos con ajustes buenos y malos que obtuve con Ransac secuencial: ingrese la descripción de la imagen aquí estoy usando los centroides de los blobs de partículas aquí, los tamaños de blob varían entre 1 y aproximadamente 20 píxeles.

Descubrí que las submuestras que utilizan, por ejemplo, solo cada décimo fotograma también funcionaban bastante bien, por lo que el tamaño de los datos a procesar se puede reducir de esta manera.

Leí una publicación de blog sobre todas las cosas que las redes neuronales pueden lograr, y me gustaría preguntarle si esta sería una aplicación viable para uno antes de comenzar a leer (vengo de un entorno no matemático, por lo que tendría que hacer bastante un poco de lectura)

¿O podrías sugerir un método diferente?

¡Gracias!

Anexo: Aquí hay un código para una función de Matlab para generar una nube de puntos de muestra que contiene 30 líneas ruidosas paralelas, que aún no puedo distinguir:

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
Lukas K.
fuente
si nos proporciona un conjunto de datos de muestra, o un conjunto de datos falso que sea lo suficientemente similar a su conjunto de datos real, o una imagen de un conjunto de datos real o falso, podría obtener una mejor respuesta. No se dice si es 2d o 3d - o 4d ...
Spacedman
No pensé que tendría que ser tan específico. Actualizado de todos modos
Lukas K.
Ooh, eso es mucho más interesante de lo que pensaba. Tienes toda una nube de puntos que pertenecen a una gran cantidad de líneas diferentes y algunos puntos ruidosos que no lo hacen, e idealmente quieres encontrar todas las líneas, incluso las más pequeñas como las 3 o 4 en la parte inferior derecha ...
Spacedman
Me alegra que el problema sea interesante, ahora espero que alguien pueda ayudarme con él :)
Lukas K.
ah, pero no son coordenadas continuas de puntos x, y, T sino un montón de rásteres binarios (0/1)? Y si se cruzan dos pistas, puede obtener un píxel que pertenece a más de una pista ...
Spacedman

Respuestas:

3

Basado en la retroalimentación y tratando de encontrar un enfoque más efectivo, desarrollé el siguiente algoritmo usando una medida de distancia dedicada.

Se realizan los siguientes pasos:

1) Definir una distancia métrica de retorno:

cero : si los puntos no pertenecen a una línea

Distancia euclidiana de los puntos : si los puntos constituyen una línea de acuerdo con los parámetros definidos, es decir

  • su distancia es mayor o igual que min_line_length y

  • su distancia es menor o igual que max_line_length y

  • la línea consta de al menos min_line_points puntos con una distancia menor que line_width / 2 desde la línea

2) Calcule la matriz de distancia usando esta medida de distancia (use una muestra de los datos para grandes conjuntos de datos; ajuste los parámetros de línea en consecuencia)

3) Encuentre los puntos A y B con la distancia máxima - vaya al paso 5) si la distancia es cero

Tenga en cuenta que si la distancia es mayor que cero, los puntos A y B están construyendo una línea basada en nuestra definición

4) Obtenga todos los puntos que pertenecen a la línea AB y elimínelos de la matriz de distancia. Repita el paso 3) para encontrar otra línea.

5) Verifique la cobertura del punto con las líneas seleccionadas, si un número sustancial de puntos permanece sin cubrir, repita todo el algoritmo con los parámetros de línea ajustados.

6) En caso de que se usó una muestra de datos, reasigne todos los puntos a las líneas y recalcule los puntos límite.

Se utilizan los siguientes parámetros:

ancho de línea - ancho_línea / 2 es la distancia permitida del punto desde la línea ideal = r line_width

longitud mínima de línea : los puntos con una distancia más corta no se consideran pertenecientes a la misma línea = r min_line_length

longitud máxima de la línea : los puntos con una distancia más larga no se consideran pertenecientes a la misma línea = r max_line_length

puntos mínimos en una línea : se ignoran las líneas con menos puntos =r min_line_points

Con sus datos (después de jugar con los parámetros) obtuve un buen resultado cubriendo las 30 líneas.

ingrese la descripción de la imagen aquí

Se pueden encontrar más detalles en el script de knitr

Bombardero Marmite
fuente
2

Resolví una tarea similar, aunque más simple, con un enfoque de fuerza bruta. La simplificación estaba en el supuesto de que la línea es una función lineal (en mi caso, incluso los coeficientes y la intersección estaban en algún rango conocido).

Por lo tanto, esto no resolverá su problema en general, donde una partícula puede moverse ortogonal con el eje x (es decir, no traza ninguna función), pero publico la solución como una posible inspiración.

1) Tome todas las combinaciones de dos puntos A y B con A (x)> B (x) + constante (para evitar la simetría y un alto error al calcular el coeficiente)

2) Calcule el coeficiente c e intercepte i de la línea 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) Redondear el coeficiente e interceptar (esto debería eliminar / disminuir los problemas con errores causados ​​por los puntos en una cuadrícula)

4) Para cada intersección y coeficiente, calcule el número de puntos en esta línea

5) Considere solo líneas con puntos por encima de algún umbral.

Ejemplo simple ver aquí

Bombardero Marmite
fuente
Eso es básicamente lo que estoy haciendo con RANSAC (excepto que uso muestreo aleatorio en lugar de probar todas las combinaciones). El problema para mí no es ajustar algunas líneas, el problema es que ajusto demasiadas líneas, porque con tantos puntos cercanos, incluso una línea sesgada encontrará suficientes inliers dentro de cualquier umbral razonable. Así que estoy buscando un criterio para distinguir las líneas que se ajustan a las líneas "reales" de otras.
Lukas K.
1
No estoy seguro si es realmente el mismo enfoque. No distingo entre el punto en una línea y el valor atípico . Estoy considerando si dos vectores pueden o no pertenecer a una misma línea. Creo que esto podría ser mucho más exacto. Además, uso parámetros de ancho de línea , longitud de línea mínima y puntos de línea mínimos para controlar la selección.
Marmite Bomber
OK veo. Aunque con 10k puntos y (10E + 5 elija 2) = 5E + 11 pares posibles, tendré que hacer un muestreo aleatorio. Además, esto probablemente sea bastante sensible en las desviaciones de una línea recta, lo que podría cambiar la intercepción. ¡Pero lo intentaré! Piensa como longitud mínima y mínimo no. de puntos en línea que ya usé en mis intentos de limpiar los resultados.
Lukas K.