【问题标题】:How to convert a numpy array view to opencv matrix?如何将 numpy 数组视图转换为 opencv 矩阵?
【发布时间】:2011-07-31 07:30:59
【问题描述】:

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

【问题讨论】:

    标签: python arrays opencv numpy stride


    【解决方案1】:

    我认为您尝试做的问题是您感兴趣的数组数据(即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
    

    【讨论】:

    • 谢谢,这似乎可行,但我认为我无法在当前解决方案(制作数组的副本)上获得任何性能,因为 tostring() 方法似乎返回了一个副本反正。如果我错了,请纠正我..
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-30
    • 1970-01-01
    • 2016-11-19
    • 1970-01-01
    相关资源
    最近更新 更多