12

C / C ++拡張ソースコードからWindows用のpydファイル(またはPythonにインポートできる他のアイテム)に移動するにはどうすればよいですか?

編集:私が使用したい特定のライブラリ(BRISK)はOpenCV 2.4.3に含まれていたので、このスキルの必要性は当分の間なくなりました。あなたがBRISKを探してここに来た場合のために、ここに私が投稿したPythonデモの簡単なBRISKがあります。


Pythonアプリケーションでビルドして使用したいBriskソースコード(ダウンロード)があります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])
    

    それはすぐに私に次の行とビルドフォルダのどこかに0バイトのbrisk.pydを与えました。とても近いですか?

    running build
    running build_ext
    
  2. ライブラリパスを持つDistutils:その試みをスクラッチします。そこで、上記のsetup.pyでコメント化されている2つのライブラリ行を追加しました。このリンクエラーが発生するまでは問題ないようでした。

    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:/ brief / build
    • cmake gui:VisualStudio10用に構成する
    • cmake gui:デフォルトのオプションを使用して生成します(CMAKE_BACKWARDS_COMPATIBILITY、CMAKE_INSTALL_PREFIX、EXECUTABLE_OUTPUT_PATH、LIBRARY_OUTPUT_PATH)
    • VC ++ Express 10:リリースに変更してcmakeによって生成されたソリューションを構築し、重大ではない警告のように見える約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
4

2 に答える 2

14

この活発なライブラリがPythonバインディングをエクスポートすることさえ確かですか?ソースコードにそれへの参照がありません-Pythonヘッダーファイルをインポートしていないようです。これは確かに、これまであまり成功しなかった理由を説明します-プレーンなC ++コードをコンパイルして、Pythonがそれとインターフェイスすることを期待することはできません。

2番目のdistutilsの例が最も正しいと思います。これは明らかにコンパイルしてリンカーの段階に到達していますが、このエラーが発生します。このエラーは、モジュールの最上位のinit関数であると私が推測しているinitbriskという名前の関数が見つからないことを意味します。繰り返しになりますが、これは、Pythonモジュールを意図していないコードからコンパイルしようとしていることを示しています。

C ++コードをPythonラッパーで自分でラップしたい場合は、c /c++拡張機能の作成に関する公式ドキュメントを参照してください。あるいは、C++コードからPython拡張機能を作成するプロセスをある程度(または完全に)自動化しようとするboost :: pythonSIP、またはshibokenを調べることもできます。

編集:あなたは自分で問題を解決するためにかなりの努力をし、良い質問を投稿したようですので、これを行う方法についてより詳細な回答をすることにしました。

boost::pythonを使用したC++ライブラリのラップに関するクイックチュートリアル

個人的には、このようなものにboost :: pythonを使用したことがあるので、それを実行する方法の概要を説明します。Visual C ++ 2010を使用していると仮定します。また、Boost Proライブラリは32ビットバイナリしか提供しないと思うので、32ビットバージョンのPythonがインストールされていると仮定します。

Boostのインストール

まず、Boostライブラリのコピーを取得する必要があります。これを行う最も簡単な方法は、boostproWebサイトからインストーラーをダウンロードすることです。これらは、Windowsでboostc++ライブラリを使用するために必要なすべてのヘッダーファイルとバイナリファイルをインストールする必要があります。後で必要になるので、これらのファイルをインストールする場所に注意してください。スペースを含まないパスにインストールするのが最適な場合があります。簡単にするために、これらのファイルをC:\ boostに配置すると仮定しますが、実際に使用したパスの代わりに使用できます。

または、これらの手順に従って、ソースからブーストを作成することもできます。100%確信はありませんが、インストールしたpythonのバージョンと互換性のあるバージョンのboost::pythonを取得するためにこれを行う必要がある場合があります。

VisualStudioプロジェクトのセットアップ

次に、brisk.pydのビジュアルスタジオプロジェクトをセットアップします。Visual Studioを開いた場合は、[新規]-> [プロジェクト]に移動し、Win32プロジェクトのオプションを見つけます。場所などを設定し、[OK]をクリックします。表示されるウィザードで、DLLプロジェクトタイプを選択し、空のプロジェクトチェックボックスをオンにします。

プロジェクトを作成したので、python、boost :: python、およびbrisk.libファイルを使用できるようにインクルードパスとライブラリパスを設定する必要があります。

Visual Studiosソリューションエクスプローラーで、プロジェクトを右クリックし、表示されるメニューからプロパティを選択します。これにより、プロジェクトのプロパティページが開きます。[リンカー]->[一般]セクションに移動し、[追加のライブラリディレクトリ]セクションを探します。.libこれに、boost、python、およびのファイルへのパスを入力する必要がありますbrisk_static.lib。通常、これらは、ライブラリをインストールした場所のlib(またはlibs)サブディレクトリにあります。パスはセミコロンで区切られます。以下に設定のスクリーンショットを添付しました。

追加のライブラリディレクトリ設定

次に、.libファイルにリンクするためのVisualStudioを入手する必要があります。これらのセクションは、プロパティの[リンカー]->[入力]セクションの[追加の依存関係]フィールドにあります。ここでも、セミコロンで区切られたリストです。Python用のライブラリを追加する必要があります(私の場合はそうですpython27.libが、バージョンによって異なります)brisk_static.lib。前の段階で追加したように、これらはフルパスを必要としません。繰り返しますが、スクリーンショットは次のとおりです。

追加の依存関係設定

boost_pythonライブラリファイルを追加する必要があるかもしれませんが、boostは問題を回避するためにヘッダーファイルの魔法を使用していると思います。私が間違っている場合は、に似た名前のファイルのブーストライブラリパスを調べて、それをboost_python-vc100-mt.lib追加してください。

最後に、プロジェクトに関連するC++ヘッダーファイルをインクルードできるようにインクルードパスを設定する必要があります。関連する設定をプロジェクトのプロパティに表示するには、プロジェクトに.cppファイルを追加する必要があります。ソリューションエクスプローラーでソースファイルフォルダーを右クリックし、新しいアイテムの追加に移動します。C ++ファイル(.cpp)を選択し、main.cpp(またはその他の任意の名前)という名前を付けます。

次に、プロジェクトのプロパティに戻り、[C /C++]->[一般]に移動します。追加のライブラリディレクトリの下に、brisk、python、boostのインクルードパスを追加する必要があります。繰り返しになりますが、区切り文字のセミコロンです。ここでもスクリーンショットを示します。

ここに画像の説明を入力してください

opencv2とagastライブラリも含めるようにこれらの設定を更新する必要があるかもしれませんが、それはあなたが理解するためのタスクとして残しておきます-それはほとんど同じプロセスであるはずです。

boost::pythonで既存のc++クラスをラップします。

ここで少し注意が必要です。実際には、C++を記述して活発なライブラリをブーストPythonでラップします。このためのチュートリアルはここにありますが、私も少し試してみます。

main.cppこれは、前に作成したファイルで行われます。まず、ファイルの先頭に必要な関連するincludeステートメントを追加します。

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

次に、Pythonモジュールを宣言する必要があります。私はあなたがこれを活発と呼びたいと思っていると思います、それであなたはこのようなことをします:

BOOST_PYTHON_MODULE(brisk)
{
}

これにより、boost::pythonに。という名前のPythonモジュールを作成するように指示する必要がありますbrisk

次に、ラップするすべてのクラスと構造体を調べて、それらを使用してブースト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クラスをラップしました。いくつかの簡単な説明:

class_< cv::BriskPatternPoint >( "BriskPatternPoint" )boost :: pythonに、cv::BriskPatternPointC ++クラスを使用してクラスを宣言し、それをBriskPatternPointpythonのように公開するように指示します。

.def_readwrite("y", &cv::BriskPatternPoint::y)読み取り可能および書き込み可能なプロパティをBriskPatternPointクラスに追加します。プロパティの名前はyで、BriskPatternPoint::yc++フィールドにマップされます。

class< cv::BriskScaleSpace >( "BriskScaleSpace", init< uint8_t >() )今回は別のクラスを宣言しBriskScaleSpaceますが、uint8_t(符号なしバイト-Pythonでは整数にマップする必要がありますが、255バイトより大きいものを渡さないように注意します-私はしません)を受け入れるコンストラクターも提供しますその状況で何が起こるかを知っている)

次の.def行は関数を宣言しているだけです--boost::pythonは(私が思うに)関数の引数タイプを自動的に決定できるはずなので、それらを提供する必要はありません。

私がこれらの例を実際にコンパイルしていないことはおそらく注目に値します-それらはまったく機能しない可能性があります。

とにかく、これをPythonで完全に機能させるには、Pythonからアクセスできるようにするすべての構造、クラス、プロパティ、関数に対して同様のことを行う必要があります。これは、非常に時間のかかる作業になる可能性があります。

この動作の別の例を見たい場合は、このクラスをまとめるためにここでこれを行いました

拡張機能の構築と使用

Visual Studioが拡張機能の構築を処理する必要があります。これを使用するのは、.DLLを取得して名前を.pydに変更する場合にすぎません(VSにこれを実行させることはできますが、それはあなたに任せます)。

次に、PythonファイルをPythonパスのどこかにコピーし(site-packagesたとえば)、インポートして使用する必要があります。

import brisk

patternPoint = brisk.BriskPatternPoint()
....    

とにかく、私はこれを書き出すのにかなりの時間を費やしました-それで私はここで止まるつもりです。何かを省略したり、何かがはっきりしない場合はお詫びしますが、これは主にメモリから行っています。うまくいけば、それはあなたの助けになっています。何か明確にする必要がある場合は、コメントを残すか、別の質問をしてください。

于 2012-06-06T15:46:13.237 に答える
4

誰かがそれを必要とする場合に備えて、これは私がこれまでに持っているものです。基本的に、 Pythonで作成してからdetectを呼び出すことができるBriskFeatureDetector。これのほとんどは、obmargが私に示したものを確認/コピーするだけですが、pydライブラリに至るまでの詳細を追加しました。

検出メソッドはデータ型を変換しないため、まだ不完全です。これを改善する良い方法を知っている人は誰でもしてください!たとえば、numpyndarrayをcv:: Matに変換しているように見えるこのライブラリを見つけましたが、今はそれを統合する方法を理解する時間がありません。変換する必要のある他のデータ型もあります。

OpenCV2.2をインストールします

  • 以下のセットアップでは、C:\opencv2.2
  • APIまたは実装に関する何かがバージョン2.4で変更され、問題が発生したため(おそらく、新しいアルゴリズムオブジェクト?)、BRISKが開発された2.2を使用しました。

BoostPythonでBoostをインストールする

  • 以下のセットアップでは、C:\boost\boost_1_47

VisualStudio10プロジェクトを作成します。

  • 新しいプロジェクト->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. インクルード/ヘッダー

    • 構成プロパティ->C/C++->一般
    • 追加のインクルードディレクトリに追加します(独自のpython / brisk /などのベースパスに調整します):

      C:\opencv2.2\include;

      C:\boost\boost_1_47;

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

      C:\python27\include;

  2. ライブラリ(リンカー)

    • 構成プロパティ->リンカー->一般
    • 追加のライブラリディレクトリに追加します(独自のpython / brisk /などのベースパスに調整します):

      C:\opencv2.2\lib;

      C:\boost\boost_1_47\lib;

      C:\brisk\win32\lib;

      C:\python27\Libs;

    • 構成プロパティ->リンカー->入力

    • 追加の依存関係に追加します(独自のpython / brisk /などのベースパスに調整します):

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

      agast_static.lib; brisk_static.lib;

      python27.lib;

  3. .dllの代わりに.pyd出力

    • 構成プロパティ->一般
    • ターゲット拡張子を.pydに変更します

必要に応じてビルドして名前を変更します

  • ソリューションを右クリックして、ビルド/再構築します
  • 出力の名前を「Brisk.pyd」から「brisk.pyd」に変更する必要がある場合があります。そうしないと、PythonでDLLを読み込めないというエラーが発生します。
  • brisk.pydをサイトパッケージに入れるか、そのパスにリンクする.pthファイルを入れることで、Pythonでbrisk.pydを利用できるようにします。

パス環境変数を更新

  • Windowsの設定で、パスに次のものが含まれていることを確認します(ここでも、パスに合わせて調整します)。

    `C:\boost\boost_1_47\lib;C:\brisk\win32\bin`
    
于 2012-06-11T15:26:53.727 に答える