2011-04-07 315 views
4

我使用opencv v2.2在ndarrays上做了一些模板匹配,当使用它们的包装方法cv.fromarray()时,我遇到了很大的内存泄漏问题。而不是插上内存泄漏我避免了fromarray()功能,直接使用cv.SetData,就像这样:如何将numpy数组视图转换为opencv矩阵?

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()(如果foo_numpy.base != None)来解决这个问题,它允许获取新副本上的缓冲区。但我有这种感觉,这是不必要的,该片有__array_struct____array_interface__,所以我应该能够用适当的步骤以某种方式跨步它?我不知道如何以一种很好的方式来做到这一点,因为这一个基地也可以在另一个更大的数组无限期的视图。

回答

2

我想与你试图做的问题是,数组数据你感兴趣的(即foo_np_view)实际上是只存储在一个地方,即foo_np.data和OpenCV的SetData方法不提供任何指定跨度设置的方法,这将允许您跳过不属于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 
+0

感谢,这似乎工作,但我不认为我可以获得任何性能超过我目前的解决方案(制作数组的副本),因为tostring()方法似乎无论如何都会返回一个副本。如我错了请纠正我.. – wim 2011-05-17 07:20:14