4

我正在使用 opencv v2.2 在 ndarrays 上进行一些模板匹配,并且在使用它们的 Wrapped 方法时遇到了内存泄漏问题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__所以我应该能够以某种方式以适当的步长跨越它?我不确定如何以一种好的方式做到这一点,因为这个基础也可以是另一个更大的数组无限的视图。

4

1 回答 1

2

我认为您尝试做的问题是您感兴趣的数组数据(即。foo_np_view)实际上只存储在一个地方,即foo_np.data,并且 OpenCVSetData方法没有提供任何方法来指定步幅设置允许您跳过不属于foo_np_view.

但是,您可以使用 Numpy 的tostring()方法解决此问题,该方法将数组(或其中的视图)转换为字节字符串:

>>> 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
于 2011-05-16T12:35:20.277 回答