如何从c/c++源代码中获取python.pyd for Windows?(更新:在Python中使用brisk,以防这是您想要的)

2024-05-17 03:20:24 发布

您现在位置:Python中文网/ 问答频道 /正文

如何从C/C++扩展源代码到Windows的PYD文件(或者我可以导入到Python的其他项目)?

编辑:我想使用的特定库(BRISK)包含在OpenCV2.4.3中,因此我暂时不需要这种技能。如果你来这里寻找轻快,这里有一个简单的BRISK in Python demo我张贴。


我有Brisk源代码(download),我想在我的python应用程序中构建和使用它。我已经生成了一个brisk.pyd文件。。。但它是0字节。如果有更好的/替代的方法来瞄准brisk.pyd文件,那么我当然也愿意接受。

编辑:请忽略下面我原始问题中的所有尝试,并查看obmarg详细演练所提供的答案

我哪里做错了?

  1. 没有库路径的Distutils:首先,我尝试用Distutils和下面的setup.py构建源代码(我刚刚开始学习Distutils,所以这是一个暗中拍摄)。BRISK源代码的结构位于这个问题的底部,以供参考。

    from distutils.core import setup, Extension
    module1 = Extension('brisk',
        include_dirs = ['include', 'C:/opencv2.4/build/include', 'C:/brisk/thirdparty/agast/include'],
        #libraries = ['agast_static', 'brisk_static'],
        #library_dirs = ['win32/lib'],
        sources = ['src/brisk.cpp'])
    setup (name = 'BriskPackage',
        ext_modules = [module1])
    

    这立刻给了我以下几行,并在build文件夹中的某个地方出现了一个0 byte brisk.pyd。这么近?

    running build
    running build_ext
    
  2. 具有库路径的Distutils:抓取该尝试。所以我添加了上面setup.py中注释掉的两个库行。在我得到这个链接错误之前,一切似乎都正常:

    creating build\lib.win32-2.7
    C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\BIN\link.exe /DLL /nologo /INCREMENTAL:NO /LIBPATH:win32/lib /LIB
    PATH:C:\Python27_32bit\libs /LIBPATH:C:\Python27_32bit\PCbuild agast_static.lib brisk_static.lib /EXPORT:initbrisk build
    \temp.win32-2.7\Release\src/brisk.obj /OUT:build\lib.win32-2.7\brisk.pyd /IMPLIB:build\temp.win32-2.7\Release\src\brisk.
    lib /MANIFESTFILE:build\temp.win32-2.7\Release\src\brisk.pyd.manifest
    LINK : error LNK2001: unresolved external symbol initbrisk
    build\temp.win32-2.7\Release\src\brisk.lib : fatal error LNK1120: 1 unresolved externals
    error: command '"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\BIN\link.exe"' failed with exit status 1120
    
  3. 不受控制的挥舞:我想可能需要建立库,所以我用cmake+mingw-mingw+vc++express 2010做了一个速成课程(很多速成课程),如下所示:

    • cmake gui:源代码:c:/brisk,构建:c:/brisk/build
    • cmake gui:为Visual Studio 10配置
    • cmake gui:使用默认选项并生成(cmake_backward_兼容性、cmake_INSTALL_PREFIX、EXECUTABLE_OUTPUT_PATH、LIBRARY_OUTPUT_PATH)
    • >Vist+VC+Express 10:< /强>更改以释放并构建CGED生成的解决方案,得到20页的所有非关键警告,然后成功完成。注意-此操作不会生成dll。它确实生成了以下与下载中包含的库大小相似的库:

      win32/lib/Release/
          agast_static.lib
          brisk_static.lib
      
  4. 进一步拍打。

相关BRISK源文件结构供参考:

build/ (empty)
include/brisk/
    brisk.h
    hammingsse.hpp
src
    brisk.cpp
    demo.cpp
thirdparty/agast/
    include/agast/
        agast5_8.h ....
        cvWrapper.h
    src/
        agast5_8.cc ...
    CMakeLists.txt
win32/
    bin/
        brisk.mexw32
        opencv_calib3d220.dll ...
    lib/
        agast_static.lib
        brisk_static.lib
CMakeLists.txt
FindOpenCV.cmake
Makefile

Tags: buildsrccmakerelease源代码includelibsetup
2条回答

如果有人需要的话,这就是我目前所拥有的。基本上是一个BriskFeatureDetector,它可以在Python中创建,然后调用detect。大部分只是确认/复制obmarg向我展示的内容,但我已经将所有细节添加到pyd库中。

但detect方法对我来说仍然不完整,因为它不转换数据类型。任何人谁知道一个很好的方法来改善这一点,请做!例如,我确实找到了this library,它似乎将numpy ndarray转换成了cv::Mat,但是我现在没有时间去想如何集成它。还需要转换其他数据类型。

安装OpenCV 2.2

  • 对于下面的设置,我安装到C:\opencv2.2
  • API或实现的某些内容在2.4版本中发生了变化,这给了我一些问题(可能是新的算法对象?)所以我坚持使用BRISK开发的2.2。

使用Boost Python安装Boost

  • 对于下面的设置,我安装到C:\boost\boost_1_47

创建Visual Studio 10项目:

  • 新建项目-->;win32
  • 对于下面的设置,我将其命名为brisk
  • 下一个-->;DLL应用程序类型;空项目-->;已完成
  • 在顶部,从DebugWin32更改为ReleaseWin32

在源文件中创建main.cpp

在项目设置之前这样做,以便C++选项在项目设置

中可用。
#include <boost/python.hpp>
#include <opencv2/opencv.hpp>
#include <brisk/brisk.h>

BOOST_PYTHON_MODULE(brisk)
{
    using namespace boost::python;

    //this long mess is the only way I could get the overloaded signatures to be accepted
    void (cv::BriskFeatureDetector::*detect_1)(const cv::Mat&,
                std::vector<cv::KeyPoint, std::allocator<cv::KeyPoint>>&,
                const cv::Mat&) const
                = &cv::BriskFeatureDetector::detect;
    void (cv::BriskFeatureDetector::*detect_vector)(const std::vector<cv::Mat, std::allocator<cv::Mat>>&,
                std::vector< std::vector< cv::KeyPoint, std::allocator<cv::KeyPoint>>, std::allocator< std::vector<cv::KeyPoint, std::allocator<cv::KeyPoint>>>>&,
                const std::vector<cv::Mat, std::allocator<cv::Mat>>&) const
                = &cv::BriskFeatureDetector::detect;

    class_< cv::BriskFeatureDetector >( "BriskFeatureDetector", init<int, int>())
        .def( "detect", detect_1)
    ;
}

项目设置(右键单击项目-->;属性):

  1. 包含/标题

      配置属性-gt;C/C++ + ->一般
    • 添加到附加的Include目录(调整到您自己的python/brisk/etc.base路径):

      C:\opencv2.2\include;

      C:\boost\boost_1_47;

      C:\brisk\include;C:\brisk\thirdparty\agast\include;

      C:\python27\include;

  2. 库(链接器)

    • 配置属性-->;链接器-->;常规
    • 添加到其他库目录(调整到您自己的python/brisk/etc.基本路径):

      C:\opencv2.2\lib;

      C:\boost\boost_1_47\lib;

      C:\brisk\win32\lib;

      C:\python27\Libs;

    • 配置属性-->;链接器-->;输入

    • 添加到附加依赖项(根据您自己的python/brisk/etc.base路径调整):

      opencv_imgproc220.lib;opencv_core220.lib;opencv_features2d220.lib;

      agast_static.lib; brisk_static.lib;

      python27.lib;

  3. .pyd输出而不是.dll

    • 配置属性-->;常规
    • 将目标扩展名更改为.pyd

必要时生成并重命名

  • 右键单击解决方案并生成/重建
  • 您可能需要将输出从“Brisk.pyd”重命名为“Brisk.pyd”,否则python将给出无法加载DLL的错误
  • 通过将brisk.pyd放入站点包或放置链接到其路径的.pth文件,使其对python可用

更新路径环境变量

  • 在“windows设置”中,确保路径中包含以下内容(再次,根据路径调整):

    `C:\boost\boost_1_47\lib;C:\brisk\win32\bin`
    

您确定这个brisk库甚至可以导出python绑定吗?我在源代码中看不到对它的任何引用——它甚至看起来都没有导入python头文件。这肯定可以解释为什么到目前为止你还没有取得多少成功——你不能仅仅编译简单的C++代码,并期望Python与它进行接口。

我认为您的第二个distutils示例最接近于正确的——它显然是在编译东西并进入链接器阶段,但是随后您会遇到这个错误。这个错误只是意味着它找不到一个名为initbrisk的函数,我猜它可能是模块的顶级init函数。这再次表明,您正试图从不是为它准备的代码中编译python模块。

如果你想将Python包装器中的C++代码包起来,你可以查看the official documentation on writing c/c++ extensions。或者,你可以查看一下{a2}、SIPshiboken,它们试图有点(或完全)自动化从C++代码中创建Python扩展的过程。

编辑:既然你似乎已经为自己解决问题付出了相当大的努力,并且发布了一个很好的问题,我决定给出一个更详细的答复,说明如何着手解决这个问题。

使用Booo::Python

包装C++库的快速教程

就我个人而言,我只使用过boost::python来完成这样的工作,所以我将尝试为您提供一个很好的关于如何完成这项工作的总结。我假设你使用Visual C++ 2010。我还假设您已经安装了32位版本的python,因为我相信boost pro库只提供32位二进制文件。

安装boost

首先,您需要获取boost库的副本。最简单的方法是从the boost pro website下载安装程序。这些文件应该安装在windows上使用boost c++库所需的所有头文件和二进制文件。请注意将这些文件安装到何处,因为稍后将需要这些文件-最好安装到没有空格的路径。为了方便起见,我假设您将这些文件放在C:\ boost中,但您可以将其替换为实际使用的路径。

或者,您可以按照these instructions从源代码构建boost。我不是百分之百确定,但可能是这样的情况,您需要来完成此操作,以便获得与您安装的python版本兼容的boost::python版本。

设置visual studio项目

接下来,您需要为brisk.pyd设置一个visual studio项目。如果打开visual studio,请转到“新建->;项目”,然后查找用于Win32项目的选项。设置位置等,然后单击“确定”。在出现的向导中,选择一个DLL项目类型,然后勾选空项目复选框。

既然已经创建了项目,就需要设置include&library路径,以便使用python、boost::python和brisk.lib文件。

在Visual Studios解决方案资源管理器中,右键单击项目,然后从显示的菜单中选择“属性”。这将打开项目的属性页。转到链接器->;常规部分并查找其他库目录部分。您需要用boost、python和您的brisk_static.lib.lib文件的路径来填充它。通常这些文件可以在lib(或libs)的子目录中找到 无论你在哪里安装了库。路径用分号分隔。我在下面附上了我的设置的截图:

Additional library directories settings

接下来,需要让visual studio链接到.lib文件。这些部分可以在属性的“链接器->;输入”部分的“附加依赖项”字段中找到。它还是一个分号分隔的列表。您应该需要为python和brisk_static.lib添加库(在我的例子中,这是python27.lib,但会因版本而异)。它们不需要您在前面添加的完整路径舞台。再一次,这是一张截图:

additional dependencies settings

您可能还需要添加boost_python库文件,但我认为boost使用了一些头文件魔法来避免麻烦。如果我不正确,那么在boost库路径中查找一个类似于boost_python-vc100-mt.lib的文件并将其添加到中。

最后,需要设置包含路径,以便允许项目包含相关的C++头文件。要使相关设置显示在项目属性中,您需要向项目中添加一个.cpp文件。右键单击解决方案资源管理器中的“源文件”文件夹,然后转到“添加新项”。选择C++文件(.cp)并命名它为Me.cpp(或者您想要的任何其他)。

下一步,回到您的项目属性,转到C/C++ +GT;在additional libraries目录下,需要为brisk、python和boost添加include路径。同样,分号表示分隔符,这里还有一张截图:

enter image description here

我怀疑您可能还需要更新这些设置以包括opencv2&agast库,但我将把它作为一项任务留给您去解决-它应该是相同的过程。

用boost::python包装现有的c++类

现在略微棘手一点——实际上编写C++来在Boost Python中包装您的快速库。你可以找一个关于这个here的教程,但我也会试着复习一下。

这将发生在您先前创建的main.cpp文件中。首先,在文件顶部添加需要的相关include语句:

#include <brisk/brisk.h>
#include <Python.h>
#include <boost/python.hpp>

接下来,需要声明python模块。我想你会希望这个叫做brisk,所以你可以这样做:

BOOST_PYTHON_MODULE(brisk)
{
}

这应该告诉boost::python创建一个名为brisk的python模块。

接下来,我们将介绍所有要包装的类和结构,并用它们声明boost python类。所有类的拒绝都应该包含在brisk.h中。您应该只包装类的公共成员,而不是任何受保护或私有成员。作为一个简单的例子,我在这里做了两个结构:

BOOST_PYTHON_MODULE(brisk)
{
    using namespace boost::python;

    class_< cv::BriskPatternPoint >( "BriskPatternPoint" )
         .def_readwrite("x", &cv::BriskPatternPoint::x)
         .def_readwrite("y", &cv::BriskPatternPoint::y)
         .def_readwrite("sigma", &cv::BriskPatternPoint::sigma);

    class< cv::BriskScaleSpace >( "BriskScaleSpace", init< uint8_t >() )
         .def( "constructPyramid", &cv::BriskScaleSpace::constructPyramid );
}

在这里,我包装了cv::BriskPatternPoint结构和cv::BriskScaleSpace类。一些简单的解释:

^ {CD10>}告诉Boosi::Python用^ {< CD11>} C++类声明类,并在Python中将其暴露为^ {CD12>}。

.def_readwrite("y", &cv::BriskPatternPoint::y)BriskPatternPoint类添加可读写属性。属性名为y,将映射到BriskPatternPoint::yc++字段。

class< cv::BriskScaleSpace >( "BriskScaleSpace", init< uint8_t >() )声明了另一个类,这次是BriskScaleSpace,但也提供了一个接受uint8的构造函数(一个无符号字节-在python中应该只是映射到一个整数,但我会小心不要传入一个大于255字节的字节-我不知道在这种情况下会发生什么)

下面的.def行只是声明了一个函数-boost::python应该(我认为)能够自动确定函数的参数类型,所以不需要提供它们。

可能值得注意的是,我实际上并没有编译这些示例中的任何一个——它们很可能根本不起作用。

无论如何,要使它在python中完全工作,只需对您希望从python访问的每个结构、类、属性和函数执行类似的操作——这可能是一项非常耗时的任务!

如果你想看到另一个例子,我用this here来结束this class

使用分机构建

Visual studio应该负责构建扩展-然后使用它只是获取.DLL并将其重命名为.pyd的一个例子(您可以让VS为您执行此操作,但我将由您决定)。

然后只需要将python文件复制到python路径上的某个位置(例如site-packages),导入并使用它!

import brisk

patternPoint = brisk.BriskPatternPoint()
....    

不管怎么说,我花了一个小时左右的时间写这篇文章,所以我就到此为止。如果我漏掉了什么或者有什么不清楚的地方,我会道歉,但我这么做主要是出于记忆。希望能对你有所帮助。如果你需要澄清什么,请留下评论,或提出另一个问题。

相关问题 更多 >