4

私は opencv v2.2 を使用して ndarray でテンプレート マッチングを行ってい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)が実際には1つの場所にしか保存されておらず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 に答える