【问题标题】:Wrapping C++ Function That Has OpenCV Parameters with Cython用 Cython 包装具有 OpenCV 参数的 C++ 函数
【发布时间】:2015-06-17 10:21:03
【问题描述】:

我有以下用 C++ 编写的类

#include "segmenter_interface.h"
#include "video_marker.cpp"
#include <opencv2/imgcodecs.hpp>
#include <opencv2/videoio/videoio.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <vector>

class UserDivide : public SegmenterInterface{
  public: 
    virtual void SegmentVideo(cv::VideoCapture *vc, 
        std::vector<Segment> *indices); 
}

实施细节并不重要。理想情况下,我想使用 Cython 将这个类公开给 python。对象 VideoCapture 已经可以被 python 实例化,因为 OpenCV 已经包装了它的所有模块。根据我的阅读,vector 已经是 Cython 的一部分,因为它支持大多数 C++ 标准库。

目前,我写了这么多.pyx:

cdef extern from "<vector>" namespace "std":
    cdef cppclass vector [T]: 
        pass

cdef extern from "<opencv2/videoio/videoio.hpp>" namespace "cv": 
    cdef cppclass VideoCapture: 
        pass # Don't care, just need a pointer

cdef extern from "segmenter_interface.h":
    cdef struct Segment: 
        pass # I will need this eventually...

cdef extern from "user_divide.h":
    cdef cppclass UserDivide: 
        UserDivide()
        void SegmentVideo(VideoCapture *vc, vector[Segment] *indices)  

cdef class PyUserDivide:
    cdef UserDivide *thisptr # hold a C++ instance
    def __cinit__(self): 
        self.thisptr = new UserDivide()
    def __dealloc__(self): 
        del self.thisptr
    def SegmentVideo(self, VideoCapture *vc, vector[Segment] *indices): 
        return self.thisptr.SegmentVideo(vc, indices)

问题在于 SegmentVideo 中的参数——cython 编译器抱怨转换它们。

我的问题是:如何在 Cython 中正确包装对象指针,特别是如果它不是标准数据类型或结构,而是一个类?我是否采取了正确的方法?

我的目标是在 Python 中执行以下操作

import cv2
cap = cv2.VideoCapture("my_video.mp4")
segments = []
ud = UserDivide()
ud.SegmentVideo(cap, segments)
# Do stuff with segments

错误信息如下:

Error compiling Cython file:
------------------------------------------------------------
...
    cdef UserDivide *thisptr # hold a C++ instance
    def __cinit__(self): 
        self.thisptr = new UserDivide()
    def __dealloc__(self): 
        del self.thisptr
    def SegmentVideo(self, VideoCapture *vc, vector[Segment] *indices): 
                          ^
------------------------------------------------------------

pyuser_divide.pyx:22:27: Cannot convert Python object argument to type 'VideoCapture *'

Error compiling Cython file:
------------------------------------------------------------
...
    cdef UserDivide *thisptr # hold a C++ instance
    def __cinit__(self): 
        self.thisptr = new UserDivide()
    def __dealloc__(self): 
        del self.thisptr
    def SegmentVideo(self, VideoCapture *vc, vector[Segment] *indices): 
                                            ^
------------------------------------------------------------

pyuser_divide.pyx:22:45: Cannot convert Python object argument to type 'vector[Segment] *'

【问题讨论】:

  • 您能否提供 Cython 报告的确切错误消息?

标签: python c++ opencv cython


【解决方案1】:

不幸的是,这是一个部分答案:我知道问题,但我不知道解决方案。

您的第二个问题很容易解决。问题是它需要一个指向 c++ 向量的指针,但它得到了一个 python 列表。 Cython 可以自动将列表转换为向量并返回,但会在指针处丢失。

 # put this at the of your file top, and remove
 # cdef extern from "<vector>" namespace "std": (etc)
 #
 # Cython has automatically defined these!
 from libcpp.vector cimport vector

 # ... other code goes here ...

 # accept a list
 def SegmentVideo(self, VideoCapture *vc, list indices):
    cdef vector[Segment] indices_vector = indices # autoconversion happens
    output = self.thisptr.SegmentVideo(vc, &indices_vector)
    # are you expecting the vector to be changed, and do you want to keep the changes?
    # if so then do
    indices[:] = indices_vector
    # if you don't care about changes then don't bother
    return output

您的第一个问题 (Cannot convert Python object argument to type 'VideoCapture *') 是我无法解决的问题。本质上,cv2 模块生成 python 对象(可能是 OpenCV 中定义的 C++ 指针的包装器),并且没有明显的方法可以从这些 python 对象生成 C++ 指针 - 你必须弄清楚它的存储位置。

我不会完全重复的快速讨论表明 VideoCapture python 对象在我的系统上是 32 字节(一个空的 Python 对象是 16 字节)。但是,这 2 个额外的 8 字节空格的内容对我来说都不是“指针”。

大部分 OpenCV python 包装器看起来都是从 C++ 代码自行生成的(至少据我所知),这意味着要弄清楚它是如何包装的并不是特别容易。一种可能有用的方法是尝试通过他们的代码生成器运行UserDivide,看看你是否可以通过这种方式为其生成python绑定......

【讨论】:

  • 你是对的,我认为没有像我上面定义的那样使用 VideoCapture 对象的好方法。在为一个好的解决方案转动轮子之后,我决定包装我需要将视频捕获对象传递给我的 UserDivide 对象。也就是说,我包装了VideoCapture,实现了VideoCapture(std::string &filename)构造函数,然后将我的VideoCapture python类传递给我的UserDivide python类。所以现在我没有使用任何 opencv 提供的包装器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-31
  • 2013-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多