2012-02-13 2 views
5

У меня вопрос.Пересечение 2D numpy ndarrays

У меня есть два массива numpy, которые являются выпуклыми оболочками OpenCV, и я хочу проверить пересечение без создания циклов или создания изображений и выполнения на них numpy.bitwise_and, оба из которых довольно медленны в Python. Массивы выглядеть следующим образом:

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

Учитывая [[x1 y1]] в качестве одного элемента, я хочу, чтобы выполнить пересечение между двумя Numpy ndarrays. Как я могу это сделать? Я нашел несколько вопросов подобного характера, но я не мог понять решение этого оттуда.

Заранее благодарен!

ответ

0

Так это то, что я сделал, чтобы получить работу:

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 

мне пришлось использовать цикл, и это в целом выглядит немного утомительно, хотя это дает мне ожидаемые результаты. Любые лучшие методы будут очень признательны!

1

вы можете использовать http://pypi.python.org/pypi/Polygon/2.0.4, вот пример:

>>> 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]> 

Для преобразования результата cv2.findContours в формате точки Polygon, вы можете:

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

Это будет преобразовывать форму из (N, N 1, 2) (N, 2)

Ниже приводится полный пример:

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() 

Выход:

enter image description here

+0

Действительно ли этот метод работает быстро? Мне нужно следить за пересечением каждого кадра во время захвата, а системный ресурс не очень высок. –

+0

Когда я пытаюсь создать многоугольник из контура opencv или выпуклой оболочки, это ошибка, которую я получаю: 'cPolygon.Error: Недопустимый полигон или контур для операции' Формат, который вы указали, отличается от формата, который у меня есть (показано в моем оригинальном посте). Я предполагаю, что некоторые изменения могут потребоваться, но не представляю, как это можно сделать. –

+0

, пожалуйста, отправьте несколько примеров данных. – HYRY

9

Вы можете использовать представление массива в одном измерении в intersect1d функции, как это:

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]) 

Это создает представление каждого массива, изменение каждая строка соответствует кортежу значений. Затем он выполняет пересечение и возвращает результат в исходный формат. Вот пример его использования:

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) 

Печатается:

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

Большое спасибо за ответ! Это было бы прекрасно, если бы все точки в периметре были в массивах numpy. Тем не менее, в выпуклых корпусах, я думаю, что только несколько пунктов передаются в качестве путеводителей. Но пересечение, поскольку это означает в этом случае, является общими значениями в обеих областях, которые могут не распространяться внутри самих массивов numpy. Я только что прочитал свой пост выше и понял, что вообще не упоминал об этом. Я прошу прощения за это. –

+0

Когда я применяю ваш взгляд на свой numpy, он выглядит так: [[[(x1,) (y1,)]] [[(x2,) (y2,)]] ... [[(xn, (yn,)]]] Принимая во внимание то, что нам действительно нужно: [(x1, y1), (x2, y2), (x3, y3), ..., (xn, yn)] Любые идеи? –

+0

У вас просто есть лишняя ось по какой-то причине? Можете ли вы просто изменить его сначала с помощью '' test_arr1.reshape (len (test_arr1), 2) ''? Это позволит избежать копирования. – jterrace

0

вдохновлен ответом jiterrace в

я наткнулся на этот пост во время работы с Udacity deep learning class( пытается найти перекрытие между данными подготовки и тестирования).

Я не знаком с «представлением» и нашел синтаксис немного трудно понять, возможно, тот же, когда я пытаюсь общаться с моими друзьями, которые думают в «таблице». Мой подход в основном состоит в том, чтобы сплющить/изменить форму формы (N, X, Y) в форму (N, X * Y, 1).

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

1).INNER JOIN (легче понять, замедлиться)

%%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 (быстро)

%%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 
Смежные вопросы