Как преобразовать представление массива в матрицу opencv? - PullRequest
4 голосов
/ 07 апреля 2011

Я использую opencv v2.2 для сопоставления некоторых шаблонов на ndarrays, и у меня возникли большие проблемы с утечками памяти при использовании их метода обтекания cv.fromarray(). Вместо того, чтобы устранить утечки памяти, я избежал функции fromarray() и использовал cv.SetData напрямую, например:

assert foo_numpy.dtype == 'uint8'
assert foo_numpy.ndim == 3
h, w = foo_numpy.shape[:2]
foo_cv = cv.CreateMat(h, w, cv.CV_8UC3)
cv.SetData(foo_cv, foo_numpy.data, foo_numpy.strides[0])

Похоже, что это устраняет утечки памяти, а foo_cv, кажется, освобождается должным образом, когда выходит из области видимости. Тем не менее, теперь у меня есть проблема, где, если foo_numpy - это просто фрагмент / представление на большем массиве, мне не разрешено foo_numpy.data (невозможно получить односегментный буфер для несмежного массива). В данный момент я работаю над этим, делая foo_numpy.copy() if foo_numpy.base != None, что позволяет получить буфер для новой копии. Но я чувствую, что в этом нет необходимости, у среза есть __array_struct__ и __array_interface__, поэтому я должен быть в состоянии как-то просто обработать его соответствующими шагами? Я не уверен, как сделать это хорошим способом, потому что основой этого также может быть представление о другом большем массиве до бесконечности.

1 Ответ

2 голосов
/ 16 мая 2011

Я думаю, что проблема с тем, что вы пытались сделать, заключается в том, что интересующие вас массивы данных (т.е. foo_np_view) на самом деле хранятся только в одном месте, т.е. foo_np.data, и метод OpenCV SetData. не предоставляет никакого способа указать настройки шага, которые позволили бы вам пропускать байты, которые не являются частью foo_np_view.

Однако вы можете обойти эту проблему, используя метод tostring() Numpy, который превращает массив (или представления в нем) в байтовую строку:

>>> import numpy as np
>>> import cv
>>> foo_np = np.array( 255 * np.random.rand( 200 , 300 , 3 ), dtype = 'uint8' )
>>> foo_np_view = foo_np [ 50:150:2 , 10:290:5 , : ]
>>> h,w,d = foo_np_view.shape
>>> foo_cv = cv.CreateMat( h , w , cv.CV_8UC3 )

Воссоздание исходной задачи:

>>> cv.SetData( foo_cv , foo_np_view.data, foo_np_view.strides[0] )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: cannot get single-segment buffer for discontiguous array

Используя метод tostring() (объяснение настройки шага см. Ниже):

>>> cv.SetData( foo_cv , foo_np_view.tostring() , w * d * foo_np_view.dtype.itemsize )
>>> np.array_equal( np.asarray( foo_cv ) , foo_np_view )
True

Значение w * d * foo_np_view.dtype.itemsize дает нам значение шага, идентичное значению foo_np_view.copy(), которое необходимо, поскольку строковые представления вида и его копии идентичны:

>>> foo_np_view.copy().tostring() == foo_np_view.tostring()
True
>>> foo_np_view.copy().strides[0] == w * d * foo_np_view.dtype.itemsize
True
...