2012-02-13 42 views
5

Tengo una pregunta.Intersección de ndarrays 2D numpy

Tengo dos matrices numpy que son cáscaras convexas OpenCV y quiero verificar la intersección sin crear bucles o crear imágenes y realizar numpy.bitwise_and en ellas, las cuales son bastante lentas en Python. Las matrices se ven así:

[[[x1 y1]] 
[[x2 y2]] 
[[x3 y3]] 
... 
[[xn yn]]] 

Teniendo en cuenta [x1 y1 []] como un solo elemento, Quiero realizar intersección entre dos ndarrays numpy. ¿Cómo puedo hacer eso? He encontrado algunas preguntas de naturaleza similar, pero no pude encontrar la solución a esto desde allí.

¡Gracias de antemano!

Respuesta

0

Así que esto es lo que hice para hacer el trabajo:

import Polygon, numpy 

# Here I extracted and combined some contours and created a convex hull from it. 
# Now I wanna check whether a contour acquired differently intersects with this hull or not. 

for contour in contours: # The result of cv2.findContours is a list of contours 
    contour1 = contour.flatten() 
    contour1 = numpy.reshape(contour1, (int(contour1.shape[0]/2),-1)) 
    poly1 = Polygon.Polygon(contour1) 

    hull = hull.flatten() # This is the hull is previously constructued 
    hull = numpy.reshape(hull, (int(hull.shape[0]/2),-1)) 
    poly2 = Polygon.Polygon(hull) 

    if (poly1 & poly2).area()<= some_max_val: 
     some_operations 

tuve que usar para el lazo, y esto en conjunto parece un poco tedioso, aunque me da los resultados esperados. ¡Cualquier método mejor sería muy apreciado!

1

puede utilizar http://pypi.python.org/pypi/Polygon/2.0.4, aquí es un ejemplo:

>>> import Polygon 
>>> a = Polygon.Polygon([(0,0),(1,0),(0,1)]) 
>>> b = Polygon.Polygon([(0.3,0.3), (0.3, 0.6), (0.6, 0.3)]) 
>>> a & b 
Polygon: 
    <0:Contour: [0:0.60, 0.30] [1:0.30, 0.30] [2:0.30, 0.60]> 

para convertir el resultado de cv2.findContours a formato de coma polígono, se puede:

points1 = contours[0].reshape(-1,2) 

Esto convertirá la forma de (N, 1, 2) a (N, 2)

siguiente es un ejemplo completo:

import Polygon 
import cv2 
import numpy as np 
from scipy.misc import bytescale 

y, x = np.ogrid[-2:2:100j, -2:2:100j] 

f1 = bytescale(np.exp(-x**2 - y**2), low=0, high=255) 
f2 = bytescale(np.exp(-(x+1)**2 - y**2), low=0, high=255) 


c1, hierarchy = cv2.findContours((f1>120).astype(np.uint8), 
             cv2.cv.CV_RETR_EXTERNAL, 
             cv2.CHAIN_APPROX_SIMPLE) 

c2, hierarchy = cv2.findContours((f2>120).astype(np.uint8), 
             cv2.cv.CV_RETR_EXTERNAL, 
             cv2.CHAIN_APPROX_SIMPLE) 


points1 = c1[0].reshape(-1,2) # convert shape (n, 1, 2) to (n, 2) 
points2 = c2[0].reshape(-1,2) 

import pylab as pl 
poly1 = pl.Polygon(points1, color="blue", alpha=0.5) 
poly2 = pl.Polygon(points2, color="red", alpha=0.5) 
pl.figure(figsize=(8,3)) 
ax = pl.subplot(121) 
ax.add_artist(poly1) 
ax.add_artist(poly2) 
pl.xlim(0, 100) 
pl.ylim(0, 100) 

a = Polygon.Polygon(points1) 
b = Polygon.Polygon(points2) 
intersect = a&b # calculate the intersect polygon 

poly3 = pl.Polygon(intersect[0], color="green") # intersect[0] are the points of the polygon 
ax = pl.subplot(122) 
ax.add_artist(poly3) 
pl.xlim(0, 100) 
pl.ylim(0, 100) 
pl.show() 

Salida:

enter image description here

+0

¿Es este método realmente rápido? Necesito seguir buscando la intersección de cada fotograma mientras capturo, y los recursos del sistema no son muy altos. –

+0

Cuando intento crear un polígono a partir de un contorno de convec o casco convexo, este es el error que obtengo: 'cPolygon.Error: polígono o contorno no válido para la operación' El formato que ha especificado no es el formato que tengo (se muestra en mi publicación original). Supongo que algunas modificaciones pueden ser necesarias, pero no puedo imaginar cómo se podría hacer. –

+0

por favor publique algunos datos de muestra. – HYRY

9

Se puede utilizar una vista de la matriz como una sola dimensión a la función intersect1d así:

def multidim_intersect(arr1, arr2): 
    arr1_view = arr1.view([('',arr1.dtype)]*arr1.shape[1]) 
    arr2_view = arr2.view([('',arr2.dtype)]*arr2.shape[1]) 
    intersected = numpy.intersect1d(arr1_view, arr2_view) 
    return intersected.view(arr1.dtype).reshape(-1, arr1.shape[1]) 

Esto crea una vista de cada matriz, cambiando cada fila a una tupla de valores. Luego realiza la intersección y cambia el resultado al formato original. He aquí un ejemplo de su uso:

test_arr1 = numpy.array([[0, 2], 
         [1, 3], 
         [4, 5], 
         [0, 2]]) 

test_arr2 = numpy.array([[1, 2], 
         [0, 2], 
         [3, 1], 
         [1, 3]]) 

print multidim_intersect(test_arr1, test_arr2) 

Esta impresora:

[[0 2] 
[1 3]] 
+0

¡Muchas gracias por la respuesta! Esto sería perfecto si todos los puntos en el perímetro estuvieran en las matrices numpy. Sin embargo, en cascos convexos, creo que solo algunos puntos se pasan como guías. Pero la intersección, como significa en este caso, es valores comunes en ambas áreas, que pueden no ser comunes dentro de las matrices numpy. Acabo de leer mi publicación anterior, y me di cuenta de que no mencioné esto en absoluto. Lo siento por eso. –

+0

Cuando aplico su vista en mi numpy, se ve así: [[[x1,) (y1,)]] [[(x2,) (y2,)]] ... [[(xn,) (yn,)]]] Considerando que lo que realmente necesitamos es esto: [(x1, y1), (x2, y2), (x3, y3), ..., (xn, yn)] ¿Alguna idea? –

+0

¿Tiene un eje extra por alguna razón? ¿Puedes simplemente reformarlo primero con '' test_arr1.reshape (len (test_arr1), 2) ''? Eso evitará una copia. – jterrace

0

inspirado por la respuesta de jiterrace

me encontré con este post mientras se trabaja con Udacity deep learning class( tratando de encontrar la coincidencia entre los datos de entrenamiento y de prueba).

No estoy familiarizado con "ver" y encontré la sintaxis un poco difícil de entender, probablemente lo mismo cuando trato de comunicarme con mis amigos que piensan en "tabla". Mi enfoque es básicamente aplanar/remodelar la ndarray de forma (N, X, Y) en forma (N, X * Y, 1).

print(train_dataset.shape) 
print(test_dataset.shape) 
#(200000L, 28L, 28L) 
#(10000L, 28L, 28L) 

1).INNER JOIN (más fácil de entender, lento)

%%timeit -n 1 -r 1 
def multidim_intersect_df(arr1, arr2): 
    p1 = pd.DataFrame([r.flatten() for r in arr1]).drop_duplicates() 
    p2 = pd.DataFrame([r.flatten() for r in arr2]).drop_duplicates() 
    res = p1.merge(p2) 
    return res 
inters_df = multidim_intersect_df(train_dataset, test_dataset) 
print(inters_df.shape) 
#(1153, 784) 
#1 loop, best of 1: 2min 56s per loop 

2). SET INTERSECTION (rápido)

%%timeit -n 1 -r 1 
def multidim_intersect(arr1, arr2): 
    arr1_new = arr1.reshape((-1, arr1.shape[1]*arr1.shape[2])) # -1 means row counts are inferred from other dimensions 
    arr2_new = arr2.reshape((-1, arr2.shape[1]*arr2.shape[2])) 
    intersected = set(map(tuple, arr1_new)).intersection(set(map(tuple, arr2_new))) # list is not hashable, go tuple 
    return list(intersected) # in shape of (N, 28*28) 

inters = multidim_intersect(train_dataset, test_dataset) 
print(len(inters)) 
# 1153 
#1 loop, best of 1: 34.6 s per loop 
Cuestiones relacionadas