SSブログ

aravis解析 その3 [aravis]

aravis解析の続き。今日はmacOSへのインストールと、接続されたカメラ個々に特有な操作をするためにGen<i>Camノードツリーを読んでカメラの機能を探すにはどうするかという話....

3  macOSへのインストール

現在aravisはREADME.mdにあるようにaravisはmacOSを直接サポートしていないが、homebrewでインストールできるようになっている。ただし、homebrewはarv-viewer(サンプルコード兼動作チェック用のカメラ画像リアルタイム表示アプリ)を一緒にインストールしようとして大量に依存ライブラリを呼び込んでしまう。

macOSで単なるviewerを動作させるなら、arv-viewerではなくArvBufferからNSBitmapImageRepを作ってNSViewに表示するほうがずっと簡単で手っ取り早い。viewer抜きでインストールするなら手動でその依存ライブラリだけをインストールしてaravisをコンパイルすればいい。

僕の環境の場合やはりhomebrewを使って、最低限のものだけインストールして
$ brew install glib intltool gettext
$ brew link --force gettext
$ brew install libusb
$ brew link --force libusb
$ brew install pkg-config
$ export PKG_CONFIG_PATH="/usr/local/opt/libffi/lib/pkgconfig"
$ ./configure --enable-usb --disable-viewer --disable-gst-plugin --disable-dependency-tracking
$ make
$ sudo make install
で、できた。

この中でPKG_CONFIG_PATHのexportは、macOSの一部としてlibffiがあってconflictする、というメッセージが出たからで、確かに/usr/libにあった。macOSは自分に不要なものはばっさり切り落とすくせに、必要なものは知らん顔して勝手に入れる。こういうのかなわんよな。

また--disable-dependency-trackingのオプションは、これなしだとconfigureが失敗して
config.status: error: Something went wrong bootstrapping makefile fragments
    for automatic dependency tracking.  Try re-running configure with the
    '--disable-dependency-tracking' option to at least be able to build
    the package (albeit without support for automatic dependency tracking).
と出たからで、何が違うのかよくわからない。

homebrewをインストールする前にXcodeのコマンドラインツールがインストールしてあったし、そのあとhomebrewで他のツールもちょこっとインストールしていたので、違う環境では要求される手順やライブラリが違うかもしれない。

ちなみに、こないだ会社で使ってる別のマシンにインストールしたら--disable-dependency-trackingオプションがなくてもできた。わからん。

3.1  カメラ固有の操作

カメラの一般的な属性や操作、例えばピクセル数やシャッタやゲインの調整はArvCameraオブジェクトからできることがわかった。
aravisはカメラが持っているGen<i>Cam準拠のXML文字列を読み込んで、Gen<i>Camのノードツリーに展開する。そのノードツリーを解析してカメラの持っている属性や機能を知って保持し、ArvCameraやArvDeviceへの操作を行う関数は、最終的にこれらのノードを使ってカメラのレジスタをアクセスしている。

ArvCameraで可能なカメラの一般的な操作以外のカメラ固有の属性機能にアクセスしたい場合は、このツリーをたどる必要がある。

3.1.1  カメラのfeature

カメラ固有の属性や操作のためにはArvDeviceオブジェクトを使う。デバイスオブジェクトはカメラから
ArvDevice *arv_camera_get_device (ArvCamera *camera);
で得られる。

カメラ固有の属性をfeatureと呼んでいる。例えば整数値を持つfeatureなら
void arv_device_get_integer_feature_bounds (ArvDevice *device,
                                       const char *feature,
                                       gint64 *min,
                                       gint64 *max);
void arv_device_set_integer_feature_value (ArvDevice *device,
                                      const char *feature,
                                      gint64 value);
gint64 arv_device_get_integer_feature_value (ArvDevice *device,
                                      const char *feature);
で読み書きできる。featureは文字列で指定する。set関数は、それが成功したかどうかはわからない(GenTLGen<i>Cam規格の一部でトランスポート層に関するAPI規格)に素直に従うと自動的にそうなる)。setしてから読みだして値が変わっていれば成功、とみなすことになるだろう。

カメラに対するコマンド(例えばソフトウェアトリガの発行など)は
void arv_device_execute_command (ArvDevice *device,
                            const char *feature);
で実行できる。

featureを使えばArvCameraでできる操作も同じように可能で、場合によってはより詳細な読み書きができる場合(例えばシャッタが秒単位の浮動小数点ではなくベースクロックの何個分などというような)もある。

しかし上の関数の呼び出し形式からわかるように、ArvDeviceからfeatureを読み書きするためには、カメラがどんなfeatureをどんな名前で持っていて、それがどんな型なのかをあらかじめ知っている必要がある。

3.1.2  featureの列挙

カメラがどんなfeatureを持っているか、を知る手段はaravisには用意されていない。そのためにはカメラの取説から文字列を拾うか、あるいはカメラが持っているGen<i>Cam準拠のカメラ記述ファイルを読む必要があるらしい。

aravisがライブラリの機能として提供していてもいいのではないかとも思う。

3.1.3  aravisのGen<i>Camのノードオブジェクト

aravis本体に代わってfeatureをGen<i>Camカメラ記述ファイルから読み出す方法を考えてみる。

Gen<i>Camカメラ記述ファイルはXML形式で、aravisはlibxml2を使ってパースしている。パースした結果のGen<i>CamノードもGObjectのオブジェクトになっている。aravisでは
  • ArvGc
  • ArvGcFeatureNode
  • ArvGcPropertyNode
がカメラのユーザから見ると必要なオブジェクトである。ArvGcはGen<i>Camのツリー全体を表すオブジェクトで、ArvGcFeatureNodeはカメラユーザが読み書きするfeatureを表すオブジェクト、ArvGcPropertyNodeはfeature以外の一般のノードである。ArvGcPropertyNodeはユーザが直接操作することはないが、featureの値などとして必要になる場合がある。

Gen<i>Camでは
解析済みGen<i>Camのノードツリーはデバイスオブジェクトから
ArvGc *arv_device_get_genicam (ArvDevice *device);
で得られる。これがツリーになってるのでそれを辿ることになる。全部辿らなくてもGen<i>Cam規格ではRootという名前のついたカテゴリノードにユーザが操作できるfeatureが列挙されているはずなので、それを辿ればいいはずである。

具体的には
        ArvCamera *camera;
        ArvDevice *device = arv_camera_get_device (camera);
        ArvGc *gc = arv_device_get_genicam (device);
        ArvGcNode   *node = arv_gc_get_node (gc, "Root");
        if (ARV_IS_GC_CATEGORY(node)) {
            GSList  *clist = (GSList *)arv_gc_category_get_features (node);
            guint   len = g_slist_length(clist);
            //  featureノードを列挙する
        }
などとすればいい。 これはまずArvCameraオブジェクトからArvDeviceオブジェクトを得て、それからさらにGen<i>Camのノードツリーを取ってくる。そのツリーからRootの名前を持つノードを得る。これはGen<i>Camのカテゴリノードのはずである。

Gen<i>CamのカテゴリノードもGObjectのオブジェクトになっているので、オブジェクトタイプを調べればカテゴリノードかどうかがわかる。ARV_IS_GC_CATEGORY()は引数がカテゴリノードオブジェクトならtrueを返すマクロである。そしてそうならその要素になっているはずのfeatureノードを取ってくればいい。GSListというのはGObjectの配列オブジェクト(双方向のリンクトリストらしい)である。

カメラによっては(というか最近のカメラはたいてい)Rootカテゴリノードの下にさらにカテゴリノードがあってfeatureが分類されている。その場合はfeatureノード列挙を入れ子にすればいい。

そうするとカメラユーザが操作可能なすべてのfeatureの名前が得られるはずである。

名前がわかればArvDeviceオブジェクトの関数
ArvGcNode *arv_device_get_feature (ArvDevice *device,
                        const char *feature);
で、そのfeatureノードを得ることができる。featureノードは実際にはGen<i>CamのpFeatureの種類に従ってArvGcFeatureNodeのサブクラスとして
  • ArvGcEnumEntry
  • ArvGcRegisterDescriptionNode
  • ArvGcGroupNode
  • ArvGcBoolean
  • ArvGcCategory
  • ArvGcCommand
  • ArvGcConverter
  • ArvGcEnumeration
  • ArvGcFloatNode
  • ArvGcIntegerNode
  • ArvGcPort
  • ArvGcRegisterNode
  • ArvGcStructEntryNode
  • ArvGcSwissKnife
が用意されていて、それぞれ固有の操作ができるようになっている。
nice!(0)  コメント(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

aravis解析 その2aravis解析 その4 ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。