Thrift + OpenCV

Thriftを利用してOpenCVの関数をスクリプトから呼んでみます。
といってもRPCで繋げるだけで特別なことをする必要はありません。

ここでは、画像の各チャンネルの平均値と標準偏差を求めてみます。
サーバ側でOpenCVの cvAvgSvd() を利用すればOK。

まず、最初にRPCのインタフェースをThrift IDLに書きます。
ここでは、平均と標準偏差を求める関数を2つ作ることにしました。
各チャンネルの値が欲しいので戻り値は list<double> に、
引数は画像ファイル名を指定したいので string にしておきます。

* cv.thrift (サービス名は CV)

service CV {
  list<double> calcAvg(1: string img)
  list<double> calcSdv(1: string img)
}

* thriftコマンドでコード生成

$ thrift --gen cpp --gen perl --gen php --gen rb cv.thrift

サーバ側の実装ではC++で普通にOpenCVを使って書けばOKです。
(今回の場合は gen-cpp/CV_server.skeleton.cpp というファイルを編集する)
メソッドの引数にだけ注意しておきます。
ここではコードを一部省略しますが、実際はドメインロジック以外自動生成されます。
ソケットを作って接続を待ったり、データ構造をシリアライズしたりといった面倒な部分は、
全てThriftが引き受けてくれるので安心です。

* サーバ側 CV_server.skeleton.cpp (C++)
[csharp]
#include “CV.h”
#include #include
#include #include

#include
#include
#include

/* 中略 */

class CVHandler : virtual public CVIf {
IplImage *srcImg;
CvScalar mean;
CvScalar std_dev;
public:
CVHandler() {
srcImg = 0;
mean = cvScalarAll(0);
std_dev = cvScalarAll(0);
}

void calcAvg(std::vector & _return, const std::string& img) {
if((srcImg = cvLoadImage(img.c_str(), CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR)) == 0) {
std::cout<<"load error."< & _return, const std::string& img) {
/* 以下略 (calcAvgと同様に書けばよい)*/
 
[/csharp]

* コンパイル

$ g++ -g CV.cpp CV_server.skeleton.cpp -o CV_server `pkg-config --cflags --libs opencv thrift`

次はクライアント側を実装します。
* クライアント側 cv.pl (Perl)
[php]
#!/usr/bin/perl

use strict;
use warnings;
use lib ‘./gen-perl’;

use Thrift;
use Thrift::BinaryProtocol;
use Thrift::Socket;

use CV;

my $transport = Thrift::Socket->new(‘localhost’, 9090);
my $client = CVClient->new(Thrift::BinaryProtocol->new($transport));

eval {
$transport->open();
print “Calculate the Mean\n( Blue Green Red ) = ( “;
printf “%f “, $_ for @{$client->calcAvg(“lena.jpg”)}; # 戻り値はリストリファレンス
print “)\n\n”;
print “Calculate the Standard-Deviation\n( Blue Green Red ) = ( “;
printf “%f “, $_ for @{$client->calcSdv(“baboon.jpg”)};
print “)”;
$transport->close();
};

if($@) {
warn $@->{message};
}
[/php]

* サーバの起動およびクライアントの実行

$ mv ./gen-cpp/CV_server .
$ ./CV_server
$ chmod +x cv.pl
$ ./cv.pl
Calculate the Mean
( Blue Green Red ) = ( 105.398991 99.562698 179.730305 )

Calculate the Standard-Deviation
( Blue Green Red ) = ( 60.611124 47.493925 55.499225 )

上手くいきました。
次はPHPから。抽象化レイヤのおかげでPHPでも簡単に使えます。
* クライアント側 cv.php (PHP)

[php]
open();
print_r($client->calcAvg(“lena.jpg”)); /* Perl版と同じように呼べる */
print_r($client->calcSdv(“baboon.jpg”));
$transport->close();
}catch(Exception $e) {
echo $e->getMessage();
}

?>
[/php]

* 出力結果

Array
(
    [0] => 105.3989906311
    [1] => 99.562698364258
    [2] => 179.73030471802
)
Array
(
    [0] => 60.611123950567
    [1] => 47.493925313866
    [2] => 55.499224912776
)

詳細は省きますが、Rubyでもシンタックスを変えるだけで利用できます。
[php]
# Rubyでも簡単
client.calcAvg(“lena.jpg”)
client.calcSdv(“baboon.jpg”)
[/php]

今回はThriftを使って各言語から簡単にOpenCVを利用できることを確認しました。

それはともかくOpenCV 2.0 のリリースが Sept. 31, 2009 って書いてありましたが、
また便利な機能が追加されてるんですかね。楽しみです。

あわせて読む:

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です