2011-04-07 307 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