Python OpenCV Cython桥内存泄漏
我已经编写了一个Python OpenCV Cython桥内存泄漏,python,c++,opencv,cython,Python,C++,Opencv,Cython,我已经编写了一个视频捕获类的实现,该类可以与Basler摄像机一起工作。它是这样使用的: import cv2 import PyBaslerCamera video = PyBaslerCamera.PyBaslerCamera() video.open(0) while True: ret, image = video.read() cv2.imshow("Test", image) cv2.waitKey(1) # distutils: language = c
视频捕获
类的实现,该类可以与Basler摄像机一起工作。它是这样使用的:
import cv2
import PyBaslerCamera
video = PyBaslerCamera.PyBaslerCamera()
video.open(0)
while True:
ret, image = video.read()
cv2.imshow("Test", image)
cv2.waitKey(1)
# distutils: language = c++
# distutils: sources = BaslerCamera.cpp
from cython.operator cimport dereference as deref
from cpython.ref cimport PyObject
from libcpp cimport bool
cdef extern from "opencv2/core/core.hpp" namespace "cv":
cdef cppclass Mat:
bool empty() const
void release() const
cdef cppclass _OutputArray:
Mat getMat(int idx=-1) const
cdef extern from "cv2.cpp":
void import_array()
PyObject* pyopencv_from(const Mat&)
int pyopencv_to(PyObject*, Mat&)
cdef Mat np2mat(object array):
cdef Mat mat
cdef PyObject* pyobject = <PyObject*> array
pyopencv_to(pyobject, mat)
return <Mat>mat
cdef object mat2np(const Mat &mat):
return <object> pyopencv_from(mat)
cdef extern from "BaslerCamera.h" namespace "cv":
cdef cppclass BaslerCamera:
BaslerCamera()
bool open(int index)
bool isOpened()
void release()
bool grab()
Mat retrieve()
bool read(_OutputArray image)
Mat read()
bool set(int propId, double value)
double get(int propId)
BaslerCamera &operator>>(Mat &image)
cdef class PyBaslerCamera:
cdef BaslerCamera *thisptr
cdef Mat mat
def __cinit__(self):
print("PyBaslerCamera init")
import_array()
self.thisptr = new BaslerCamera()
def __dealloc__(self):
del self.thisptr
def open(self, int index = 0):
self.thisptr.open(index)
def read(self):
mat = self.thisptr.read()
if mat.empty():
return (False, None)
else:
out = mat2np(mat)
return (True, out)
我的Cython文件如下所示:
import cv2
import PyBaslerCamera
video = PyBaslerCamera.PyBaslerCamera()
video.open(0)
while True:
ret, image = video.read()
cv2.imshow("Test", image)
cv2.waitKey(1)
# distutils: language = c++
# distutils: sources = BaslerCamera.cpp
from cython.operator cimport dereference as deref
from cpython.ref cimport PyObject
from libcpp cimport bool
cdef extern from "opencv2/core/core.hpp" namespace "cv":
cdef cppclass Mat:
bool empty() const
void release() const
cdef cppclass _OutputArray:
Mat getMat(int idx=-1) const
cdef extern from "cv2.cpp":
void import_array()
PyObject* pyopencv_from(const Mat&)
int pyopencv_to(PyObject*, Mat&)
cdef Mat np2mat(object array):
cdef Mat mat
cdef PyObject* pyobject = <PyObject*> array
pyopencv_to(pyobject, mat)
return <Mat>mat
cdef object mat2np(const Mat &mat):
return <object> pyopencv_from(mat)
cdef extern from "BaslerCamera.h" namespace "cv":
cdef cppclass BaslerCamera:
BaslerCamera()
bool open(int index)
bool isOpened()
void release()
bool grab()
Mat retrieve()
bool read(_OutputArray image)
Mat read()
bool set(int propId, double value)
double get(int propId)
BaslerCamera &operator>>(Mat &image)
cdef class PyBaslerCamera:
cdef BaslerCamera *thisptr
cdef Mat mat
def __cinit__(self):
print("PyBaslerCamera init")
import_array()
self.thisptr = new BaslerCamera()
def __dealloc__(self):
del self.thisptr
def open(self, int index = 0):
self.thisptr.open(index)
def read(self):
mat = self.thisptr.read()
if mat.empty():
return (False, None)
else:
out = mat2np(mat)
return (True, out)
<代码> diditul:语言= C++
#distutils:sources=BaslerCamera.cpp
从cython.operator cimport将解引用作为解引用
从cpython.ref cimport PyObject
来自libcpp cimport bool
来自“opencv2/core/core.hpp”命名空间“cv”的cdef外部:
cdef CPP类材料:
bool empty()常量
无效释放()常量
cdef CPP类输出阵列:
Mat getMat(int idx=-1)常量
来自“cv2.cpp”的cdef外部:
无效导入_数组()
PyObject*pyopencv_from(const Mat&)
int pyopencv_to(PyObject*,Mat&)
cdef Mat np2mat(对象阵列):
cdef垫
cdef PyObject*PyObject=数组
pyopencv_to(pyobject,mat)
回程垫
cdef对象mat2np(常数Mat和Mat):
从(mat)返回pyopencv_
“BaslerCamera.h”命名空间“cv”中的cdef外部:
cdef CPP类BaslerCamera:
巴斯勒照相机()
布尔开放(整数索引)
bool isOpened()
无效释放()
bool-grab()
Mat检索()
布尔读取(输出阵列图像)
Mat read()
布尔集合(int-propId,双值)
双get(int-propId)
BaslerCamera&operator>>(材料和图像)
cdef类PyBaslerCamera:
cdef BaslerCamera*此PTR
cdef垫
定义(自我):
打印(“PyBaslerCamera初始化”)
导入数组()
self.thisptr=新BaslerCamera()
def uu dealoc uu(自我):
del self.thisptr
def打开(自身,int索引=0):
self.thisptr.open(索引)
def读取(自):
mat=self.thisptr.read()
如果mat.empty():
返回(假,无)
其他:
out=mat2np(mat)
返回(True,out)
我使用了OpenCV中的cv2.cpp文件:
现在,一切都正常了,我正在从摄像机获取视频流,但问题是它泄漏了很多(在几秒钟内它会填满我的内存,这让我相信它只是泄漏了所有的帧)。Valgrind似乎证实了这一点
==21435== 1,050,624,000 bytes in 152 blocks are possibly lost in loss record 5,939 of 5,939
==21435== at 0x4C2BBA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21435== by 0x20D7F3AB: ??? (in /usr/lib/python3/dist-packages/numpy/core/multiarray.cpython-34m-x86_64-linux-gnu.so)
==21435== by 0x20D1BD89: ??? (in /usr/lib/python3/dist-packages/numpy/core/multiarray.cpython-34m-x86_64-linux-gnu.so)
==21435== by 0x251D55E1: NumpyAllocator::allocate(int, int const*, int, void*, unsigned long*, int, cv::UMatUsageFlags) const (cv2.cpp:156)
==21435== by 0xB983720: cv::Mat::create(int, int const*, int) (in /usr/local/lib/libopencv_core.so.3.0.0)
==21435== by 0xB9B54C7: cv::_OutputArray::create(int, int, int, int, bool, int) const (in /usr/local/lib/libopencv_core.so.3.0.0)
==21435== by 0xB810A7C: cv::Mat::copyTo(cv::_OutputArray const&) const (in /usr/local/lib/libopencv_core.so.3.0.0)
==21435== by 0x251D44F9: pyopencv_from<cv::Mat> (cv2.cpp:211)
==21435== by 0x251D44F9: __pyx_f_14PyBaslerCamera_mat2np (PyBaslerCamera.cpp:662)
==21435== by 0x251D44F9: __pyx_pf_14PyBaslerCamera_14PyBaslerCamera_6read(__pyx_obj_14PyBaslerCamera_PyBaslerCamera*) [clone .isra.9] (PyBaslerCamera.cpp:973)
==21435== by 0x503F5C: PyEval_EvalFrameEx (in /usr/bin/python3.4)
==21435== by 0x5A9CB4: PyEval_EvalCodeEx (in /usr/bin/python3.4)
==21435== by 0x5E7104: ??? (in /usr/bin/python3.4)
==21435== by 0x5E71C8: PyRun_FileExFlags (in /usr/bin/python3.4)
==21435==
==21435== LEAK SUMMARY:
==21435== definitely lost: 165,107 bytes in 262 blocks
==21435== indirectly lost: 179,724,840 bytes in 205 blocks
==21435== possibly lost: 1,057,720,529 bytes in 646 blocks
==21435== still reachable: 9,399,307 bytes in 10,288 blocks
==21435== suppressed: 0 bytes in 0 blocks
==21435== Reachable blocks (those to which a pointer was found) are not shown.
==21435== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==21435==1050624000字节(152个块)可能在5939的丢失记录5939中丢失
==21435==0x4C2BBA0:malloc(在/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so中)
==21435==0x20D7F3AB:???(在/usr/lib/python3/dist-packages/numpy/core/multiarray.cpython-34m-x86_64-linux-gnu.so中)
==21435==0x20D1BD89:???(在/usr/lib/python3/dist-packages/numpy/core/multiarray.cpython-34m-x86_64-linux-gnu.so中)
==21435==by 0x251D55E1:NumpyAllocator::allocate(int,int const*,int,void*,unsigned long*,int,cv::UMatUsageFlags)const(cv2.cpp:156)
==21435==by 0xB983720:cv::Mat::create(int,int const*,int)(在/usr/local/lib/libopencv_core.so.3.0.0中)
==21435==by 0xB9B54C7:cv:_OutputArray::create(int,int,int,int,bool,int)const(在/usr/local/lib/libopencv_core.so.3.0.0中)
==21435==by 0xB810A7C:cv::Mat::copyTo(cv:_outputarrayconst&)const(in/usr/local/lib/libopencv_core.so.3.0.0)
==21435==0x251D44F9:pyopencv_from(cv2.cpp:211)
==21435==0x251D44F9:\uuuuPyx\uF\u14PybaslerCamera\uMat2NP(PyBaslerCamera.cpp:662)
==21435==0x251D44F9:[clone.isra.9](PyBaslerCamera.cpp:973)
==21435==0x503F5C:PyEval_EvalFrameEx(在/usr/bin/python3.4中)
==21435==0x5A9CB4:PyEval_evalcodex(在/usr/bin/python3.4中)
==21435==0x5E7104:???(in/usr/bin/python3.4)
==21435==by 0x5E71C8:PyRun_FileExFlags(在/usr/bin/python3.4中)
==21435==
==21435==泄漏汇总:
==21435==肯定丢失:262个块中有165107个字节
==21435==间接丢失:205个块中179724840字节
==21435==可能丢失:646个块中的1057720529字节
==21435==仍然可访问:10288块中的9399307字节
==21435==抑制:0个块中有0个字节
==21435==未显示可访问块(找到指针的块)。
==21435==若要查看它们,请使用--leak check=full--show leak kinds=all重新运行
看起来Numpy分配器创建的ndarray
s没有被释放,但我不知道如何解决这个问题。有人能告诉我如何正确释放这个内存吗
或者,如果有人对如何处理整个
cv::Mat
到np array
业务有更好的建议,我愿意接受想法。问题是,您需要将pyopencv\u的定义从PyObject*pyopencv\u从const-Mat&
更改为对象pyopencv\u从(const-Mat&)
:
#刚刚演示到位
来自“cv2.cpp”的cdef外部:
无效导入_数组()
对象pyopencv_from(const Mat&)
#等
#还有一个稍后出现的函数。。。
cdef对象mat2np(常数Mat和Mat):
#从(mat)问题行返回pyopencv#u!
#现在可以成为:
从(mat)返回pyopencv_
这是基于我认为不再存在的参考文献。引述如下:
当返回Py_uu函数时
对PyObject*
的新引用,返回类型为“object”。
当函数返回借用的引用时,返回
类型为PyObject*
。当Cython将“object”视为返回类型时
它不会增加引用计数。当它看到PyObject*
为了使用结果,必须显式强制转换为
,
当你这样做时,Cython会增加引用计数
无论您是否希望,都会强制您执行显式的DECREF
(或泄漏内存)。
为了避免这种情况,我们制定了上述惯例
借
引用如果您对
执行显式类型转换,[Cython]将生成
INCREF
和DECREF
因此您必须小心
因此,要点是:
- 从
的pyopencv_返回的对象