如何将 numpy 数组视图转换为 opencv 矩阵?

发布于 2024-10-31 07:35:35 字数 785 浏览 7 评论 0原文

我正在使用 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< /code> 超出范围时似乎已正确释放。但是,现在我遇到的问题是,如果 foo_numpy 只是更大数组上的切片/视图,则不允许 foo_numpy.data (无法获取单段缓冲区对于不连续的数组)。目前,我正在通过设置 foo_numpy.copy() if foo_numpy.base != None 来解决这个问题,这允许在新副本上获取缓冲区。但我觉得这是不必要的,切片有 __array_struct__ 和 __array_interface__ 所以我应该能够以适当的步长以某种方式跨过它?我不知道如何以一种好的方式做到这一点,因为这个的基础也可以是另一个更大的数组的视图。

I'm using opencv v2.2 to do some template matching on ndarrays, and I had great trouble with memory leaks when using their wrapped method cv.fromarray(). Rather than plug the memory leaks I avoided the fromarray() function and used cv.SetData directly, like this:

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])

This seems to solve the memory leaks and foo_cv seems to be deallocated properly when it goes out of scope. However, now I have the issue where if foo_numpy is just a slice/view on a bigger array, I'm not permitted foo_numpy.data (cannot get single-segment buffer for discontiguous array). At the moment I'm working around this by making foo_numpy.copy() if foo_numpy.base != None, which permits getting the buffer on the new copy. But I have the feeling this is unnecessary, the slice has the __array_struct__ and __array_interface__ so I should be able to just stride it with the appropriate stepsizes somehow? I'm not sure how to do it in a nice way, because the base of this one can also be a view on another larger array ad infinitum.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

怼怹恏 2024-11-07 07:35:35

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

I think the problem with what you were trying to do is that the array data you're interested in (ie. foo_np_view) is actually only stored in one place i.e. foo_np.data, and the OpenCV SetData method doesn't provide any way to specify stride settings that would allow you to skip the bytes that are not part of foo_np_view.

You can, however, get around this problem using Numpy’s tostring() method, which turns an array (or views therein) into a byte string:

>>> 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 )

Recreating the original problem:

>>> 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

Using the tostring() method (see below for explanation of the stride setting):

>>> 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

The value w * d * foo_np_view.dtype.itemsize gives us a stride value identical to that of foo_np_view.copy(), which is necessary as the string representations of the view and its copy are identical:

>>> foo_np_view.copy().tostring() == foo_np_view.tostring()
True
>>> foo_np_view.copy().strides[0] == w * d * foo_np_view.dtype.itemsize
True
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文